static void Com_SetupDownload(const char *remote, const char *filename) { dld.bWWWDl = qtrue; dld.bWWWDlDisconnected = qtrue; // download format: @remotename@localname Q_strncpyz(dld.downloadList, va("@%s@%s", filename, filename), MAX_INFO_STRING); Q_strncpyz(dld.originalDownloadName, va("%s/%s", Cvar_VariableString("fs_game"), filename), sizeof(dld.originalDownloadName)); Q_strncpyz(dld.downloadName, va("%s/%s", remote, filename), sizeof(dld.downloadName)); Q_strncpyz(dld.downloadTempName, FS_BuildOSPath(Cvar_VariableString("fs_homepath"), Cvar_VariableString("fs_game"), va("%s.tmp", filename)), sizeof(dld.downloadTempName)); if (!DL_BeginDownload(dld.downloadTempName, dld.downloadName)) { Com_Error(ERR_DROP, "Could not download file: \"%s\"", dld.downloadName); dld.bWWWDlAborting = qtrue; } }
/* ===================== CL_ParseDownload A download message has been received from the server ===================== */ void CL_ParseDownload( msg_t *msg ) { int size; unsigned char data[ MAX_MSGLEN ]; int block; if ( !*cls.downloadTempName ) { Com_Printf("%s", _( "Server sending download, but no download was requested\n" )); CL_AddReliableCommand( "stopdl" ); return; } // read the data block = MSG_ReadShort( msg ); // TTimo - www dl // if we haven't acked the download redirect yet if ( block == -1 ) { if ( !clc.bWWWDl ) { // server is sending us a www download Q_strncpyz( cls.originalDownloadName, cls.downloadName, sizeof( cls.originalDownloadName ) ); Q_strncpyz( cls.downloadName, MSG_ReadString( msg ), sizeof( cls.downloadName ) ); clc.downloadSize = MSG_ReadLong( msg ); clc.downloadFlags = MSG_ReadLong( msg ); Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); Com_DPrintf( "Server redirected download: %s\n", cls.downloadName ); clc.bWWWDl = qtrue; // activate wwwdl client loop CL_AddReliableCommand( "wwwdl ack" ); // make sure the server is not trying to redirect us again on a bad checksum if ( strstr( clc.badChecksumList, va( "@%s", cls.originalDownloadName ) ) ) { Com_Printf(_( "refusing redirect to %s by server (bad checksum)\n"), cls.downloadName ); CL_AddReliableCommand( "wwwdl fail" ); clc.bWWWDlAborting = qtrue; return; } // make downloadTempName an OS path Q_strncpyz( cls.downloadTempName, FS_BuildOSPath( Cvar_VariableString( "fs_homepath" ), cls.downloadTempName, "" ), sizeof( cls.downloadTempName ) ); cls.downloadTempName[ strlen( cls.downloadTempName ) - 1 ] = '\0'; if ( !DL_BeginDownload( cls.downloadTempName, cls.downloadName, com_developer->integer ) ) { // setting bWWWDl to false after sending the wwwdl fail doesn't work // not sure why, but I suspect we have to eat all remaining block -1 that the server has sent us // still leave a flag so that CL_WWWDownload is inactive // we count on server sending us a gamestate to start up clean again CL_AddReliableCommand( "wwwdl fail" ); clc.bWWWDlAborting = qtrue; Com_Printf(_( "Failed to initialize download for '%s'\n"), cls.downloadName ); } // Check for a disconnected download // we'll let the server disconnect us when it gets the bbl8r message if ( clc.downloadFlags & ( 1 << DL_FLAG_DISCON ) ) { CL_AddReliableCommand( "wwwdl bbl8r" ); cls.bWWWDlDisconnected = qtrue; } return; } else { // server keeps sending that message till we ack it, eat and ignore //MSG_ReadLong( msg ); MSG_ReadString( msg ); MSG_ReadLong( msg ); MSG_ReadLong( msg ); return; } } if ( !block ) { // block zero is special, contains file size clc.downloadSize = MSG_ReadLong( msg ); Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); if ( clc.downloadSize < 0 ) { Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) ); } } size = MSG_ReadShort( msg ); if ( size < 0 || size > sizeof( data ) ) { Com_Error( ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size ); } MSG_ReadData( msg, data, size ); if ( clc.downloadBlock != block ) { Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block ); return; } // open the file if not opened yet if ( !clc.download ) { clc.download = FS_SV_FOpenFileWrite( cls.downloadTempName ); if ( !clc.download ) { Com_Printf(_( "Could not create %s\n"), cls.downloadTempName ); CL_AddReliableCommand( "stopdl" ); CL_NextDownload(); return; } } if ( size ) { FS_Write( data, size, clc.download ); } CL_AddReliableCommand( va( "nextdl %d", clc.downloadBlock ) ); clc.downloadBlock++; clc.downloadCount += size; // So UI gets access to it Cvar_SetValue( "cl_downloadCount", clc.downloadCount ); if ( !size ) { // A zero length block means EOF if ( clc.download ) { FS_FCloseFile( clc.download ); clc.download = 0; // rename the file FS_SV_Rename( cls.downloadTempName, cls.downloadName ); } *cls.downloadTempName = *cls.downloadName = 0; Cvar_Set( "cl_downloadName", "" ); // send intentions now // We need this because without it, we would hold the last nextdl and then start // loading right away. If we take a while to load, the server is happily trying // to send us that last block over and over. // Write it twice to help make sure we acknowledge the download CL_WritePacket(); CL_WritePacket(); // get another file if needed CL_NextDownload(); } }
qboolean CL_InitUpdateDownloads(void) { #ifdef FEATURE_AUTOUPDATE if (autoupdate.updateStarted && NET_CompareAdr(autoupdate.autoupdateServer, clc.serverAddress)) { if (strlen(com_updatefiles->string) > 4) { char *updateFile; char updateFilesRemaining[MAX_TOKEN_CHARS] = ""; clc.bWWWDl = qtrue; cls.bWWWDlDisconnected = qtrue; updateFile = strtok(com_updatefiles->string, ";"); if (updateFile == NULL) { Com_Error(ERR_AUTOUPDATE, "Could not parse update string."); } else { // download format: @remotename@localname Q_strncpyz(clc.downloadList, va("@%s@%s", updateFile, updateFile), MAX_INFO_STRING); Q_strncpyz(cls.originalDownloadName, updateFile, sizeof(cls.originalDownloadName)); Q_strncpyz(cls.downloadName, va("%s/%s", UPDATE_SERVER_NAME, updateFile), sizeof(cls.downloadName)); Q_strncpyz(cls.downloadTempName, FS_BuildOSPath(Cvar_VariableString("fs_homepath"), AUTOUPDATE_DIR, va("%s.tmp", cls.originalDownloadName)), sizeof(cls.downloadTempName)); // TODO: add file size, so UI can show progress bar //Cvar_SetValue("cl_downloadSize", clc.downloadSize); if (!DL_BeginDownload(cls.downloadTempName, cls.downloadName)) { Com_Error(ERR_AUTOUPDATE, "Could not download an update file: \"%s\"", cls.downloadName); clc.bWWWDlAborting = qtrue; } while (1) { updateFile = strtok(NULL, ";"); if (updateFile == NULL) { break; } Q_strcat(updateFilesRemaining, sizeof(updateFilesRemaining), va("%s;", updateFile)); } if (strlen(updateFilesRemaining) > 4) { Cvar_Set("com_updatefiles", updateFilesRemaining); } else { Cvar_Set("com_updatefiles", ""); } } } return qtrue; } #endif // FEATURE_AUTOUPDATE return qfalse; }