diff options
43 files changed, 3775 insertions, 235 deletions
@@ -95,6 +95,18 @@ ifndef USE_OPENAL_DLOPEN USE_OPENAL_DLOPEN=0 endif +ifndef USE_CURL +USE_CURL=1 +endif + +ifndef USE_CURL_DLOPEN + ifeq ($(PLATFORM),mingw32) + USE_CURL_DLOPEN=0 + else + USE_CURL_DLOPEN=1 + endif +endif + ifndef USE_CODEC_VORBIS USE_CODEC_VORBIS=0 endif @@ -129,13 +141,19 @@ LIBSDIR=$(MOUNT_DIR)/libs MASTERDIR=$(MOUNT_DIR)/master # extract version info -VERSION=$(shell grep "#define VERSION_NUMBER" $(CMDIR)/q_shared.h | \ +VERSION=$(shell grep "\#define VERSION_NUMBER" $(CMDIR)/q_shared.h | \ sed -e 's/[^"]*"\(.*\)"/\1/') +USE_SVN= ifeq ($(wildcard .svn),.svn) - SVN_VERSION=$(VERSION)_SVN$(shell LANG=C svnversion .) -else - SVN_VERSION=$(VERSION) + SVN_REV=$(shell LANG=C svnversion .) + ifneq ($(SVN_REV),) + SVN_VERSION=$(VERSION)_SVN$(SVN_REV) + USE_SVN=1 + endif +endif +ifneq ($(USE_SVN),1) + SVN_VERSION=$(VERSION) endif @@ -179,6 +197,13 @@ ifeq ($(PLATFORM),linux) 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 @@ -241,6 +266,12 @@ ifeq ($(PLATFORM),linux) 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 @@ -294,14 +325,15 @@ ifeq ($(PLATFORM),darwin) ifeq ($(BUILD_MACOSX_UB),x86) CC=gcc-4.0 BASE_CFLAGS += -arch i386 -DSMP \ - -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ -mmacosx-version-min=10.4 \ -DMAC_OS_X_VERSION_MIN_REQUIRED=1040 -nostdinc \ -F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks \ -I/Developer/SDKs/MacOSX10.4u.sdk/usr/lib/gcc/i686-apple-darwin8/4.0.1/include \ -isystem /Developer/SDKs/MacOSX10.4u.sdk/usr/include - LDFLAGS = -mmacosx-version-min=10.4 \ - -L/Developer/SDKs/MacOSX10.4u.sdk/usr/lib/gcc/i686-apple-darwin8/4.0.1 + LDFLAGS = -arch i386 -mmacosx-version-min=10.4 \ + -L/Developer/SDKs/MacOSX10.4u.sdk/usr/lib/gcc/i686-apple-darwin8/4.0.1 \ + -F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks \ + -Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk ARCH=x86 BUILD_SERVER=0 else @@ -314,13 +346,13 @@ ifeq ($(PLATFORM),darwin) endif ifeq ($(ARCH),ppc) - OPTIMIZE += -faltivec + OPTIMIZE += -faltivec -O3 # Carbon is required on PPC only to make a call to MakeDataExecutable # in the PPC vm (should be a better non-Carbon way). LDFLAGS += -framework Carbon endif ifeq ($(ARCH),x86) - OPTIMIZE += -msse2 + OPTIMIZE += -march=prescott -mfpmath=sse # x86 vm will crash without -mstackrealign since MMX instructions will be # used no matter what and they corrupt the frame pointer in VM calls BASE_CFLAGS += -mstackrealign @@ -339,6 +371,15 @@ ifeq ($(PLATFORM),darwin) 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 @@ -360,7 +401,7 @@ ifeq ($(PLATFORM),darwin) #CLIENT_LDFLAGS += -L/usr/X11R6/$(LIB) -lX11 -lXext -lXxf86dga -lXxf86vm endif - OPTIMIZE += -O3 -ffast-math -falign-loops=16 + OPTIMIZE += -ffast-math -falign-loops=16 ifneq ($(HAVE_VM_COMPILED),true) BASE_CFLAGS += -DNO_VM_COMPILED @@ -395,6 +436,13 @@ ifeq ($(PLATFORM),mingw32) 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 @@ -418,9 +466,15 @@ ifeq ($(PLATFORM),mingw32) BINEXT=.exe - LDFLAGS= -mwindows -lshfolder -lwsock32 -lgdi32 -lwinmm -lole32 + LDFLAGS= -mwindows -lwsock32 -lgdi32 -lwinmm -lole32 CLIENT_LDFLAGS= + ifeq ($(USE_CURL),1) + ifneq ($(USE_CURL_DLOPEN),1) + CLIENT_LDFLAGS += $(LIBSDIR)/win32/libcurl.a + endif + endif + ifeq ($(USE_CODEC_VORBIS),1) CLIENT_LDFLAGS += -lvorbisfile -lvorbis -logg endif @@ -713,6 +767,10 @@ ifeq ($(GENERATE_DEPENDENCIES),1) endif endif +ifeq ($(USE_SVN),1) + BASE_CFLAGS += -DSVN_VERSION=\\\"$(SVN_VERSION)\\\" +endif + DO_CC=$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -o $@ -c $< DO_SMP_CC=$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -DSMP -o $@ -c $< DO_BOT_CC=$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(BOTCFLAGS) -DBOTLIB -o $@ -c $< # $(SHLIBCFLAGS) # bk001212 @@ -829,6 +887,8 @@ Q3OBJ = \ $(B)/client/qal.o \ $(B)/client/snd_openal.o \ \ + $(B)/client/cl_curl.o \ + \ $(B)/client/sv_ccmds.o \ $(B)/client/sv_client.o \ $(B)/client/sv_game.o \ @@ -984,6 +1044,9 @@ endif $(B)/client/cl_cgame.o : $(CDIR)/cl_cgame.c; $(DO_CC) $(B)/client/cl_cin.o : $(CDIR)/cl_cin.c; $(DO_CC) $(B)/client/cl_console.o : $(CDIR)/cl_console.c; $(DO_CC) +ifeq ($(USE_SVN),1) + $(B)/client/cl_console.o : .svn/entries +endif $(B)/client/cl_input.o : $(CDIR)/cl_input.c; $(DO_CC) $(B)/client/cl_keys.o : $(CDIR)/cl_keys.c; $(DO_CC) $(B)/client/cl_main.o : $(CDIR)/cl_main.c; $(DO_CC) @@ -1006,6 +1069,8 @@ $(B)/client/snd_codec_ogg.o : $(CDIR)/snd_codec_ogg.c; $(DO_CC) $(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_client.o : $(SDIR)/sv_client.c; $(DO_CC) $(B)/client/sv_ccmds.o : $(SDIR)/sv_ccmds.c; $(DO_CC) $(B)/client/sv_game.o : $(SDIR)/sv_game.c; $(DO_CC) @@ -1021,6 +1086,9 @@ $(B)/client/cm_patch.o : $(CMDIR)/cm_patch.c; $(DO_CC) $(B)/client/cm_polylib.o : $(CMDIR)/cm_polylib.c; $(DO_CC) $(B)/client/cmd.o : $(CMDIR)/cmd.c; $(DO_CC) $(B)/client/common.o : $(CMDIR)/common.c; $(DO_CC) +ifeq ($(USE_SVN),1) + $(B)/client/common.o : .svn/entries +endif $(B)/client/cvar.o : $(CMDIR)/cvar.c; $(DO_CC) $(B)/client/files.o : $(CMDIR)/files.c; $(DO_CC) $(B)/client/md4.o : $(CMDIR)/md4.c; $(DO_CC) @@ -1222,6 +1290,9 @@ $(B)/ded/cm_trace.o : $(CMDIR)/cm_trace.c; $(DO_DED_CC) $(B)/ded/cm_patch.o : $(CMDIR)/cm_patch.c; $(DO_DED_CC) $(B)/ded/cmd.o : $(CMDIR)/cmd.c; $(DO_DED_CC) $(B)/ded/common.o : $(CMDIR)/common.c; $(DO_DED_CC) +ifeq ($(USE_SVN),1) + $(B)/ded/common.o : .svn/entries +endif $(B)/ded/cvar.o : $(CMDIR)/cvar.c; $(DO_DED_CC) $(B)/ded/files.o : $(CMDIR)/files.c; $(DO_DED_CC) $(B)/ded/md4.o : $(CMDIR)/md4.c; $(DO_DED_CC) diff --git a/make-macosx-ub.sh b/make-macosx-ub.sh index a641e655..0bcee56c 100755 --- a/make-macosx-ub.sh +++ b/make-macosx-ub.sh @@ -1,7 +1,12 @@ #!/bin/sh - +APPBUNDLE=ioquake3.app +BINARY=ioquake3.ub +PKGINFO=APPIOQ3 +ICNS=code/unix/MacSupport/ioquake3.icns DESTDIR=build/release-darwin-ub BASEDIR=base +Q3_VERSION=`grep "\#define Q3_VERSION" code/qcommon/q_shared.h | \ + sed -e 's/.*".* \([^ ]*\)"/\1/'`; BIN_OBJ=" build/release-darwin-ppc/tremulous.ppc @@ -36,15 +41,57 @@ fi (BUILD_MACOSX_UB=ppc make && BUILD_MACOSX_UB=x86 make) || exit 1; -if [ ! -d $DESTDIR ]; then - mkdir $DESTDIR || exit 1; +echo "Creating .app bundle $DESTDIR/$APPBUNDLE" +if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR ]; then + mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR || exit 1; +fi +if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR ]; then + mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR || exit 1; fi -if [ ! -d $DESTDIR/$BASEDIR ]; then - mkdir $DESTDIR/$BASEDIR || exit 1; +if [ ! -d $DESTDIR/$APPBUNDLE/Contents/Resources ]; then + mkdir -p $DESTDIR/$APPBUNDLE/Contents/Resources fi +cp $ICNS $DESTDIR/$APPBUNDLE/Contents/Resources/ioquake3.icns || exit 1; +echo $PKGINFO > $DESTDIR/$APPBUNDLE/Contents/PkgInfo +echo " + <?xml version=\"1.0\" encoding="UTF-8"?> + <!DOCTYPE plist + PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" + \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"> + <plist version=\"1.0\"> + <dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>$BINARY</string> + <key>CFBundleGetInfoString</key> + <string>ioquake3 $Q3_VERSION</string> + <key>CFBundleIconFile</key> + <string>ioquake3.icns</string> + <key>CFBundleIdentifier</key> + <string>org.icculus.quake3</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>ioquake3</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>$Q3_VERSION</string> + <key>CFBundleSignature</key> + <string>$PKGINFO</string> + <key>CFBundleVersion</key> + <string>$Q3_VERSION</string> + <key>NSExtensions</key> + <dict/> + <key>NSPrincipalClass</key> + <string>NSApplication</string> + </dict> + </plist> + " > $DESTDIR/$APPBUNDLE/Contents/Info.plist -echo "Installing Universal Binaries in $DESTDIR" -lipo -create -o $DESTDIR/Tremulous $BIN_OBJ -cp $BASE_OBJ $DESTDIR/$BASEDIR/ -cp src/libs/macosx/*.dylib $DESTDIR/ +lipo -create -o $DESTDIR/$APPBUNDLE/Contents/MacOS/$BINARY $BIN_OBJ +cp $BASE_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR/ +cp $MPACK_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR/ +cp code/libs/macosx/*.dylib $DESTDIR/$APPBUNDLE/Contents/MacOS/ diff --git a/misc/merge-ioq3-into-trem.sh b/misc/merge-ioq3-into-trem.sh index b7e7af1d..1bf9e00a 100755 --- a/misc/merge-ioq3-into-trem.sh +++ b/misc/merge-ioq3-into-trem.sh @@ -17,7 +17,7 @@ svn export . $IOQ3VERSION cd $IOQ3VERSION # Remove READMEs and the like -rm -rf BUGS ChangeLog README COPYING.txt TODO id-readme.txt web/ +rm -rf BUGS ChangeLog README COPYING.txt NOTTODO TODO id-readme.txt web/ # Remove Q3 ui stuff rm -rf ui/ diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c index 463f873c..c54e7054 100644 --- a/src/client/cl_avi.c +++ b/src/client/cl_avi.c @@ -2,20 +2,20 @@ =========================================================================== Copyright (C) 2005-2006 Tim Angus -This file is part of Quake III Arena source code. +This file is part of Tremulous. -Quake III Arena source code is free software; you can redistribute it +Tremulous 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 +Tremulous 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 +along with Tremulous; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ diff --git a/src/client/cl_cgame.c b/src/client/cl_cgame.c index fd7c29ed..262f6b47 100644 --- a/src/client/cl_cgame.c +++ b/src/client/cl_cgame.c @@ -981,7 +981,7 @@ void CL_SetCGameTime( void ) { } // allow pause in single player - if ( sv_paused->integer && cl_paused->integer && com_sv_running->integer ) { + if ( sv_paused->integer && CL_CheckPaused() && com_sv_running->integer ) { // paused return; } diff --git a/src/client/cl_console.c b/src/client/cl_console.c index 22a148a1..3e321394 100644 --- a/src/client/cl_console.c +++ b/src/client/cl_console.c @@ -516,13 +516,13 @@ void Con_DrawSolidConsole( float frac ) { re.SetColor( g_color_table[ColorIndex(COLOR_RED)] ); - i = strlen( Q3_VERSION ); + i = strlen( SVN_VERSION ); for (x=0 ; x<i ; x++) { SCR_DrawSmallChar( cls.glconfig.vidWidth - ( i - x ) * SMALLCHAR_WIDTH, - (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), Q3_VERSION[x] ); + (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), SVN_VERSION[x] ); } diff --git a/src/client/cl_curl.c b/src/client/cl_curl.c new file mode 100644 index 00000000..246095a1 --- /dev/null +++ b/src/client/cl_curl.c @@ -0,0 +1,358 @@ +/* +=========================================================================== +Copyright (C) 2006 Tony J. White (tjw@tjw.org) + +This file is part of Tremulous. + +Tremulous 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. + +Tremulous 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 Tremulous; 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 <windows.h> +#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 <dlfcn.h> +#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 <unistd.h> +#include <sys/types.h> +#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() +{ +#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_easy_cleanup(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 ) +{ + clc.cURLUsed = qtrue; + 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.sv_allowDownload & DLF_NO_DISCONNECT) && + !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); + clc.downloadRestart = qtrue; + } + else { + long code; + + 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 */ diff --git a/src/client/cl_curl.h b/src/client/cl_curl.h new file mode 100644 index 00000000..7b3f8929 --- /dev/null +++ b/src/client/cl_curl.h @@ -0,0 +1,101 @@ +/* +=========================================================================== +Copyright (C) 2006 Tony J. White (tjw@tjw.org) + +This file is part of Tremulous. + +Tremulous 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. + +Tremulous 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 Tremulous; 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__ + +extern cvar_t *cl_cURLLib; + +#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.3" +#endif + +#if USE_LOCAL_HEADERS + #include "../libcurl/curl/curl.h" +#else + #include <curl/curl.h> +#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__ diff --git a/src/client/cl_keys.c b/src/client/cl_keys.c index 691a59e2..c65ce916 100644 --- a/src/client/cl_keys.c +++ b/src/client/cl_keys.c @@ -1071,7 +1071,8 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { if (!down) { return; } - Con_ToggleConsole_f (); + Con_ToggleConsole_f (); + Key_ClearStates (); return; } diff --git a/src/client/cl_main.c b/src/client/cl_main.c index 808553b9..aefbab8c 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -655,6 +655,9 @@ CL_ShutdownAll */ void CL_ShutdownAll(void) { +#if USE_CURL + CL_cURL_Shutdown(); +#endif // clear sounds S_DisableSounds(); // shutdown CGame @@ -1159,6 +1162,9 @@ void CL_Vid_Restart_f( void ) { CL_CloseAVI( ); } + if(clc.demorecording) + CL_StopRecord_f(); + // don't let them loop during the restart S_StopAllSounds(); // shutdown the UI @@ -1291,6 +1297,23 @@ Called when all downloading has been completed */ void CL_DownloadsComplete( void ) { +#if USE_CURL + // if we downloaded with cURL + if(clc.cURLUsed) { + clc.cURLUsed = qfalse; + CL_cURL_Shutdown(); + if( clc.cURLDisconnected ) { + if(clc.downloadRestart) { + 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; @@ -1378,6 +1401,7 @@ A download completed or failed void CL_NextDownload(void) { char *s; char *remoteName, *localName; + qboolean useCURL = qfalse; // We are looking to start a download here if (*clc.downloadList) { @@ -1401,9 +1425,48 @@ void CL_NextDownload(void) { *s++ = 0; else s = localName + strlen(localName); // point at the nul byte - - CL_BeginDownload( localName, remoteName ); - +#if USE_CURL + if(!(cl_allowDownload->integer & DLF_NO_REDIRECT)) { + if(clc.sv_allowDownload & DLF_NO_REDIRECT) { + Com_Printf("WARNING: server does not " + "allow download redirection " + "(sv_allowDownload is %d)\n", + clc.sv_allowDownload); + } + else if(!*clc.sv_dlURL) { + Com_Printf("WARNING: server allows " + "download redirection, but does not " + "have sv_dlURL set\n"); + } + else if(!CL_cURL_Init()) { + Com_Printf("WARNING: could not load " + "cURL library\n"); + } + else { + CL_cURL_BeginDownload(localName, va("%s/%s", + clc.sv_dlURL, remoteName)); + useCURL = qtrue; + } + } + else if(!(clc.sv_allowDownload & DLF_NO_REDIRECT)) { + Com_Printf("WARNING: server allows download " + "redirection, but it disabled by client " + "configuration (cl_allowDownload is %d)\n", + cl_allowDownload->integer); + } +#endif /* USE_CURL */ + if(!useCURL) { + if((cl_allowDownload->integer & DLF_NO_UDP)) { + Com_Error(ERR_DROP, "UDP Downloads are " + "disabled on your client. " + "(cl_allowDownload is %d)", + cl_allowDownload->integer); + return; + } + else { + CL_BeginDownload( localName, remoteName ); + } + } clc.downloadRestart = qtrue; // move over the rest @@ -1426,7 +1489,7 @@ and determine if we need to download them void CL_InitDownloads(void) { char missingfiles[1024]; - if ( !cl_allowDownload->integer ) + if ( !(cl_allowDownload->integer & DLF_ENABLE) ) { // autodownload is disabled on the client // but it's possible that some referenced files on the server are missing @@ -1911,7 +1974,7 @@ void CL_CheckTimeout( void ) { // // check timeout // - if ( ( !cl_paused->integer || !sv_paused->integer ) + if ( ( !CL_CheckPaused() || !sv_paused->integer ) && cls.state >= CA_CONNECTED && cls.state != CA_CINEMATIC && cls.realtime - clc.lastPacketTime > cl_timeout->value*1000) { if (++cl.timeoutcount > 5) { // timeoutcount saves debugger @@ -1924,6 +1987,22 @@ void CL_CheckTimeout( void ) { } } +/* +================== +CL_CheckPaused +Check whether client has been paused. +================== +*/ +qboolean CL_CheckPaused(void) +{ + // if cl_paused->modified is set, the cvar has only been changed in + // this frame. Keep paused in this frame to ensure the server doesn't + // lag behind. + if(cl_paused->integer || cl_paused->modified) + return qtrue; + + return qfalse; +} //============================================================================ @@ -1935,19 +2014,19 @@ CL_CheckUserinfo */ void CL_CheckUserinfo( void ) { // don't add reliable commands when not yet connected - if ( cls.state < CA_CHALLENGING ) { + if(cls.state < CA_CHALLENGING) return; - } + // don't overflow the reliable command buffer when paused - if ( cl_paused->integer ) { + if(CL_CheckPaused()) return; - } + // send a reliable userinfo update if needed - if ( cvar_modifiedFlags & CVAR_USERINFO ) { + if(cvar_modifiedFlags & CVAR_USERINFO) + { cvar_modifiedFlags &= ~CVAR_USERINFO; CL_AddReliableCommand( va("userinfo \"%s\"", Cvar_InfoString( CVAR_USERINFO ) ) ); } - } /* @@ -1962,6 +2041,25 @@ void CL_Frame ( int msec ) { return; } +#if USE_CURL + if(clc.downloadCURLM) { + CL_cURL_PerformDownload(); + // we can't process frames normally when in disconnected + // download mode since the ui vm expects cls.state to be + // CA_CONNECTED + if(clc.cURLDisconnected) { + cls.realFrametime = msec; + cls.frametime = msec; + cls.realtime += cls.frametime; + SCR_UpdateScreen(); + S_Update(); + Con_RunConsole(); + cls.framecount++; + return; + } + } +#endif + if ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI ) && !com_sv_running->integer ) { // if disconnected, bring up the menu @@ -2273,6 +2371,12 @@ void CL_Video_f( void ) char filename[ MAX_OSPATH ]; int i, last; + if( !clc.demoplaying ) + { + Com_Printf( "The video command can only be used when playing back demos\n" ); + return; + } + if( Cmd_Argc( ) == 2 ) { // explicit filename @@ -2404,6 +2508,9 @@ void CL_Init( void ) { cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0); cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE); +#if USE_CURL + cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE); +#endif cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); #ifdef MACOS_X @@ -2718,7 +2825,7 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING ); if (strlen(info)) { if (info[strlen(info)-1] != '\n') { - strncat(info, "\n", sizeof(info)); + strncat(info, "\n", sizeof(info) - 1); } Com_Printf( "%s: %s", NET_AdrToString( from ), info ); } diff --git a/src/client/cl_parse.c b/src/client/cl_parse.c index 7de07e91..093893a6 100644 --- a/src/client/cl_parse.c +++ b/src/client/cl_parse.c @@ -220,6 +220,10 @@ void CL_ParseSnapshot( msg_t *msg ) { newSnap.serverTime = MSG_ReadLong( msg ); + // if we were just unpaused, we can only *now* really let the + // change come into effect or the client hangs. + cl_paused->modified = 0; + newSnap.messageNum = clc.serverMessageSequence; deltaNum = MSG_ReadByte( msg ); @@ -411,6 +415,25 @@ void CL_SystemInfoChanged( void ) { /* ================== +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")); + Q_strncpyz(clc.sv_dlURL, + Info_ValueForKey(serverInfo, "sv_dlURL"), + sizeof(clc.sv_dlURL)); +} + +/* +================== CL_ParseGamestate ================== */ @@ -476,11 +499,18 @@ void CL_ParseGamestate( msg_t *msg ) { // 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(); + // stop recording now so the demo won't have an unnecessary level load at the end. + if(cl_autoRecordDemo->integer && clc.demorecording) + CL_StopRecord_f(); + // reinitialize the filesystem if the game directory has changed - FS_ConditionalRestart( clc.checksumFeed ); + FS_ConditionalRestart( clc.checksumFeed ); // This used to call CL_StartHunkUsers, but now we enter the download state before loading the // cgame diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c index 327eaacf..caa9179f 100644 --- a/src/client/cl_ui.c +++ b/src/client/cl_ui.c @@ -603,10 +603,10 @@ static void CL_GetGlconfig( glconfig_t *config ) { /* ==================== -GetClipboardData +CL_GetClipboardData ==================== */ -static void GetClipboardData( char *buf, int buflen ) { +static void CL_GetClipboardData( char *buf, int buflen ) { char *cbd; cbd = Sys_GetClipboardData(); @@ -836,7 +836,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) { return 0; case UI_GETCLIPBOARDDATA: - GetClipboardData( VMA(1), args[2] ); + CL_GetClipboardData( VMA(1), args[2] ); return 0; case UI_GETCLIENTSTATE: diff --git a/src/client/client.h b/src/client/client.h index ae5915db..77cf7dca 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -31,12 +31,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #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" #define RETRANSMIT_TIMEOUT 3000 // time between connection packet retransmits - // snapshots are a view of the server at a given time typedef struct { qboolean valid; // cleared if delta parsing was invalid @@ -187,6 +190,16 @@ typedef struct { fileHandle_t download; char downloadTempName[MAX_OSPATH]; char downloadName[MAX_OSPATH]; +#ifdef USE_CURL + qboolean cURLEnabled; + qboolean cURLUsed; + qboolean cURLDisconnected; + char downloadURL[MAX_OSPATH]; + CURL *downloadCURL; + CURLM *downloadCURLM; +#endif /* USE_CURL */ + int sv_allowDownload; + char sv_dlURL[MAX_CVAR_VALUE_STRING]; int downloadNumber; int downloadBlock; // block we are waiting for int downloadCount; // how many bytes we got @@ -352,10 +365,12 @@ extern cvar_t *cl_aviMotionJpeg; extern cvar_t *cl_activeAction; extern cvar_t *cl_allowDownload; +extern cvar_t *cl_downloadMethod; extern cvar_t *cl_conXOffset; extern cvar_t *cl_inGameVideo; extern cvar_t *cl_lanForcePackets; +extern cvar_t *cl_autoRecordDemo; //================================================= @@ -380,6 +395,7 @@ void CL_ReadDemoMessage( void ); demoState_t CL_DemoState( void ); int CL_DemoPos( void ); void CL_DemoName( char *buffer, int size ); +void CL_StopRecord_f( void ); void CL_InitDownloads(void); void CL_NextDownload(void); @@ -393,6 +409,7 @@ void CL_ShutdownRef( void ); void CL_InitRef( void ); int CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen ); +qboolean CL_CheckPaused(void); // // cl_input diff --git a/src/client/qal.c b/src/client/qal.c index b206881f..4c04bd41 100644 --- a/src/client/qal.c +++ b/src/client/qal.c @@ -177,8 +177,8 @@ qboolean QAL_Init(const char *libname) #else char fn[1024]; getcwd(fn, sizeof(fn)); - strncat(fn, "/", sizeof(fn)); - strncat(fn, libname, sizeof(fn)); + strncat(fn, "/", sizeof(fn) - strlen(fn) - 1); + strncat(fn, libname, sizeof(fn) - strlen(fn) - 1); if( (OpenALLib = OBJLOAD(fn)) == 0 ) { diff --git a/src/client/snd_codec_ogg.c b/src/client/snd_codec_ogg.c index 72ece944..f13f9a8d 100644 --- a/src/client/snd_codec_ogg.c +++ b/src/client/snd_codec_ogg.c @@ -4,20 +4,20 @@ Copyright (C) 1999-2005 Id Software, Inc. Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de> -This file is part of Quake III Arena source code. +This file is part of Tremulous. -Quake III Arena source code is free software; you can redistribute it +Tremulous 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 +Tremulous 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 +along with Tremulous; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ diff --git a/src/client/snd_main.c b/src/client/snd_main.c index 8f09570e..eb31f2d7 100644 --- a/src/client/snd_main.c +++ b/src/client/snd_main.c @@ -405,9 +405,9 @@ void S_Init( void ) } S_SoundInfo( ); - Com_Printf( "Sound intialization successful.\n" ); + Com_Printf( "Sound initialization successful.\n" ); } else { - Com_Printf( "Sound intialization failed.\n" ); + Com_Printf( "Sound initialization failed.\n" ); } } diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c index 39a04179..6f5396c4 100644 --- a/src/client/snd_openal.c +++ b/src/client/snd_openal.c @@ -37,8 +37,12 @@ cvar_t *s_alSources; cvar_t *s_alDopplerFactor; cvar_t *s_alDopplerSpeed; cvar_t *s_alMinDistance; +cvar_t *s_alMaxDistance; cvar_t *s_alRolloff; +cvar_t *s_alGraceDistance; cvar_t *s_alDriver; +cvar_t *s_alDevice; +cvar_t *s_alAvailableDevices; cvar_t *s_alMaxSpeakerDistance; /* @@ -134,7 +138,11 @@ static sfxHandle_t S_AL_BufferFindFree( void ) { // Got one if(knownSfx[i].filename[0] == '\0') + { + if(i >= numSfx) + numSfx = i + 1; return i; + } } // Shit... @@ -155,7 +163,7 @@ static sfxHandle_t S_AL_BufferFind(const char *filename) sfxHandle_t sfx = -1; int i; - for(i = 0; i < MAX_SFX; i++) + for(i = 0; i < numSfx; i++) { if(!Q_stricmp(knownSfx[i].filename, filename)) { @@ -230,7 +238,7 @@ static qboolean S_AL_BufferEvict( void ) int i, oldestBuffer = -1; int oldestTime = Sys_Milliseconds( ); - for( i = 0; i < MAX_SFX; i++ ) + for( i = 0; i < numSfx; i++ ) { if( !knownSfx[ i ].filename[ 0 ] ) continue; @@ -404,7 +412,7 @@ void S_AL_BufferShutdown( void ) knownSfx[default_sfx].isLocked = qfalse; // Free all used effects - for(i = 0; i < MAX_SFX; i++) + for(i = 0; i < numSfx; i++) S_AL_BufferUnload(i); // Clear the tables @@ -463,6 +471,9 @@ typedef struct src_s int isLooping; // Is this a looping effect (attached to an entity) int isTracking; // Is this object tracking it's owner + float curGain; // gain employed if source is within maxdistance. + float scaleGain; // Last gain value for this source. 0 if muted. + qboolean local; // Is this local (relative to the cam) } src_t; @@ -512,6 +523,50 @@ static void _S_AL_SanitiseVector( vec3_t v, int line ) /* ================= +S_AL_ScaleGain +Adapt the gain if necessary to get a quicker fadeout when the source is too far away. +================= +*/ + +static void S_AL_ScaleGain(src_t *chksrc, vec3_t origin) +{ + float distance; + + if(chksrc->local) + distance = VectorLength(origin); + else + distance = Distance(origin, lastListenerOrigin); + + // If we exceed a certain distance, scale the gain linearly until the sound + // vanishes into nothingness. + if((distance -= s_alMaxDistance->value) > 0) + { + float scaleFactor; + + if(distance >= s_alGraceDistance->value) + scaleFactor = 0.0f; + else + scaleFactor = 1.0f - distance / s_alGraceDistance->value; + + scaleFactor *= chksrc->curGain; + + if(chksrc->scaleGain != scaleFactor); + { + chksrc->scaleGain = scaleFactor; + // if(scaleFactor > 0.0f) + // Com_Printf("%f\n", scaleFactor); + qalSourcef(chksrc->alSource, AL_GAIN, chksrc->scaleGain); + } + } + else if(chksrc->scaleGain != chksrc->curGain) + { + chksrc->scaleGain = chksrc->curGain; + qalSourcef(chksrc->alSource, AL_GAIN, chksrc->scaleGain); + } +} + +/* +================= S_AL_HearingThroughEntity ================= */ @@ -615,41 +670,46 @@ static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t prio int entity, int channel, qboolean local) { ALuint buffer; + src_t *curSource; // Mark the SFX as used, and grab the raw AL buffer S_AL_BufferUse(sfx); buffer = S_AL_BufferGet(sfx); // Set up src struct - srcList[src].lastUsedTime = Sys_Milliseconds(); - srcList[src].sfx = sfx; - srcList[src].priority = priority; - srcList[src].entity = entity; - srcList[src].channel = channel; - srcList[src].isActive = qtrue; - srcList[src].isLocked = qfalse; - srcList[src].isLooping = qfalse; - srcList[src].isTracking = qfalse; - srcList[src].local = local; + curSource = &srcList[src]; + + curSource->lastUsedTime = Sys_Milliseconds(); + curSource->sfx = sfx; + curSource->priority = priority; + curSource->entity = entity; + curSource->channel = channel; + curSource->isActive = qtrue; + curSource->isLocked = qfalse; + curSource->isLooping = qfalse; + curSource->isTracking = qfalse; + curSource->curGain = s_alGain->value * s_volume->value; + curSource->scaleGain = curSource->curGain; + curSource->local = local; // Set up OpenAL source - qalSourcei(srcList[src].alSource, AL_BUFFER, buffer); - qalSourcef(srcList[src].alSource, AL_PITCH, 1.0f); - qalSourcef(srcList[src].alSource, AL_GAIN, s_alGain->value * s_volume->value); - qalSourcefv(srcList[src].alSource, AL_POSITION, vec3_origin); - qalSourcefv(srcList[src].alSource, AL_VELOCITY, vec3_origin); - qalSourcei(srcList[src].alSource, AL_LOOPING, AL_FALSE); - qalSourcef(srcList[src].alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value); + qalSourcei(curSource->alSource, AL_BUFFER, buffer); + qalSourcef(curSource->alSource, AL_PITCH, 1.0f); + qalSourcef(curSource->alSource, AL_GAIN, curSource->curGain); + qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin); + qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin); + qalSourcei(curSource->alSource, AL_LOOPING, AL_FALSE); + qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value); if(local) { - qalSourcei(srcList[src].alSource, AL_SOURCE_RELATIVE, AL_TRUE); - qalSourcef(srcList[src].alSource, AL_ROLLOFF_FACTOR, 0.0f); + qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE); + qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f); } else { - qalSourcei(srcList[src].alSource, AL_SOURCE_RELATIVE, AL_FALSE); - qalSourcef(srcList[src].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value); + qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE); + qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value); } } @@ -825,6 +885,27 @@ void S_AL_UpdateEntityPosition( int entityNum, const vec3_t origin ) /* ================= +S_AL_CheckInput +Check whether input values from mods are out of range. +Necessary for i.g. Western Quake3 mod which is buggy. +================= +*/ +static qboolean S_AL_CheckInput(int entityNum, sfxHandle_t sfx) +{ + if (entityNum < 0 || entityNum > MAX_GENTITIES) + Com_Error(ERR_DROP, "S_StartSound: bad entitynum %i", entityNum); + + if (sfx < 0 || sfx >= numSfx) + { + Com_Printf(S_COLOR_RED, "ERROR: S_AL_CheckInput: handle %i out of range\n", sfx); + return qtrue; + } + + return qfalse; +} + +/* +================= S_AL_StartLocalSound Play a local (non-spatialized) sound effect @@ -833,6 +914,9 @@ Play a local (non-spatialized) sound effect static void S_AL_StartLocalSound(sfxHandle_t sfx, int channel) { + if(S_AL_CheckInput(0, sfx)) + return; + // Try to grab a source srcHandle_t src = S_AL_SrcAlloc(SRCPRI_LOCAL, -1, channel); if(src == -1) @@ -857,6 +941,9 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx { vec3_t sorigin; + if(S_AL_CheckInput(origin ? 0 : entnum, sfx)) + return; + // Try to grab a source srcHandle_t src = S_AL_SrcAlloc(SRCPRI_ONESHOT, entnum, entchannel); if(src == -1) @@ -865,8 +952,6 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx // Set up the effect if( origin == NULL ) { - srcList[ src ].isTracking = qtrue; - if( S_AL_HearingThroughEntity( entnum ) ) { // Where the entity is the local player, play a local sound @@ -878,6 +963,7 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx S_AL_SrcSetup( src, sfx, SRCPRI_ONESHOT, entnum, entchannel, qfalse ); VectorCopy( entityList[ entnum ].origin, sorigin ); } + srcList[ src ].isTracking = qtrue; } else { @@ -887,6 +973,7 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx S_AL_SanitiseVector( sorigin ); qalSourcefv( srcList[ src ].alSource, AL_POSITION, sorigin ); + S_AL_ScaleGain(&srcList[src], sorigin); // Start it playing qalSourcePlay(srcList[src].alSource); @@ -918,6 +1005,7 @@ static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx, { int src; sentity_t *sent = &entityList[ entityNum ]; + src_t *curSource; // Do we need to allocate a new source for this entity if( !sent->srcAllocated ) @@ -945,28 +1033,33 @@ static void S_AL_SrcLoop( alSrcPriority_t priority, sfxHandle_t sfx, // If this is not set then the looping sound is removed sent->loopAddedThisFrame = qtrue; + curSource = &srcList[src]; + // UGH // These lines should be called via S_AL_SrcSetup, but we // can't call that yet as it buffers sfxes that may change // with subsequent calls to S_AL_SrcLoop - srcList[ src ].entity = entityNum; - srcList[ src ].isLooping = qtrue; - srcList[ src ].isActive = qtrue; + curSource->entity = entityNum; + curSource->isLooping = qtrue; + curSource->isActive = qtrue; if( S_AL_HearingThroughEntity( entityNum ) ) { - srcList[ src ].local = qtrue; + curSource->local = qtrue; - qalSourcefv( srcList[ src ].alSource, AL_POSITION, vec3_origin ); - qalSourcefv( srcList[ src ].alSource, AL_VELOCITY, vec3_origin ); + qalSourcefv( curSource->alSource, AL_POSITION, vec3_origin ); + qalSourcefv( curSource->alSource, AL_VELOCITY, vec3_origin ); } else { - srcList[ src ].local = qfalse; + curSource->local = qfalse; - qalSourcefv( srcList[ src ].alSource, AL_POSITION, (ALfloat *)sent->origin ); - qalSourcefv( srcList[ src ].alSource, AL_VELOCITY, (ALfloat *)velocity ); + qalSourcefv( curSource->alSource, AL_POSITION, (ALfloat *)sent->origin ); + qalSourcefv( curSource->alSource, AL_VELOCITY, (ALfloat *)velocity ); + } + + S_AL_ScaleGain(curSource, sent->origin); } /* @@ -977,6 +1070,9 @@ S_AL_AddLoopingSound static void S_AL_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) { + if(S_AL_CheckInput(entityNum, sfx)) + return; + S_AL_SanitiseVector( (vec_t *)origin ); S_AL_SanitiseVector( (vec_t *)velocity ); S_AL_SrcLoop(SRCPRI_ENTITY, sfx, origin, velocity, entityNum); @@ -990,6 +1086,9 @@ S_AL_AddRealLoopingSound static void S_AL_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) { + if(S_AL_CheckInput(entityNum, sfx)) + return; + S_AL_SanitiseVector( (vec_t *)origin ); S_AL_SanitiseVector( (vec_t *)velocity ); @@ -1028,63 +1127,65 @@ void S_AL_SrcUpdate( void ) int i; int entityNum; ALint state; + src_t *curSource; for(i = 0; i < srcCount; i++) { entityNum = srcList[i].entity; + curSource = &srcList[i]; - if(srcList[i].isLocked) + if(curSource->isLocked) continue; - if(!srcList[i].isActive) + if(!curSource->isActive) continue; // Update source parameters if((s_alGain->modified)||(s_volume->modified)) - qalSourcef(srcList[i].alSource, AL_GAIN, s_alGain->value * s_volume->value); - if((s_alRolloff->modified)&&(!srcList[i].local)) - qalSourcef(srcList[i].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value); + curSource->curGain = s_alGain->value * s_volume->value; + if((s_alRolloff->modified)&&(!curSource->local)) + qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value); if(s_alMinDistance->modified) - qalSourcef(srcList[i].alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value); + qalSourcef(curSource->alSource, AL_REFERENCE_DISTANCE, s_alMinDistance->value); - if( srcList[ i ].isLooping ) + if(curSource->isLooping) { sentity_t *sent = &entityList[ entityNum ]; // If a looping effect hasn't been touched this frame, kill it - if( sent->loopAddedThisFrame ) + if(sent->loopAddedThisFrame) { // The sound has changed without an intervening removal - if( srcList[ i ].isActive && !sent->startLoopingSound && - srcList[ i ].sfx != sent->loopSfx ) + if(curSource->isActive && !sent->startLoopingSound && + curSource->sfx != sent->loopSfx) { - qalSourceStop( srcList[ i ].alSource ); - qalSourcei( srcList[ i ].alSource, AL_BUFFER, 0 ); + qalSourceStop(curSource->alSource); + qalSourcei(curSource->alSource, AL_BUFFER, 0); sent->startLoopingSound = qtrue; } - // Ths sound hasn't been started yet - if( sent->startLoopingSound ) + // The sound hasn't been started yet + if(sent->startLoopingSound) { - S_AL_SrcSetup( i, sent->loopSfx, sent->loopPriority, - entityNum, -1, srcList[ i ].local ); - srcList[ i ].isLooping = qtrue; - qalSourcei( srcList[ i ].alSource, AL_LOOPING, AL_TRUE ); - qalSourcePlay( srcList[ i ].alSource ); + S_AL_SrcSetup(i, sent->loopSfx, sent->loopPriority, + entityNum, -1, curSource->local); + curSource->isLooping = qtrue; + qalSourcei(curSource->alSource, AL_LOOPING, AL_TRUE); + qalSourcePlay(curSource->alSource); sent->startLoopingSound = qfalse; } // Update locality - if( srcList[ i ].local) + if(curSource->local) { - qalSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, AL_TRUE ); - qalSourcef( srcList[ i ].alSource, AL_ROLLOFF_FACTOR, 0.0f ); + qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_TRUE); + qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, 0.0f); } else { - qalSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, AL_FALSE ); - qalSourcef( srcList[ i ].alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value ); + qalSourcei(curSource->alSource, AL_SOURCE_RELATIVE, AL_FALSE); + qalSourcef(curSource->alSource, AL_ROLLOFF_FACTOR, s_alRolloff->value); } } else @@ -1093,20 +1194,23 @@ void S_AL_SrcUpdate( void ) continue; } - // Query relativity of source, don't move if it's true - qalGetSourcei( srcList[ i ].alSource, AL_SOURCE_RELATIVE, &state ); - - // See if it needs to be moved - if( srcList[ i ].isTracking && !state ) - qalSourcefv(srcList[i].alSource, AL_POSITION, entityList[entityNum].origin); - // Check if it's done, and flag it - qalGetSourcei(srcList[i].alSource, AL_SOURCE_STATE, &state); + qalGetSourcei(curSource->alSource, AL_SOURCE_STATE, &state); if(state == AL_STOPPED) { S_AL_SrcKill(i); continue; } + + // Query relativity of source, don't move if it's true + qalGetSourcei(curSource->alSource, AL_SOURCE_RELATIVE, &state); + + // See if it needs to be moved + if(curSource->isTracking && !state) + { + qalSourcefv(curSource->alSource, AL_POSITION, entityList[entityNum].origin); + S_AL_ScaleGain(curSource, entityList[entityNum].origin); + } } } @@ -1290,6 +1394,7 @@ static ALuint musicSource; static ALuint musicBuffers[NUM_MUSIC_BUFFERS]; static snd_stream_t *mus_stream; +static snd_stream_t *intro_stream; static char s_backgroundLoop[MAX_QPATH]; static byte decode_buffer[MUSIC_BUFFER_SIZE]; @@ -1333,6 +1438,26 @@ static void S_AL_MusicSourceFree( void ) /* ================= +S_AL_CloseMusicFiles +================= +*/ +static void S_AL_CloseMusicFiles(void) +{ + if(intro_stream) + { + S_CodecCloseStream(intro_stream); + intro_stream = NULL; + } + + if(mus_stream) + { + S_CodecCloseStream(mus_stream); + mus_stream = NULL; + } +} + +/* +================= S_AL_StopBackgroundTrack ================= */ @@ -1355,9 +1480,7 @@ void S_AL_StopBackgroundTrack( void ) S_AL_MusicSourceFree(); // Unload the stream - if(mus_stream) - S_CodecCloseStream(mus_stream); - mus_stream = NULL; + S_AL_CloseMusicFiles(); musicPlaying = qfalse; } @@ -1373,27 +1496,42 @@ void S_AL_MusicProcess(ALuint b) ALenum error; int l; ALuint format; + snd_stream_t *curstream; - if(!mus_stream) + if(intro_stream) + curstream = intro_stream; + else + curstream = mus_stream; + + if(!curstream) return; - l = S_CodecReadStream(mus_stream, MUSIC_BUFFER_SIZE, decode_buffer); + l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer); // Run out data to read, start at the beginning again if(l == 0) { - S_CodecCloseStream(mus_stream); - mus_stream = S_CodecOpenStream(s_backgroundLoop); - if(!mus_stream) + S_CodecCloseStream(curstream); + + // the intro stream just finished playing so we don't need to reopen + // the music stream. + if(intro_stream) + intro_stream = NULL; + else + mus_stream = S_CodecOpenStream(s_backgroundLoop); + + curstream = mus_stream; + + if(!curstream) { S_AL_StopBackgroundTrack(); return; } - l = S_CodecReadStream(mus_stream, MUSIC_BUFFER_SIZE, decode_buffer); + l = S_CodecReadStream(curstream, MUSIC_BUFFER_SIZE, decode_buffer); } - format = S_AL_Format(mus_stream->info.width, mus_stream->info.channels); + format = S_AL_Format(curstream->info.width, curstream->info.channels); if( l == 0 ) { @@ -1403,7 +1541,7 @@ void S_AL_MusicProcess(ALuint b) qalBufferData( b, AL_FORMAT_MONO16, (void *)dummyData, 2, 22050 ); } else - qalBufferData(b, format, decode_buffer, l, mus_stream->info.rate); + qalBufferData(b, format, decode_buffer, l, curstream->info.rate); if( ( error = qalGetError( ) ) != AL_NO_ERROR ) { @@ -1423,27 +1561,12 @@ static void S_AL_StartBackgroundTrack( const char *intro, const char *loop ) { int i; + qboolean issame; // Stop any existing music that might be playing S_AL_StopBackgroundTrack(); - if ( !intro || !intro[0] ) { - intro = loop; - } - if ( !loop || !loop[0] ) { - loop = intro; - } - - if((!intro || !intro[0]) && (!intro || !intro[0])) - return; - - // Copy the loop over - strncpy( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) ); - - // Open the intro - mus_stream = S_CodecOpenStream(intro); - - if(!mus_stream) + if((!intro || !*intro) && (!loop || !*loop)) return; // Allocate a musicSource @@ -1451,9 +1574,32 @@ void S_AL_StartBackgroundTrack( const char *intro, const char *loop ) if(musicSourceHandle == -1) return; + if (!loop || !*loop) + { + loop = intro; + issame = qtrue; + } + else if(intro && *intro && !strcmp(intro, loop)) + issame = qtrue; + else + issame = qfalse; + + // Copy the loop over + strncpy( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) ); + + if(!issame) + { + // Open the intro and don't mind whether it succeeds. + // The important part is the loop. + intro_stream = S_CodecOpenStream(intro); + } + else + intro_stream = NULL; + mus_stream = S_CodecOpenStream(s_backgroundLoop); if(!mus_stream) { + S_AL_CloseMusicFiles(); S_AL_MusicSourceFree(); return; } @@ -1526,6 +1672,7 @@ static ALCcontext *alContext; #ifdef _WIN32 #define ALDRIVER_DEFAULT "OpenAL32.dll" +#define ALDEVICE_DEFAULT "Generic Software" #elif defined(MACOS_X) #define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" #else @@ -1674,7 +1821,11 @@ void S_AL_SoundInfo( void ) Com_Printf( " Version: %s\n", qalGetString( AL_VERSION ) ); Com_Printf( " Renderer: %s\n", qalGetString( AL_RENDERER ) ); Com_Printf( " Extensions: %s\n", qalGetString( AL_EXTENSIONS ) ); - + if(qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + { + Com_Printf(" Device: %s\n", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER)); + Com_Printf("Available Devices:\n%s", s_alAvailableDevices->string); + } } /* @@ -1714,6 +1865,9 @@ S_AL_Init qboolean S_AL_Init( soundInterface_t *si ) { #if USE_OPENAL + + qboolean enumsupport, founddev = qfalse; + if( !si ) { return qfalse; } @@ -1725,7 +1879,9 @@ qboolean S_AL_Init( soundInterface_t *si ) s_alDopplerFactor = Cvar_Get( "s_alDopplerFactor", "1.0", CVAR_ARCHIVE ); s_alDopplerSpeed = Cvar_Get( "s_alDopplerSpeed", "2200", CVAR_ARCHIVE ); s_alMinDistance = Cvar_Get( "s_alMinDistance", "120", CVAR_CHEAT ); - s_alRolloff = Cvar_Get( "s_alRolloff", "0.8", CVAR_CHEAT ); + s_alMaxDistance = Cvar_Get("s_alMaxDistance", "1024", CVAR_CHEAT); + s_alRolloff = Cvar_Get( "s_alRolloff", "2", CVAR_CHEAT); + s_alGraceDistance = Cvar_Get("s_alGraceDistance", "512", CVAR_CHEAT); s_alMaxSpeakerDistance = Cvar_Get( "s_alMaxSpeakerDistance", "1024", CVAR_ARCHIVE ); s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE ); @@ -1737,8 +1893,56 @@ qboolean S_AL_Init( soundInterface_t *si ) return qfalse; } - // Open default device - alDevice = qalcOpenDevice( NULL ); + // Device enumeration support (extension is implemented reasonably only on Windows right now). + if((enumsupport = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))) + { + char devicenames[1024] = ""; + const char *devicelist; + const char *defaultdevice; + int curlen; + + // get all available devices + the default device name. + devicelist = qalcGetString(NULL, ALC_DEVICE_SPECIFIER); + defaultdevice = qalcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + +#ifdef _WIN32 + // check whether the default device is generic hardware. If it is, change to + // Generic Software as that one works more reliably with various sound systems. + // If it's not, use OpenAL's default selection as we don't want to ignore + // native hardware acceleration. + if(!strcmp(defaultdevice, "Generic Hardware")) + s_alDevice = Cvar_Get("s_alDevice", ALDEVICE_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH); + else +#endif + s_alDevice = Cvar_Get("s_alDevice", defaultdevice, CVAR_ARCHIVE | CVAR_LATCH); + + // dump a list of available devices to a cvar for the user to see. + while((curlen = strlen(devicelist))) + { + Q_strcat(devicenames, sizeof(devicenames), devicelist); + Q_strcat(devicenames, sizeof(devicenames), "\n"); + + // check whether the device we want to load is available at all. + if(!strcmp(s_alDevice->string, devicelist)) + founddev = qtrue; + + devicelist += curlen + 1; + } + + s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART); + + if(!founddev) + { + Cvar_ForceReset("s_alDevice"); + founddev = 1; + } + } + + if(founddev) + alDevice = qalcOpenDevice(s_alDevice->string); + else + alDevice = qalcOpenDevice(NULL); + if( !alDevice ) { QAL_Shutdown( ); @@ -1746,6 +1950,9 @@ qboolean S_AL_Init( soundInterface_t *si ) return qfalse; } + if(enumsupport) + Cvar_Set("s_alDevice", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER)); + // Create OpenAL context alContext = qalcCreateContext( alDevice, NULL ); if( !alContext ) @@ -1762,6 +1969,7 @@ qboolean S_AL_Init( soundInterface_t *si ) S_AL_SrcInit( ); // Set up OpenAL parameters (doppler, etc) + qalDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); qalDopplerFactor( s_alDopplerFactor->value ); qalDopplerVelocity( s_alDopplerSpeed->value ); diff --git a/src/libcurl/curl/curl.h b/src/libcurl/curl/curl.h new file mode 100644 index 00000000..a0a04148 --- /dev/null +++ b/src/libcurl/curl/curl.h @@ -0,0 +1,1563 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id: curl.h,v 1.304 2006-08-04 16:08:41 giva Exp $ + ***************************************************************************/ + +/* If you have problems, all libcurl docs and details are found here: + http://curl.haxx.se/libcurl/ +*/ + +#include "curlver.h" /* the libcurl version defines */ + +#include <stdio.h> +#include <limits.h> + +/* The include stuff here below is mainly for time_t! */ +#ifdef vms +# include <types.h> +# include <time.h> +#else +# include <sys/types.h> +# include <time.h> +#endif /* defined (vms) */ + +typedef void CURL; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Decorate exportable functions for Win32 DLL linking. + * This avoids using a .def file for building libcurl.dll. + */ +#if (defined(WIN32) || defined(_WIN32)) && !defined(CURL_STATICLIB) +#if defined(BUILDING_LIBCURL) +#define CURL_EXTERN __declspec(dllexport) +#else +#define CURL_EXTERN __declspec(dllimport) +#endif +#else + +#ifdef CURL_HIDDEN_SYMBOLS +/* + * This definition is used to make external definitions visibile in the + * shared library when symbols are hidden by default. It makes no + * difference when compiling applications whether this is set or not, + * only when compiling the library. + */ +#define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +#define CURL_EXTERN +#endif +#endif + +/* + * We want the typedef curl_off_t setup for large file support on all + * platforms. We also provide a CURL_FORMAT_OFF_T define to use in *printf + * format strings when outputting a variable of type curl_off_t. + * + * Note: "pocc -Ze" is MSVC compatibily mode and this sets _MSC_VER! + */ + +#if (defined(_MSC_VER) && !defined(__POCC__)) || (defined(__LCC__) && defined(WIN32)) +/* MSVC */ +#ifdef _WIN32_WCE + typedef long curl_off_t; +#define CURL_FORMAT_OFF_T "%ld" +#else + typedef signed __int64 curl_off_t; +#define CURL_FORMAT_OFF_T "%I64d" +#endif +#else /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */ +#if (defined(__GNUC__) && defined(WIN32)) || defined(__WATCOMC__) +/* gcc on windows or Watcom */ + typedef long long curl_off_t; +#define CURL_FORMAT_OFF_T "%I64d" +#else /* GCC or Watcom on Windows */ + +/* "normal" POSIX approach, do note that this does not necessarily mean that + the type is >32 bits, see the SIZEOF_CURL_OFF_T define for that! */ + typedef off_t curl_off_t; + +/* Check a range of defines to detect large file support. On Linux it seems + none of these are set by default, so if you don't explicitly switches on + large file support, this define will be made for "small file" support. */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 0 /* to prevent warnings in the check below */ +#define UNDEF_FILE_OFFSET_BITS +#endif +#ifndef FILESIZEBITS +#define FILESIZEBITS 0 /* to prevent warnings in the check below */ +#define UNDEF_FILESIZEBITS +#endif + +#if defined(_LARGE_FILES) || (_FILE_OFFSET_BITS > 32) || (FILESIZEBITS > 32) \ + || defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE) + /* For now, we assume at least one of these to be set for large files to + work! */ +#define CURL_FORMAT_OFF_T "%lld" +#else /* LARGE_FILE support */ +#define CURL_FORMAT_OFF_T "%ld" +#endif +#endif /* GCC or Watcom on Windows */ +#endif /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */ + +#ifdef UNDEF_FILE_OFFSET_BITS +/* this was defined above for our checks, undefine it again */ +#undef _FILE_OFFSET_BITS +#endif + +#ifdef UNDEF_FILESIZEBITS +/* this was defined above for our checks, undefine it again */ +#undef FILESIZEBITS +#endif + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist* contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ +#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */ +#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */ +#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer + do not free in formfree */ +#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer + do not free in formfree */ +#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */ +#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */ + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ +}; + +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. */ +#define CURL_MAX_WRITE_SIZE 16384 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + + +#ifndef CURL_NO_OLDIES + /* not used since 7.10.8, will be removed in a future release */ +typedef int (*curl_passwd_callback)(void *clientp, + const char *prompt, + char *buffer, + int buflen); +#endif + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_URL_MALFORMAT_USER, /* 4 - NOT USED */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_FTP_ACCESS_DENIED, /* 9 a service was denied by the FTP server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 - NOT USED */ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_WEIRD_USER_REPLY, /* 12 */ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_FTP_CANT_RECONNECT, /* 16 */ + CURLE_FTP_COULDNT_SET_BINARY, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_FTP_WRITE_ERROR, /* 20 */ + CURLE_FTP_QUOTE_ERROR, /* 21 */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_MALFORMAT_USER, /* 24 - NOT USED */ + CURLE_FTP_COULDNT_STOR_FILE, /* 25 - failed FTP upload */ + CURLE_READ_ERROR, /* 26 - could open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEOUTED, /* 28 - the timeout time was reached */ + CURLE_FTP_COULDNT_SET_ASCII, /* 29 - TYPE A failed */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_FTP_COULDNT_GET_SIZE, /* 32 - the SIZE command failed */ + CURLE_HTTP_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_LIBRARY_NOT_FOUND, /* 40 */ + CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_BAD_CALLING_ORDER, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_BAD_PASSWORD_ENTERED, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_TELNET_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ + CURLE_OBSOLETE, /* 50 - NOT USED */ + CURLE_SSL_PEER_CERTIFICATE, /* 51 - peer's certificate wasn't ok */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_SHARE_IN_USE, /* 57 - share is in use */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized transfer encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_FTP_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_TFTP_DISKFULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_TFTP_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURL_LAST /* never use! */ +} CURLcode; + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +/* Make a spelling correction for the operation timed-out define */ +#define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ +/* backwards compatibility with older names */ +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#endif + +typedef enum { + CURLPROXY_HTTP = 0, + CURLPROXY_SOCKS4 = 4, + CURLPROXY_SOCKS5 = 5 +} curl_proxytype; + +#define CURLAUTH_NONE 0 /* nothing */ +#define CURLAUTH_BASIC (1<<0) /* Basic (default) */ +#define CURLAUTH_DIGEST (1<<1) /* Digest */ +#define CURLAUTH_GSSNEGOTIATE (1<<2) /* GSS-Negotiate */ +#define CURLAUTH_NTLM (1<<3) /* NTLM */ +#define CURLAUTH_ANY ~0 /* all types set */ +#define CURLAUTH_ANYSAFE (~CURLAUTH_BASIC) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ +/* this was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* These are just to make older programs not break: */ +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME +#endif + +#define CURL_ERROR_SIZE 256 + +/* parameter for the CURLOPT_FTP_SSL option */ +typedef enum { + CURLFTPSSL_NONE, /* do not attempt to use SSL */ + CURLFTPSSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLFTPSSL_CONTROL, /* SSL for the control connection or fail */ + CURLFTPSSL_ALL, /* SSL for all communication or fail */ + CURLFTPSSL_LAST /* not an option, never use */ +} curl_ftpssl; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* name is uppercase CURLOPT_<name>, + type is one of the defined CURLOPTTYPE_<type> + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif +/* + * Figure out if we can use the ## operator, which is supported by ISO/ANSI C + * and C++. Some compilers support it without setting __STDC__ or __cplusplus + * so we need to carefully check for them too. We don't use configure-checks + * for these since we want these headers to remain generic and working for all + * platforms. + */ +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +#ifdef CURL_ISOCPP +#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(FILE, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, OBJECTPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, OBJECTPOINT, 4), + + /* "name:password" to use when fetching. */ + CINIT(USERPWD, OBJECTPOINT, 5), + + /* "name:password" to use with proxy. */ + CINIT(PROXYUSERPWD, OBJECTPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, OBJECTPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(INFILE, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was succcessful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referer page (needed by some CGIs) */ + CINIT(REFERER, OBJECTPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, OBJECTPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, OBJECTPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG , 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, OBJECTPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct HttpPost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, OBJECTPOINT, 25), + + /* password for the SSL-private key, keep this for compatibility */ + CINIT(SSLCERTPASSWD, OBJECTPOINT, 26), + /* password for the SSL private key */ + CINIT(SSLKEYPASSWD, OBJECTPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(WRITEHEADER, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, OBJECTPOINT, 31), + + /* What version to specifly try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, OBJECTPOINT, 36), + + /* HTTP request, for odd commands like DELETE, TRACE and others */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + /* Pass a pointer to string of the output using full variable-replacement + as described elsewhere. */ + CINIT(WRITEINFO, OBJECTPOINT, 40), + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(FTPLISTONLY, LONG, 48), /* Use NLST when listing ftp dir */ + + CINIT(FTPAPPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the progress callback */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), + + /* We want the referer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, OBJECTPOINT, 62), + + /* Set the krb4 security level, this also enables krb4 awareness. This is a + * string, 'clear', 'safe', 'confidential' or 'private'. If the string is + * set but doesn't match one of these, 'private' will be used. */ + CINIT(KRB4LEVEL, OBJECTPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, OBJECTPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + /* What policy to use when closing connections when the cache is filled + up */ + CINIT(CLOSEPOLICY, LONG, 72), + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, OBJECTPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, OBJECTPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects + are OK within this time, then fine... This only aborts the connect + phase. [Only works on unix-style/SIGALRM operating systems] */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, OBJECTPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specificly switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, OBJECTPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, OBJECTPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, OBJECTPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, OBJECTPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To becomeO BSOLETE soon */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands (Wesley Laxton)*/ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, OBJECTPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_SOCKS4 and CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. */ + CINIT(ENCODING, OBJECTPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentionally send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specificly switch on or off the FTP engine's use of the EPRT command ( it + also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG , 112), + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, OBJECTPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLFTPSSL_TRY - try using SSL, proceed anyway otherwise + CURLFTPSSL_CONTROL - SSL for the control connection or fail + CURLFTPSSL_ALL - SSL for all communication or fail + */ + CINIT(FTP_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + + /* When doing 3rd party transfer, set the source user and password with + this */ + CINIT(SOURCE_USERPWD, OBJECTPOINT, 123), + + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + + /* When doing 3rd party transfer, set the source pre-quote linked list + of commands with this */ + CINIT(SOURCE_PREQUOTE, OBJECTPOINT, 127), + + /* When doing 3rd party transfer, set the source post-quote linked list + of commands with this */ + CINIT(SOURCE_POSTQUOTE, OBJECTPOINT, 128), + + /* When FTP over SSL/TLS is selected (with CURLOPT_FTP_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* To make a 3rd party transfer, set the source URL with this */ + CINIT(SOURCE_URL, OBJECTPOINT, 132), + + /* When doing 3rd party transfer, set the source quote linked list of + commands with this */ + CINIT(SOURCE_QUOTE, OBJECTPOINT, 133), + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, OBJECTPOINT, 134), + + /* feed cookies into cookie engine */ + CINIT(COOKIELIST, OBJECTPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_WRITEDATA CURLOPT_FILE +#define CURLOPT_READDATA CURLOPT_INFILE +#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ +#define CURLOPT_HTTPREQUEST -1 +#define CURLOPT_FTPASCII CURLOPT_TRANSFERTEXT +#define CURLOPT_MUTE -2 +#define CURLOPT_PASSWDFUNCTION -3 +#define CURLOPT_PASSWDDATA -4 +#define CURLOPT_CLOSEFUNCTION -5 + +#define CURLOPT_SOURCE_HOST -6 +#define CURLOPT_SOURCE_PATH -7 +#define CURLOPT_SOURCE_PORT -8 +#define CURLOPT_PASV_HOST -9 + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + +#ifdef __BEOS__ +#include <support/SupportDefs.h> +#endif + + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details */ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_<name> */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CURLFORM_LASTENTRY /* the last unusued */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanved function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 30 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internaly to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + +typedef void CURLSH; + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* out of memory */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify shich data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basicly all programs ever, that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_THIRD + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */ +#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */ +#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */ +#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */ +#define CURL_VERSION_CONV (1<<12) /* character conversions are + supported */ + +/* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +#endif /* __CURL_CURL_H */ diff --git a/src/libcurl/curl/curlver.h b/src/libcurl/curl/curlver.h new file mode 100644 index 00000000..1634b172 --- /dev/null +++ b/src/libcurl/curl/curlver.h @@ -0,0 +1,56 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id: curlver.h,v 1.21 2006-06-12 07:24:14 bagder Exp $ + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.15.5" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 15 +#define LIBCURL_VERSION_PATCH 5 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. +*/ +#define LIBCURL_VERSION_NUM 0x070f05 + +#endif /* __CURL_CURLVER_H */ diff --git a/src/libcurl/curl/easy.h b/src/libcurl/curl/easy.h new file mode 100644 index 00000000..b5867200 --- /dev/null +++ b/src/libcurl/curl/easy.h @@ -0,0 +1,81 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id: easy.h,v 1.13 2004/11/09 14:02:58 giva Exp $ + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistant connections cannot + * be transfered. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libcurl/curl/mprintf.h b/src/libcurl/curl/mprintf.h new file mode 100644 index 00000000..8d835f13 --- /dev/null +++ b/src/libcurl/curl/mprintf.h @@ -0,0 +1,62 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id: mprintf.h,v 1.13 2006-03-28 10:08:54 bagder Exp $ + ***************************************************************************/ + +#include <stdarg.h> +#include <stdio.h> /* needed for FILE */ + +#include "curl.h" + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef _MPRINTF_REPLACE +# define printf curl_mprintf +# define fprintf curl_mfprintf +#ifdef CURLDEBUG +/* When built with CURLDEBUG we define away the sprintf() functions since we + don't want internal code to be using them */ +# define sprintf sprintf_was_used +# define vsprintf vsprintf_was_used +#else +# define sprintf curl_msprintf +# define vsprintf curl_mvsprintf +#endif +# define snprintf curl_msnprintf +# define vprintf curl_mvprintf +# define vfprintf curl_mvfprintf +# define vsnprintf curl_mvsnprintf +# define aprintf curl_maprintf +# define vaprintf curl_mvaprintf +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/src/libcurl/curl/multi.h b/src/libcurl/curl/multi.h new file mode 100644 index 00000000..05aeafc7 --- /dev/null +++ b/src/libcurl/curl/multi.h @@ -0,0 +1,344 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id: multi.h,v 1.38 2006-08-04 18:53:48 danf Exp $ + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ +#if defined(_WIN32) && !defined(WIN32) +/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we + make this adjustment to catch this. */ +#define WIN32 1 +#endif + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \ + !defined(__CYGWIN__) || defined(__MINGW32__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include <winsock2.h> +#endif +#else + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on system that are known to + require it! */ +#if defined(_AIX) || defined(NETWARE) || defined(__NetBSD__) || defined(_MINIX) +#include <sys/select.h> +#endif + +#ifndef _WIN32_WCE +#include <sys/socket.h> +#endif +#include <sys/time.h> +#include <sys/types.h> +#endif + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * <curl/curl.h> without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void CURLM; + +#ifndef curl_socket_typedef +/* Public socket typedef */ +#ifdef WIN32 +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic informations. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,number) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + number +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/src/libcurl/curl/stdcheaders.h b/src/libcurl/curl/stdcheaders.h new file mode 100644 index 00000000..024413ac --- /dev/null +++ b/src/libcurl/curl/stdcheaders.h @@ -0,0 +1,34 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id: stdcheaders.h,v 1.8 2004/01/07 09:19:34 bagder Exp $ + ***************************************************************************/ + +#include <sys/types.h> + +size_t fread (void *, size_t, size_t, FILE *); +size_t fwrite (const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif diff --git a/src/libcurl/curl/types.h b/src/libcurl/curl/types.h new file mode 100644 index 00000000..d37d6ae9 --- /dev/null +++ b/src/libcurl/curl/types.h @@ -0,0 +1 @@ +/* not used */ diff --git a/src/libs/win32/libcurl.a b/src/libs/win32/libcurl.a Binary files differnew file mode 100644 index 00000000..7f6ed2d7 --- /dev/null +++ b/src/libs/win32/libcurl.a diff --git a/src/qcommon/common.c b/src/qcommon/common.c index cc105ee8..dfbfcd0f 100644 --- a/src/qcommon/common.c +++ b/src/qcommon/common.c @@ -263,9 +263,6 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { code = ERR_FATAL; } - // make sure we can get at our local stuff - FS_PureServerSetLoadedPaks( "", "" ); - // if we are getting a solid stream of ERR_DROP, do an ERR_FATAL currentTime = Sys_Milliseconds(); if ( currentTime - lastErrorTime < 100 ) { @@ -286,20 +283,22 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { vsprintf (com_errorMessage,fmt,argptr); va_end (argptr); - if ( code != ERR_DISCONNECT && code != ERR_NEED_CD ) { + if (code != ERR_DISCONNECT && code != ERR_NEED_CD) Cvar_Set("com_errorMessage", com_errorMessage); - } - if ( code == ERR_SERVERDISCONNECT ) { + if (code == ERR_DISCONNECT || code == ERR_SERVERDISCONNECT) { CL_Disconnect( qtrue ); CL_FlushMemory( ); + // make sure we can get at our local stuff + FS_PureServerSetLoadedPaks("", ""); com_errorEntered = qfalse; longjmp (abortframe, -1); - } else if ( code == ERR_DROP || code == ERR_DISCONNECT ) { + } else if (code == ERR_DROP) { Com_Printf ("********************\nERROR: %s\n********************\n", com_errorMessage); SV_Shutdown (va("Server crashed: %s", com_errorMessage)); CL_Disconnect( qtrue ); CL_FlushMemory( ); + FS_PureServerSetLoadedPaks("", ""); com_errorEntered = qfalse; longjmp (abortframe, -1); } else if ( code == ERR_NEED_CD ) { @@ -312,6 +311,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { } else { Com_Printf("Server didn't have CD\n" ); } + FS_PureServerSetLoadedPaks("", ""); longjmp (abortframe, -1); } else { CL_Shutdown (); @@ -2279,7 +2279,7 @@ Com_Init void Com_Init( char *commandLine ) { char *s; - Com_Printf( "%s %s %s\n", Q3_VERSION, PLATFORM_STRING, __DATE__ ); + Com_Printf( "%s %s %s\n", SVN_VERSION, PLATFORM_STRING, __DATE__ ); if ( setjmp (abortframe) ) { Sys_Error ("Error during initialization"); @@ -2523,9 +2523,9 @@ int Com_ModifyMsec( int msec ) { // dedicated servers don't want to clamp for a much longer // period, because it would mess up all the client's views // of time. - if ( msec > 500 ) { + if (com_sv_running->integer && msec > 500) Com_Printf( "Hitch warning: %i msec frame time\n", msec ); - } + clampTime = 5000; } else if ( !com_sv_running->integer ) { diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c index a4af1af0..4340dcc4 100644 --- a/src/qcommon/cvar.c +++ b/src/qcommon/cvar.c @@ -452,6 +452,15 @@ void Cvar_Reset( const char *var_name ) { Cvar_Set2( var_name, NULL, qfalse ); } +/* +============ +Cvar_ForceReset +============ +*/ +void Cvar_ForceReset(const char *var_name) +{ + Cvar_Set2(var_name, NULL, qtrue); +} /* ============ diff --git a/src/qcommon/files.c b/src/qcommon/files.c index 15e183a4..ac73a0a8 100644 --- a/src/qcommon/files.c +++ b/src/qcommon/files.c @@ -2706,7 +2706,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) { ================ FS_Shutdown -Frees all resources and closes all files +Frees all resources. ================ */ void FS_Shutdown( qboolean closemfp ) { @@ -2819,10 +2819,6 @@ static void FS_Startup( const char *gameName ) { if (fs_basepath->string[0]) { FS_AddGameDirectory( fs_basepath->string, gameName ); } -#ifdef MACOS_X - // allow .app bundles to be placed along side base dir - FS_AddGameDirectory( ".", gameName ); -#endif // fs_homepath is somewhat particular to *nix systems, only add if relevant // NOTE: same filtering below for mods and basegame if (fs_basepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index 8d84b3f7..f7a8b43e 100644 --- a/src/qcommon/q_shared.h +++ b/src/qcommon/q_shared.h @@ -29,6 +29,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define VERSION_NUMBER "1.1.0" #define Q3_VERSION "tremulous " VERSION_NUMBER +#ifndef SVN_VERSION +#define SVN_VERSION Q3_VERSION +#endif #define CLIENT_WINDOW_TITLE "Tremulous " VERSION_NUMBER #define CLIENT_WINDOW_ICON "Tremulous" #define CONSOLE_WINDOW_TITLE "Tremulous " VERSION_NUMBER " console" diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index bf20536d..478cd5d5 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -481,6 +481,7 @@ void Cvar_CommandCompletion( void(*callback)(const char *s) ); // callback with each valid string void Cvar_Reset( const char *var_name ); +void Cvar_ForceReset(const char *var_name); void Cvar_SetCheatState( void ); // reset all testing vars to a safe value @@ -1096,4 +1097,10 @@ extern huffman_t clientHuffTables; #define CL_ENCODE_START 12 #define CL_DECODE_START 4 +// flags for sv_allowDownload and cl_allowDownload +#define DLF_ENABLE 1 +#define DLF_NO_REDIRECT 2 +#define DLF_NO_UDP 4 +#define DLF_NO_DISCONNECT 8 + #endif // _QCOMMON_H_ diff --git a/src/qcommon/vm_ppc_new.c b/src/qcommon/vm_ppc_new.c index a731d653..79fc506f 100644 --- a/src/qcommon/vm_ppc_new.c +++ b/src/qcommon/vm_ppc_new.c @@ -158,32 +158,38 @@ typedef enum { #define RG_EA r14 // The deepest value I saw in the Quake3 games was 9. -#define OP_STACK_MAX_DEPTH 12 +#define OP_STACK_MAX_DEPTH 16 -// These are all volatile and thus must be saved -// upon entry to the VM code. +// These are all volatile and thus must be saved upon entry to the VM code. +// NOTE: These are General Purpose Registers (GPR) numbers like the +// R_ definitions in the regNums_t enum above (31 is the max) static int opStackIntRegisters[OP_STACK_MAX_DEPTH] = { 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27 + 24, 25, 26, 27, + 28, 29, 30, 31 }; static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH]; // We use different registers for the floating point // operand stack (these are volatile in the PPC ABI) +// NOTE: these are Floating Point Register (FPR) numbers, not +// General Purpose Register (GPR) numbers static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] = { 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11 + 8, 9, 10, 11, + 12, 13, 14, 15 }; static int opStackRegType[OP_STACK_MAX_DEPTH] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; diff --git a/src/renderer/tr_model.c b/src/renderer/tr_model.c index b59ff3b4..8fdd0adb 100644 --- a/src/renderer/tr_model.c +++ b/src/renderer/tr_model.c @@ -653,9 +653,9 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char for(j = 0; j < surf->numTriangles; j++) { - tri->indexes[0] = curtri->indexes[0]; - tri->indexes[1] = curtri->indexes[1]; - tri->indexes[2] = curtri->indexes[2]; + tri->indexes[0] = LittleLong(curtri->indexes[0]); + tri->indexes[1] = LittleLong(curtri->indexes[1]); + tri->indexes[2] = LittleLong(curtri->indexes[2]); tri++; curtri++; diff --git a/src/server/server.h b/src/server/server.h index fd49da7b..4d73038e 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -169,6 +169,7 @@ typedef struct client_s { netchan_buffer_t **netchan_end_queue; int oldServerTime; + qboolean csUpdated[MAX_CONFIGSTRINGS+1]; } client_t; //============================================================================= @@ -272,6 +273,7 @@ void SV_MasterGameStat( const char *data ); // void SV_SetConfigstring( int index, const char *val ); void SV_GetConfigstring( int index, char *buffer, int bufferSize ); +void SV_UpdateConfigstrings( client_t *client ); void SV_SetUserinfo( int index, const char *val ); void SV_GetUserinfo( int index, char *buffer, int bufferSize ); diff --git a/src/server/sv_client.c b/src/server/sv_client.c index 794f32a8..e128b579 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -462,6 +462,10 @@ void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { Com_DPrintf( "Going from CS_PRIMED to CS_ACTIVE for %s\n", client->name ); client->state = CS_ACTIVE; + // resend all configstrings using the cs commands since these are + // no longer sent when the client is CS_PRIMED + SV_UpdateConfigstrings( client ); + // set up the entity for the client clientNum = client - svs.clients; ent = SV_GentityNum( clientNum ); @@ -643,7 +647,9 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) } // We open the file here - if ( !sv_allowDownload->integer || idPack || unreferenced || + if ( !(sv_allowDownload->integer & DLF_ENABLE) || + (sv_allowDownload->integer & DLF_NO_UDP) || + idPack || unreferenced || ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) { // cannot auto-download file if(unreferenced) @@ -660,7 +666,10 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) else { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName); } - } else if ( !sv_allowDownload->integer ) { + } + else if ( !(sv_allowDownload->integer & DLF_ENABLE) || + (sv_allowDownload->integer & DLF_NO_UDP) ) { + Com_Printf("clientDownload: %d : \"%s\" download disabled", cl - svs.clients, cl->downloadName); if (sv_pure->integer) { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" diff --git a/src/server/sv_init.c b/src/server/sv_init.c index 0099e63f..293b31c9 100644 --- a/src/server/sv_init.c +++ b/src/server/sv_init.c @@ -23,6 +23,81 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "server.h" + +/* +=============== +SV_SendConfigstring + +Creates and sends the server command necessary to update the CS index for the +given client +=============== +*/ +static void SV_SendConfigstring(client_t *client, int index) +{ + int maxChunkSize = MAX_STRING_CHARS - 24; + int len; + + len = strlen(sv.configstrings[index]); + + if( len >= maxChunkSize ) { + int sent = 0; + int remaining = len; + char *cmd; + char buf[MAX_STRING_CHARS]; + + while (remaining > 0 ) { + if ( sent == 0 ) { + cmd = "bcs0"; + } + else if( remaining < maxChunkSize ) { + cmd = "bcs2"; + } + else { + cmd = "bcs1"; + } + Q_strncpyz( buf, &sv.configstrings[index][sent], + maxChunkSize ); + + SV_SendServerCommand( client, "%s %i \"%s\"\n", cmd, + index, buf ); + + sent += (maxChunkSize - 1); + remaining -= (maxChunkSize - 1); + } + } else { + // standard cs, just send it + SV_SendServerCommand( client, "cs %i \"%s\"\n", index, + sv.configstrings[index] ); + } +} + +/* +=============== +SV_UpdateConfigstrings + +Called when a client goes from CS_PRIMED to CS_ACTIVE. Updates all +Configstring indexes that have changed while the client was in CS_PRIMED +=============== +*/ +void SV_UpdateConfigstrings(client_t *client) +{ + int index; + + for( index = 0; index <= MAX_CONFIGSTRINGS; index++ ) { + // if the CS hasn't changed since we went to CS_PRIMED, ignore + if(!client->csUpdated[index]) + continue; + + // do not always send server info to all clients + if ( index == CS_SERVERINFO && client->gentity && + (client->gentity->r.svFlags & SVF_NOSERVERINFO) ) { + continue; + } + SV_SendConfigstring(client, index); + client->csUpdated[index] = qfalse; + } +} + /* =============== SV_SetConfigstring @@ -31,7 +106,6 @@ SV_SetConfigstring */ void SV_SetConfigstring (int index, const char *val) { int len, i; - int maxChunkSize = MAX_STRING_CHARS - 24; client_t *client; if ( index < 0 || index >= MAX_CONFIGSTRINGS ) { @@ -57,48 +131,23 @@ void SV_SetConfigstring (int index, const char *val) { // send the data to all relevent clients for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) { - if ( client->state < CS_PRIMED ) { + if ( client->state < CS_ACTIVE ) { + if ( client->state == CS_PRIMED ) + client->csUpdated[ index ] = qtrue; continue; } // do not always send server info to all clients if ( index == CS_SERVERINFO && client->gentity && (client->gentity->r.svFlags & SVF_NOSERVERINFO) ) { continue; } + len = strlen( val ); - if( len >= maxChunkSize ) { - int sent = 0; - int remaining = len; - char *cmd; - char buf[MAX_STRING_CHARS]; - - while (remaining > 0 ) { - if ( sent == 0 ) { - cmd = "bcs0"; - } - else if( remaining < maxChunkSize ) { - cmd = "bcs2"; - } - else { - cmd = "bcs1"; - } - Q_strncpyz( buf, &val[sent], maxChunkSize ); - - SV_SendServerCommand( client, "%s %i \"%s\"\n", cmd, index, buf ); - - sent += (maxChunkSize - 1); - remaining -= (maxChunkSize - 1); - } - } else { - // standard cs, just send it - SV_SendServerCommand( client, "cs %i \"%s\"\n", index, val ); - } + SV_SendConfigstring(client, index); } } } - - /* =============== SV_GetConfigstring @@ -561,6 +610,7 @@ void SV_Init (void) { sv_zombietime = Cvar_Get ("sv_zombietime", "2", CVAR_TEMP ); sv_allowDownload = Cvar_Get ("sv_allowDownload", "0", CVAR_SERVERINFO); + Cvar_Get ("sv_dlURL", "", 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 ); diff --git a/src/server/sv_main.c b/src/server/sv_main.c index c84e5ac3..2dc5a778 100644 --- a/src/server/sv_main.c +++ b/src/server/sv_main.c @@ -129,6 +129,10 @@ void SV_AddServerCommand( client_t *client, const char *cmd ) { // return; // } + // do not send commands until the gamestate has been sent + if( client->state < CS_PRIMED ) + return; + client->reliableSequence++; // if we would be losing an old command that hasn't been acknowledged, // we must drop the connection @@ -186,9 +190,6 @@ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) { // send the data to all relevent clients for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) { - if ( client->state < CS_PRIMED ) { - continue; - } SV_AddServerCommand( client, (char *)message ); } } @@ -784,7 +785,15 @@ void SV_Frame( int msec ) { return; } - if ( !com_sv_running->integer ) { + if (!com_sv_running->integer) + { + if(com_dedicated->integer) + { + // Block indefinitely until something interesting happens + // on STDIN. + NET_Sleep(-1); + } + return; } @@ -797,7 +806,14 @@ void SV_Frame( int msec ) { if ( sv_fps->integer < 1 ) { Cvar_Set( "sv_fps", "10" ); } - frameMsec = 1000 / sv_fps->integer ; + + frameMsec = 1000 / sv_fps->integer * com_timescale->value; + // don't let it scale below 1ms + if(frameMsec < 1) + { + Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f)); + frameMsec = 1; + } sv.timeResidual += msec; diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c index 75da32b0..47471ba5 100644 --- a/src/server/sv_snapshot.c +++ b/src/server/sv_snapshot.c @@ -559,7 +559,7 @@ static int SV_RateMsec( client_t *client, int messageSize ) { rate = sv_minRate->integer; } - rateMsec = ( messageSize + HEADER_RATE_BYTES ) * 1000 / rate; + rateMsec = ( messageSize + HEADER_RATE_BYTES ) * 1000 / rate * com_timescale->value; return rateMsec; } @@ -588,31 +588,30 @@ void SV_SendMessageToClient( msg_t *msg, client_t *client ) { // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 // added sv_lanForceRate check if ( client->netchan.remoteAddress.type == NA_LOOPBACK || (sv_lanForceRate->integer && Sys_IsLANAddress (client->netchan.remoteAddress)) ) { - client->nextSnapshotTime = svs.time + (1000/sv_fps->integer); + client->nextSnapshotTime = svs.time + (1000.0 / sv_fps->integer * com_timescale->value); return; } // normal rate / snapshotMsec calculation - rateMsec = SV_RateMsec( client, msg->cursize ); + rateMsec = SV_RateMsec(client, msg->cursize); - if ( rateMsec < client->snapshotMsec ) { + if ( rateMsec < client->snapshotMsec * com_timescale->value) { // never send more packets than this, no matter what the rate is at - rateMsec = client->snapshotMsec; + rateMsec = client->snapshotMsec * com_timescale->value; client->rateDelayed = qfalse; } else { client->rateDelayed = qtrue; } - client->nextSnapshotTime = svs.time + rateMsec; + client->nextSnapshotTime = svs.time + rateMsec * com_timescale->value; // don't pile up empty snapshots while connecting if ( client->state != CS_ACTIVE ) { // a gigantic connection message may have already put the nextSnapshotTime // more than a second away, so don't shorten it // do shorten if client is downloading - if ( !*client->downloadName && client->nextSnapshotTime < svs.time + 1000 ) { - client->nextSnapshotTime = svs.time + 1000; - } + if (!*client->downloadName && client->nextSnapshotTime < svs.time + 1000 * com_timescale->value) + client->nextSnapshotTime = svs.time + 1000 * com_timescale->value; } } diff --git a/src/unix/MacSupport/SLA-dmg.sh b/src/unix/MacSupport/SLA-dmg.sh new file mode 100755 index 00000000..51c6e429 --- /dev/null +++ b/src/unix/MacSupport/SLA-dmg.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# +# This script appends a SLA.r (Software License Agreement) resource to a .dmg +# +# usage is './SLA-dmg.sh SLA.r /path/to/ioquake3.dmg' +# + +if [ "x$1" = "x" ] || [ "x$2" = "x"]; then + echo "usage: ./SLA-dmg.sh SLAFILE DMGFILE" + exit 1; +fi + +if [ ! -r $1 ]; then + echo "$1 is not a readable .r file" + exit 1; +fi +if [ ! -w $2 ]; then + echo "$2 is not writable .dmg file" + exit 1; +fi + +hdiutil convert -format UDCO -o tmp.dmg $2 || exit 1 +hdiutil unflatten tmp.dmg || exit 1 +/Developer/Tools/Rez /Developer/Headers/FlatCarbon/*.r $1 -a -o tmp.dmg \ + || exit 1 +hdiutil flatten tmp.dmg || exit 1 +hdiutil internet-enable -yes tmp.dmg || exit 1 +mv tmp.dmg $2 || (echo "Could not copy tmp.dmg to $2" && exit 1) +rm tmp.dmg +echo "SLA $1 successfully added to $2" diff --git a/src/unix/MacSupport/SLA.r b/src/unix/MacSupport/SLA.r new file mode 100644 index 00000000..e5edaf0e --- /dev/null +++ b/src/unix/MacSupport/SLA.r @@ -0,0 +1,260 @@ +data 'LPic' (5000) { + $"0002 0011 0003 0001 0000 0000 0002 0000" + $"0008 0003 0000 0001 0004 0000 0004 0005" + $"0000 000E 0006 0001 0005 0007 0000 0007" + $"0008 0000 0047 0009 0000 0034 000A 0001" + $"0035 000B 0001 0020 000C 0000 0011 000D" + $"0000 005B 0004 0000 0033 000F 0001 000C" + $"0010 0000 000B 000E 0000" +}; + + +data 'TEXT' (5002, "English") { +"LIMITED USE SOFTWARE LICENSE AGREEMENT\n" +"\n" +"\n" +"\n" +"This Limited Use Software License Agreement (the \"Agreement\") is a legal" +"agreement between you, the end-user, and Id Software, Inc. (\"ID\"). BY" +"CONTINUING THE INSTALLATION OF THIS GAME DEMO PROGRAM ENTITLED QUAKE III:" +"ARENA (THE \"SOFTWARE\"), BY LOADING OR RUNNING THE SOFTWARE, OR BY PLACING" +"OR COPYING THE SOFTWARE ONTO YOUR COMPUTER HARD DRIVE, COMPUTER RAM OR" +"OTHER STORAGE, YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS " +"AGREEMENT.\n" +"\n" +"\n" +"\n" +"1. Grant of License. Subject to the terms and provisions of this" +"Agreement, ID grants to you the non-exclusive and limited right to use the" +"Software only in executable or object code form. The term \"Software\"" +"includes all elements of the Software, including, without limitation, data" +"files and screen displays. You are not receiving any ownership or" +"proprietary right, title or interest in or to the Software or the " +"copyright, trademarks, or other rights related thereto. For purposes of" +"this section, \"use\" means loading the Software into RAM and/or onto " +"computer hard drive, as well as installation of the Software on a hard" +"disk or other storage device and means the uses permitted in section 3." +"hereinbelow. You agree that the Software will not be shipped," +"transferred or exported into any country in violation of the U.S. Export" +"Administration Act (or any other law governing such matters) by you or" +"anyone at your direction and that you will not utilize and will not" +"authorize anyone to utilize, in any other manner, the Software in" +"violation of any applicable law. The Software may not be downloaded" +"or otherwise exported or exported into (or to a national or resident" +"of) any country to which the U.S. has embargoed goods or to anyone" +"or into any country who/which are prohibited, by applicable law, from" +"receiving such property." +"\n" +"\n" +"\n" +"2. Prohibitions. You, either directly or indirectly, shall not do" +"any of the following acts:" +"\n" +"\n" +"\n" +"a. rent the Software;" +"\n" +"\n" +"\n" +"b. sell the Software;" +"\n" +"\n" +"\n" +"c. lease or lend the Software;" +"\n" +"\n" +"\n" +"d. offer the Software on a \"pay-per-play\" basis;" +"\n" +"\n" +"\n" +"e. distribute the Software (except as permitted by section 3." +"hereinbelow);" +"\n" +"\n" +"\n" +"f. in any other manner and through any medium whatsoever" +"commercially exploit the Software or use the Software for any commercial" +"purpose;" +"\n" +"\n" +"\n" +"g. disassemble, reverse engineer, decompile, modify or alter the" +"Software including, without limitation, creating or developing extra or" +"add-on levels for the Software;" +"\n" +"\n" +"\n" +"h. translate the Software;" +"\n" +"\n" +"\n" +"i. reproduce or copy the Software (except as permitted by section" +"3. hereinbelow);" +"\n" +"\n" +"\n" +"j. publicly display the Software;" +"\n" +"\n" +"\n" +"k. prepare or develop derivative works based upon the Software; or" +"\n" +"\n" +"\n" +"l. remove or alter any legal notices or other markings or " +"legends, such as trademark and copyright notices, affixed on or within" +"the Software." +"\n" +"\n" +"\n" +"3. Permitted Distribution and Copying. So long as this Agreement" +"accompanies each copy you make of the Software, and so long as you fully" +"comply, at all times, with this Agreement, ID grants to you the" +"non-exclusive and limited right to copy the Software and to distribute " +"such copies of the Software free of charge for non-commercial purposes " +"which shall include the free of charge distribution of copies of the" +"Software as mounted on the covers of magazines; provided, however, you" +"shall not copy or distribute the Software in any infringing manner or" +"in any manner which violates any law or third party right and you shall" +"not distribute the Software together with any material which is " +"infringing, libelous, defamatory, obscene, false, misleading, or " +"otherwise illegal or unlawful. You agree to label conspicuously as " +"\"SHAREWARE\" or \"DEMO\" each CD or other non-electronic copy of the " +"Software that you make and distribute. ID reserves all rights not" +"granted in this Agreement. You shall not commercially distribute the" +"Software unless you first enter into a separate contract with ID, a" +"copy of which you may request, but which ID may decline to execute." +"For more information visit www.quake3arena.com." +"\n" +"\n" +"\n" +"4. Intellectual Property Rights. The Software and all copyrights," +"trademarks and all other conceivable intellectual property rights related" +"to the Software are owned by ID and are protected by United States" +"copyright laws, international treaty provisions and all applicable law," +"such as the Lanham Act. You must treat the Software like any other" +"copyrighted material, as required by 17 U.S.C., §101 et seq. and othen" +"applicable law. You agree to use your best efforts to see that any user" +"of the Software licensed hereunder complies with this Agreement. You" +"agree that you are receiving a copy of the Software by license only" +"and not by sale and that the \"first sale\" doctrine of 17 U.S.C. §10" +"does not apply to your receipt or use of the Software." +"\n" +"\n" +"\n" +"5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS OR" +"IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF" +"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT TO THE" +"SOFTWARE. ID DOES NOT WARRANT THAT THE OPERATION OF THE SOFTWARE WILL BE" +"UNINTERRUPTED OR ERROR FREE OR THAT THE SOFTWARE WILL MEET YOUR SPECIFIC" +"REQUIREMENTS. ADDITIONAL STATEMENTS SUCH AS PRESENTATIONS, WHETHER ORAL" +"OR WRITTEN, DO NOT CONSTITUTE WARRANTIES BY ID AND SHOULD NOT BE RELIED" +"UPON. THIS SECTION 5. SHALL SURVIVE CANCELLATION OR TERMINATION OF THIS" +"AGREEMENT." +"\n" +"\n" +"\n" +"6. Governing Law, Venue, Indemnity and Liability Limitation. This" +"Agreement shall be construed in accordance with and governed by the" +"applicable laws of the State of Texas and applicable United States federal" +"law. Copyright and other proprietary matters will be governed by United" +"States laws and international treaties. Exclusive venue for all" +"litigation regarding this Agreement shall be in Dallas County, Texas" +"and you agree to submit to the jurisdiction of the courts in Dallas," +"Texas for any such litigation. You agree to indemnify, defend and hold" +"harmless ID and ID's officers, employees, directors, agents, licensees" +"(excluding you), successors and assigns from and against all losses," +"lawsuits, damages, causes of action and claims relating to and/or" +"arising from your breach of this Agreement. You agree that your" +"unauthorized use of the Software, or any part thereof, may immediately" +"and irreparably damage ID such that ID could not be adequately" +"compensated solely by a monetary award and that at ID's option ID shall" +"be entitled to an injunctive order, in addition to all other available" +"remedies including a monetary award, appropriately restraining and/or" +"prohibiting such unauthorized use without the necessity of ID posting" +"bond or other security. IN ANY CASE, ID AND ID'S OFFICERS, EMPLOYEES," +"DIRECTORS, AGENTS, LICENSEES, SUBLICENSEES, SUCCESSORS AND ASSIGNS" +"SHALL NOT BE LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST SAVINGS," +"SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT, PUNITIVE OR OTHER SIMILAR" +"DAMAGES ARISING FROM ANY ALLEGED CLAIM FOR BREACH OF WARRANTY, BREACH" +"OF CONTRACT, NEGLIGENCE, STRICT PRODUCT LIABILITY, OR OTHER LEGAL" +"THEORY EVEN IF ID OR ITS AGENT HAVE BEEN ADVISED OF THE POSSIBILITY" +"OF SUCH DAMAGES OR EVEN IF SUCH DAMAGES ARE FORESEEABLE, OR LIABLE" +"FOR ANY CLAIM BY ANY OTHER PARTY. Some jurisdictions do not allow" +"the exclusion or limitation of incidental or consequential damages," +"so the above limitation or exclusion may not apply to you. This" +"Section 6. shall survive cancellation or termination of this Agreement." +"\n" +"\n" +"\n" +"7. U.S. Government Restricted Rights. To the extent applicable," +"the United States Government shall only have those rights to use the" +"Software as expressly stated and expressly limited and restricted in" +"this Agreement, as provided in 48 C.F.R. §§ 227.7201 through 227.7204," +"inclusive." +"\n" +"\n" +"\n" +"8. General Provisions. Neither this Agreement nor any part or" +"portion hereof shall be assigned or sublicensed by you. ID may assign its" +"rights under this Agreement in ID's sole discretion. Should any provision" +"of this Agreement be held to be void, invalid, unenforceable or illegal by" +"a court of competent jurisdiction, the validity and enforceability of the" +"other provisions shall not be affected thereby. If any provision is" +"determined to be unenforceable by a court of competent jurisdiction, you" +"agree to a modification of such provision to provide for enforcement of" +"the provision's intent, to the extent permitted by applicable law." +"Failure of ID to enforce any provision of this Agreement shall not" +"constitute or be construed as a waiver of such provision or of the right" +"to enforce such provision. Immediately upon your failure to comply with" +"or breach of any term or provision of this Agreement, THIS AGREEMENT" +"AND YOUR LICENSE SHALL AUTOMATICALLY TERMINATE, WITHOUT NOTICE, AND ID" +"MAY PURSUE ALL RELIEF AND REMEDIES AGAINST YOU WHICH ARE AVAILABLE UNDER" +"APPLICABLE LAW AND/OR THIS AGREEMENT. In the event this Agreement is" +"terminated, you shall have no right to use the Software, in any manner," +"and you shall immediately destroy all copies of the Software in your" +"possession, custody or control." +"\n" +"\n" +"\n" +"YOU ACKNOWLEDGE THAT YOU HAVE READ THIS AGREEMENT, YOU UNDERSTAND THIS" +"AGREEMENT, AND UNDERSTAND THAT BY CONTINUING THE INSTALLATION OF THE" +"SOFTWARE, BY LOADING OR RUNNING THE SOFTWARE, OR BY PLACING OR COPYING" +"THE SOFTWARE ONTO YOUR COMPUTER HARD DRIVE OR RAM, YOU AGREE TO BE BOUND" +"BY THE TERMS AND CONDITIONS OF THIS AGREEMENT. YOU FURTHER AGREE THAT," +"EXCEPT FOR WRITTEN SEPARATE AGREEMENTS BETWEEN ID AND YOU, THIS " +"AGREEMENT IS A COMPLETE AND EXCLUSIVE STATEMENT OF THE RIGHTS AND" +"LIABILITIES OF THE PARTIES HERETO. THIS AGREEMENT SUPERSEDES ALL PRIOR" +"ORAL AGREEMENTS, PROPOSALS OR UNDERSTANDINGS, AND ANY OTHER" +"COMMUNICATIONS BETWEEN ID AND YOU RELATING TO THE SUBJECT MATTER OF" +"THIS AGREEMENT." +"\n" +}; + +resource 'STR#' (5002, "English") { + { /* array StringArray: 9 elements */ + /* [1] */ + "English", + /* [2] */ + "Agree", + /* [3] */ + "Disagree", + /* [4] */ + "Print", + /* [5] */ + "Save...", + /* [6] */ + "IMPORTANT - Read this License Agreement carefully before clicking on " + "the \"Agree\" button. By clicking on the \"Agree\" button, you agree " + "to be bound by the terms of the License Agreement.", + /* [7] */ + "Software License Agreement", + /* [8] */ + "This text cannot be saved. This disk may be full or locked, or the file " + "may be locked.", + /* [9] */ + "Unable to print. Make sure you have selected a printer." + } +}; + diff --git a/src/unix/MacSupport/ioquake3.icns b/src/unix/MacSupport/ioquake3.icns Binary files differnew file mode 100755 index 00000000..30e3b673 --- /dev/null +++ b/src/unix/MacSupport/ioquake3.icns diff --git a/src/unix/unix_main.c b/src/unix/unix_main.c index eb815685..e399140c 100644 --- a/src/unix/unix_main.c +++ b/src/unix/unix_main.c @@ -1237,7 +1237,7 @@ void Sys_ANSIColorify( const char *msg, char *buffer, int bufferSize ) if( msg[ i ] == '\n' ) { Com_sprintf( tempBuffer, 7, "%c[0m\n", 0x1B ); - strncat( buffer, tempBuffer, bufferSize ); + strncat( buffer, tempBuffer, bufferSize - 1); i++; } else if( msg[ i ] == Q_COLOR_ESCAPE ) @@ -1259,7 +1259,7 @@ void Sys_ANSIColorify( const char *msg, char *buffer, int bufferSize ) if( escapeCode ) { Com_sprintf( tempBuffer, 7, "%c[%sm", 0x1B, escapeCode ); - strncat( buffer, tempBuffer, bufferSize ); + strncat( buffer, tempBuffer, bufferSize - 1); } i++; @@ -1268,7 +1268,7 @@ void Sys_ANSIColorify( const char *msg, char *buffer, int bufferSize ) else { Com_sprintf( tempBuffer, 7, "%c", msg[ i++ ] ); - strncat( buffer, tempBuffer, bufferSize ); + strncat( buffer, tempBuffer, bufferSize - 1); } } } @@ -1383,8 +1383,42 @@ void Sys_ParseArgs( int argc, char* argv[] ) { } } +#ifdef MACOS_X +/* +================= +Sys_EscapeAppBundle + +Discovers if passed dir is suffixed with the directory structure of a +Mac OS X .app bundle. If it is, the .app directory structure is stripped off +the end and the result is returned. If not, dir is returned untouched. + +================= +*/ +char *Sys_StripAppBundle(char *dir) +{ + static char cwd[MAX_OSPATH]; + + Q_strncpyz(cwd, dir, sizeof(cwd)); + if(strcmp(basename(cwd), "MacOS")) + return dir; + Q_strncpyz(cwd, dirname(cwd), sizeof(cwd)); + if(strcmp(basename(cwd), "Contents")) + return dir; + Q_strncpyz(cwd, dirname(cwd), sizeof(cwd)); + if(!strstr(basename(cwd), ".app")) + return dir; + Q_strncpyz(cwd, dirname(cwd), sizeof(cwd)); + return cwd; +} +#endif /* MACOS_X */ + #ifndef DEFAULT_BASEDIR -# define DEFAULT_BASEDIR Sys_DefaultCDPath() + #ifdef MACOS_X + // if run from an .app bundle, we want to also search its containing dir + #define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_DefaultCDPath()) + #else + #define DEFAULT_BASEDIR Sys_DefaultCDPath() + #endif #endif #include "../client/client.h" diff --git a/src/unix/unix_net.c b/src/unix/unix_net.c index d89e766a..31d27c8d 100644 --- a/src/unix/unix_net.c +++ b/src/unix/unix_net.c @@ -649,19 +649,40 @@ char *NET_ErrorString (void) // sleeps msec or until net socket is ready void NET_Sleep(int msec) { - struct timeval timeout; + struct timeval timeout; fd_set fdset; extern qboolean stdin_active; + int highestfd = 0; - if (!ip_socket || !com_dedicated->integer) + if (!com_dedicated->integer) return; // we're not a server, just run full speed FD_ZERO(&fdset); if (stdin_active) + { FD_SET(0, &fdset); // stdin is processed too - FD_SET(ip_socket, &fdset); // network socket - timeout.tv_sec = msec/1000; - timeout.tv_usec = (msec%1000)*1000; - select(ip_socket+1, &fdset, NULL, NULL, &timeout); + highestfd = 1; + } + if(ip_socket) + { + FD_SET(ip_socket, &fdset); // network socket + if(ip_socket >= highestfd) + highestfd = ip_socket + 1; + } + + if(highestfd) + { + if(msec >= 0) + { + timeout.tv_sec = msec/1000; + timeout.tv_usec = (msec%1000)*1000; + select(highestfd, &fdset, NULL, NULL, &timeout); + } + else + { + // Block indefinitely + select(highestfd, &fdset, NULL, NULL, NULL); + } + } } diff --git a/src/win32/win_shared.c b/src/win32/win_shared.c index ca7644ba..5ed7770c 100644 --- a/src/win32/win_shared.c +++ b/src/win32/win_shared.c @@ -288,15 +288,32 @@ char *Sys_GetCurrentUser( void ) char *Sys_DefaultHomePath(void) { TCHAR szPath[MAX_PATH]; static char path[MAX_OSPATH]; + FARPROC qSHGetFolderPath; + HMODULE shfolder = LoadLibrary("shfolder.dll"); + + if(shfolder == NULL) { + Com_Printf("Unable to load SHFolder.dll\n"); + return NULL; + } - if( !SUCCEEDED( SHGetFolderPath( NULL, CSIDL_LOCAL_APPDATA, - NULL, 0, szPath ) ) ) + qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA"); + if(qSHGetFolderPath == NULL) { + Com_Printf("Unable to find SHGetFolderPath in SHFolder.dll\n"); + FreeLibrary(shfolder); + return NULL; + } + if( !SUCCEEDED( qSHGetFolderPath( NULL, CSIDL_APPDATA, + NULL, 0, szPath ) ) ) + { + Com_Printf("Unable to detect CSIDL_APPDATA\n"); + FreeLibrary(shfolder); return NULL; } Q_strncpyz( path, szPath, sizeof(path) ); Q_strcat( path, sizeof(path), "\\Tremulous" ); + FreeLibrary(shfolder); if( !CreateDirectory( path, NULL ) ) { if( GetLastError() != ERROR_ALREADY_EXISTS ) |