Beispiel #1
0
/*
* SV_Download_f
* Download command issued from server
*/
static void SV_Download_f( void )
{
	qboolean success;
	char *s;
	char url[MAX_STRING_CHARS], filepath[MAX_QPATH], writepath[MAX_QPATH];

	if( Cmd_Argc() != 2 )
	{
		Com_Printf( "Usage: %s <url>\n", Cmd_Argv( 0 ) );
		Com_Printf( "Downloads .pk3 or .pak from URL to gamedir and adds it to the server\n" );
		Com_Printf( "Note, server will not function properly while downloading\n" );
		return;
	}

	s = Cmd_Argv( 1 );
	if( !Com_GlobMatch( "*://*", s, qfalse ) )
		Q_strncpyz( url, "http://", sizeof( url ) );
	else
		url[0] = 0;
	Q_strncatz( url, s, sizeof( url ) );

	s = strrchr( url, '/' );
	if( !s )
	{
		Com_Printf( "%s: invalid URL\n", Cmd_Argv( 0 ) );
		return;
	}

	Q_strncpyz( filepath, va( "%s/%s", FS_GameDirectory(), s + 1 ), sizeof( filepath ) );
	Q_strncpyz( writepath, va( "%s.tmp", filepath ), sizeof( writepath ) );

	if( !FS_CheckPakExtension( writepath ) )
	{
		Com_Printf( "Missing or invalid archive extension. Only download of pack files is supported\n" );
		return;
	}

	Com_Printf( "download url: %s\n", url );

	webDownloadPercentPrint = 0;

	success = Web_Get( url, NULL, writepath, qtrue, 60 * 30, 60, SV_WebDownloadProgress, qfalse );

	if( !success )
	{
		Com_Printf( "Server web download failed\n" );
		return;
	}

	if( !FS_MoveBaseFile( writepath, filepath ) )
	{
		Com_Printf( "Couldn't rename the downloaded file. Download failed\n" );
		return;
	}

	Com_Printf( "Download successful\n" );

	// update the map list, which also does a filesystem rescan
	ML_Update();
}
Beispiel #2
0
/*
* CL_DownloadComplete
* 
* Checks downloaded file's checksum, renames it and adds to the filesystem.
*/
static void CL_DownloadComplete( void )
{
	unsigned checksum = 0;
	int length;
	qboolean updateMapList = qfalse;

	FS_FCloseFile( cls.download.filenum );
	cls.download.filenum = 0;

	// verify checksum
	if( FS_CheckPakExtension( cls.download.name ) )
	{
		if( !FS_IsPakValid( cls.download.tempname, &checksum ) )
		{
			Com_Printf( "Downloaded file is not a valid pack file. Removing\n" );
			FS_RemoveBaseFile( cls.download.tempname );
			return;
		}
	}
	else
	{
		length = FS_LoadBaseFile( cls.download.tempname, NULL, NULL, 0 );
		if( length < 0 )
		{
			Com_Printf( "Error: Couldn't load downloaded file\n" );
			return;
		}
		checksum = FS_ChecksumBaseFile( cls.download.tempname );
	}

	if( cls.download.checksum != checksum )
	{
		Com_Printf( "Downloaded file has wrong checksum. Removing: %u %u %s\n", cls.download.checksum, checksum, cls.download.tempname );
		FS_RemoveBaseFile( cls.download.tempname );
		return;
	}

	if( !FS_MoveBaseFile( cls.download.tempname, cls.download.name ) )
	{
		Com_Printf( "Failed to rename the downloaded file\n" );
		return;
	}

	if( FS_CheckPakExtension( cls.download.name ) )
		updateMapList = qtrue;
	else if( !Q_stricmp( COM_FileExtension( cls.download.name ), ".bsp" ) )
		updateMapList = qtrue;

	// Maplist hook so we also know when a new map is added
	if( updateMapList )
		ML_Update ();

	cls.download.successCount++;
	cls.download.timeout = 0;
}
Beispiel #3
0
/*
* SV_AutoUpdateComplete_f
*/
static void SV_AutoUpdateComplete_f( void )
{
	// update the map list, which also does a filesystem rescan
	ML_Update();

	if( FS_GetNotifications() & FS_NOTIFY_NEWPAKS )
	{
		// force restart
		svc.lastActivity = 0;
	}
}
Beispiel #4
0
/*
* ML_MapListCmd
* Handler for console command "maplist"
*/
static void ML_MapListCmd( void )
{
	char *pattern;
	mapinfo_t *map;
	int argc = Cmd_Argc();
	unsigned int i;
	struct trie_dump_s *dump = NULL;

	if( argc > 2 )
	{
		Com_Printf( "Usage: %s [rebuild]\n", Cmd_Argv(0) );
		return;
	}

	pattern = (argc == 2 ? Cmd_Argv( 1 ) : NULL);
	if( pattern && !*pattern )
		pattern = NULL;

	if( pattern )
	{
		if( !strcmp( pattern, "rebuild" ) )
		{
			Com_Printf( "Rebuilding map list...\n" );
			ML_Restart( true );
			return;
		}

		if( !strcmp( pattern, "update" ) )
		{
			Com_Printf( "Updating map list...\n" );
			ML_Update();
			return;
		}
	}

	Trie_DumpIf( mlist_filenames_trie, "", TRIE_DUMP_VALUES, ML_PatternMatchesMap, pattern, &dump );
	for( i = 0; i < dump->size; i++ )
	{
		map = ( mapinfo_t * )( dump->key_value_vector[i].value );
		Com_Printf( "%s: %s\n", map->filename, map->fullname );
	}
	Trie_FreeDump( dump );

	Com_Printf( "%d map(s) %s\n", i, pattern ? "matching" : "total" );
}
Beispiel #5
0
/*
* SV_Map_f
* 
* User command to change the map
* map: restart game, and start map
* devmap: restart game, enable cheats, and start map
* gamemap: just start the map
*/
static void SV_Map_f( void )
{
	char *map;
	char mapname[MAX_CONFIGSTRING_CHARS];
	qboolean found = qfalse;

	if( Cmd_Argc() < 2 )
	{
		Com_Printf( "Usage: %s <map>\n", Cmd_Argv( 0 ) );
		return;
	}

	// if map "<map>" is used Cmd_Args() will return the "" as well.
	if( Cmd_Argc() == 2 )
		map = Cmd_Argv( 1 );
	else
		map = Cmd_Args();

	Com_DPrintf( "SV_GameMap(%s)\n", map );

	// applies to fullnames and filenames (whereas + strlen( "maps/" ) wouldnt)
	if( strlen( map ) >= MAX_CONFIGSTRING_CHARS )
	{
		Com_Printf( "Map name too long.\n" );
		return;
	}

	Q_strncpyz( mapname, map, sizeof( mapname ) );
	if( ML_ValidateFilename( mapname ) )
	{
		COM_StripExtension( mapname );
		if( ML_FilenameExists( mapname ) )
		{
			found = qtrue;
		}
		else
		{
			ML_Update();
			if( ML_FilenameExists( mapname ) )
				found = qtrue;
		}
	}

	if( !found )
	{
		if( ML_ValidateFullname( map ) )
		{
			Q_strncpyz( mapname, ML_GetFilename( map ), sizeof( mapname ) );
			if( *mapname )
				found = qtrue;
		}

		if( !found )
		{
			Com_Printf( "Couldn't find map: %s\n", map );
			return;
		}
	}

	if( FS_GetNotifications() & FS_NOTIFT_NEWPAKS )
	{
		FS_RemoveNotifications( FS_NOTIFT_NEWPAKS );
		sv.state = ss_dead; // don't save current level when changing
	}
	else if( !Q_stricmp( Cmd_Argv( 0 ), "map" ) || !Q_stricmp( Cmd_Argv( 0 ), "devmap" ) )
	{
		sv.state = ss_dead; // don't save current level when changing
	}

	// start up the next map
	SV_Map( mapname, !Q_stricmp( Cmd_Argv( 0 ), "devmap" ) );

	// archive server state
	Q_strncpyz( svs.mapcmd, mapname, sizeof( svs.mapcmd ) );
}
Beispiel #6
0
/*
* SV_AutoUpdateFromWeb
*/
void SV_AutoUpdateFromWeb( qboolean checkOnly )
{
	static const char *autoUpdateBaseUrl = APP_UPDATE_URL APP_SERVER_UPDATE_DIRECTORY;
	char checksumString1[32], checksumString2[32];
	unsigned int checksum;
	qboolean success;
	int length, filenum;
	qbyte *data;
	const char *token, *ptr;
	char path[MAX_QPATH];
	int downloadCount = 0, downloadFailed = 0;
	char newVersionTag[MAX_QPATH];
	qboolean newVersion = qfalse;

	if( !dedicated->integer )
		return;

	assert( svs.mapcmd[0] );

	if( !checkOnly )
		SV_UpdateActivity();

	Com_Printf( "\n" );
	Com_Printf( "========== Starting Auto Update ===========\n" );

	Com_Printf( "Checking for updates\n" );

	// download the update file list
	success = SV_WebDownload( autoUpdateBaseUrl, APP_SERVER_UPDATE_FILE, qtrue, qtrue );

	// set as last updated today
	if( !checkOnly )
		Cvar_ForceSet( "sv_lastAutoUpdate", va( "%i", (int)Com_DaysSince1900() ) );

	if( !success ) // no update to do
		goto done;

	// read the file list
	if( ( length = FS_FOpenBaseFile( APP_SERVER_UPDATE_FILE, &filenum, FS_READ ) ) == -1 )
	{
		Com_Printf( "WARNING: Couldn't find %s\n", path );
		goto done;
	}

	if( !length )
	{
		FS_FCloseFile( filenum );
		goto done;
	}

	data = Mem_TempMalloc( length + 1 );
	FS_Read( data, length, filenum );
	FS_FCloseFile( filenum );
	FS_RemoveBaseFile( APP_SERVER_UPDATE_FILE );

	ptr = (const char *)data;

	// first token is always the current release version
	token = COM_ParseExt( &ptr, qtrue );
	if( !token[0] )
		goto cancel;

	// compare versions
	Q_strncpyz( newVersionTag, token, sizeof( newVersionTag ) );
	if( atof( newVersionTag ) > atof( va( "%4.3f", APP_VERSION ) ) )
		newVersion = qtrue;

	while( ptr )
	{
		// we got what should be a checksum
		token = COM_ParseExt( &ptr, qtrue );
		if( !token[0] )
			goto cancel;

		// copy checksum reported by server
		Q_strncpyz( checksumString1, token, sizeof( checksumString1 ) );

		// get filename
		token = COM_ParseExt( &ptr, qtrue );
		if( !token[0] )
			goto cancel;

		// filename should never begin with a slash
		if( token[0] == '/' )
			token++;

		Q_strncpyz( path, token, sizeof( path ) );

		// we got what should be a file path
		if( !COM_ValidateRelativeFilename( path ) )
		{
			Com_Printf( "WARNING: Invalid filename %s\n", path );
			continue;
		}

		checksum = FS_ChecksumBaseFile( path );
		Q_snprintfz( checksumString2, sizeof( checksumString2 ), "%u", checksum );

		// if same checksum no need to update
		if( !strcmp( checksumString1, checksumString2 ) )
			continue;

		// if it's a pack file and the file exists it can't be replaced, so skip
		if( FS_CheckPakExtension( path ) && checksum )
		{
			Com_Printf( "WARNING: Purity check failed for: %s\n", path );
			Com_Printf( "WARNING: This file has been locally modified. It is highly \n" );
			Com_Printf( "WARNING: recommended to restore the original file.\n" );
			Com_Printf( "WARNING: Reinstalling \""APPLICATION"\" might be convenient.\n" );
			continue;	
		}

		if( checkOnly )
		{
			Com_Printf( "File update available : %s\n", path );
			continue;
		}
		
		if( developer->integer )
			Com_Printf( "Downloading update of %s (checksum %s local checksum %s)\n", path, checksumString1, checksumString2 );
		else
			Com_Printf( "Updating %s\n", path );

		if( !SV_WebDownload( autoUpdateBaseUrl, path, qtrue, qtrue ) )
		{
			Com_Printf( "Failed to update %s\n", path );
			downloadFailed++;
		}

		downloadCount++;
	}

cancel:
	Mem_TempFree( data );
done:
	if( newVersion )
	{
		if( downloadCount )
		{
			if( downloadFailed )
				Com_Printf( "This version of "APPLICATION" was updated incompletely\n" );
			else
				Com_Printf( "This version of "APPLICATION" was updated successfully\n\n" );
		}

		Com_Printf( "****** Version %s of "APPLICATION" is available. ******\n", newVersionTag );
		Com_Printf( "****** Please download the new version at "APP_URL" ******\n" );
	}
	else if( downloadCount )
	{
		if( downloadFailed )
			Com_Printf( APPLICATION" was updated incompletely\n" );
		else
			Com_Printf( APPLICATION" was updated successfully\n" );
	}
	else if( !checkOnly )
	{
		if( downloadFailed )
			Com_Printf( "At least one file failed to update\n" );
		else
			Com_Printf( APPLICATION" is up to date\n" );
	}

	Com_Printf( "========== Auto Update Finished ===========\n" );
	Com_Printf( "\n" );

	// update the map list, which also does a filesystem rescan
	ML_Update();

	// if there are any new filesystem entries, restart
	if( FS_GetNotifications() & FS_NOTIFT_NEWPAKS )
	{
		if( sv.state != ss_dead )
		{
			// restart the current map, SV_Map also rescans the filesystem
			Com_Printf( "The server will now restart...\n\n" );

			// start the default map if current map isn't available
			Cbuf_ExecuteText( EXEC_APPEND, va( "map %s\n", svs.mapcmd[0] ? svs.mapcmd : sv_defaultmap->string ) );
		}
	}
}