const char* PHandler_OpenTempFile(char* name, char* fullfilepath, int fplen){ // Load a plugin, safe for use

    void *buf;
    int len;
    int wlen;
    char* file;
    char tmpfile[MAX_QPATH];
    char filepath[MAX_QPATH];
	
    Com_sprintf(filepath, sizeof(filepath),"plugins/%s" DLL_EXT, name);

    len = FS_ReadFile(filepath, &buf);

    if(len < 100)
        len = FS_SV_ReadFile( filepath, &buf );

    if(len < 100)
    {
        Com_Printf("No such file found: %s. Can not load this plugin.\n", filepath);
        return NULL;

    }
	
	if(PHandler_VerifyPlugin(buf, len) == qfalse)
	{
	    Com_Printf("%s is not a plugin file or is corrupt or contains disallowed functions.\n", filepath);
		FS_FreeFile(buf);
		return NULL;
	}
	Com_sprintf(tmpfile, sizeof(tmpfile), "plugin.%s.tmp", name);
    /* If there is already such a file remove it now */
    file = FS_SV_GetFilepath( tmpfile, fullfilepath, fplen );
    if(file)
    {
        FS_RemoveOSPath(file);
        file = FS_SV_GetFilepath( tmpfile, fullfilepath, fplen );
        if(file)
        {
            FS_RemoveOSPath(file);
        }
    }
    wlen = FS_SV_HomeWriteFile( tmpfile, buf, len);
    if(wlen != len)
    {
            Com_PrintError("fs_homepath is readonly. Can not load this plugin.\n");
            FS_FreeFile(buf);
            return NULL;
    }
    //Additional test if a file is there and creation of full filepath
    FS_FreeFile(buf);
    return FS_SV_GetFilepath( tmpfile, fullfilepath, fplen );
}
void PHandler_CloseTempFile(char* filepath)
{
    if(!com_developer || com_developer->integer == 0)
        FS_RemoveOSPath(filepath);
}
int PbSVLoadModule()
{
	char hash[128];
	long unsigned sizeofhash;

	char modname[256];
	char modname_dest[256];
	const char* dlname;
	const char* dlname2;
	byte* imagebase;

	if ( pbsv.hLibModule )
	{
		return 0;
	}
	
	PbSvUnload();

	if ( FS_FileExistsOSPath( PbSv6makefn(modname, "pbsvnew" DLL_EXT) ) == qtrue )
	{
		Sys_Chmod( PbSv6makefn(modname, "pbsvold" DLL_EXT), 0777);
		FS_RemoveOSPath( PbSv6makefn(modname, "pbsvold" DLL_EXT) );
		rename( PbSv6makefn(modname, "pbsv" DLL_EXT),  PbSv6makefn(modname_dest, "pbsvold" DLL_EXT) );
		Sys_Chmod( PbSv6makefn(modname, "pbsv" DLL_EXT), 0777);
		FS_RemoveOSPath( PbSv6makefn(modname, "pbsv" DLL_EXT) );
		rename( PbSv6makefn(modname, "pbsvnew" DLL_EXT), PbSv6makefn(modname_dest, "pbsv" DLL_EXT) );
	}

	if(com_securemode)
	{

		dlname = PbSv6makefn(modname, "pbag" DLL_EXT);
		dlname2 = PbSv6makefn(modname_dest, "pbags" DLL_EXT);

		if ( FS_FileExistsOSPath( dlname ) == qtrue )
		{
			FS_RemoveOSPath( dlname2 );
			rename( dlname ,dlname2 );
			FS_RemoveOSPath( dlname );
		}

		hash[0] = '\0';
		sizeofhash = sizeof(hash);

		Sec_HashFile(SEC_HASH_TIGER, dlname2, hash, &sizeofhash, qfalse);

		if(Q_stricmp(hash ,PBAG_HASH))
		{
			Com_Printf("Tiger = %s\n", hash);
			Com_PrintError("%s checksum missmatch! PunkBuster will not startup in securemode when the checksum is invalid.\n", dlname2);
			return 1;
		}


		dlname = PbSv6makefn(modname, "pbcl" DLL_EXT);
		dlname2 = PbSv6makefn(modname_dest, "pbcls" DLL_EXT);

		if ( FS_FileExistsOSPath( dlname ) == qtrue )
		{
			FS_RemoveOSPath( dlname2 );
			rename( dlname ,dlname2 );
			FS_RemoveOSPath( dlname );
		}

		hash[0] = '\0';
		sizeofhash = sizeof(hash);

		Sec_HashFile(SEC_HASH_TIGER, dlname2, hash, &sizeofhash, qfalse);

		if(Q_stricmp(hash ,PBCL_HASH))
		{
			Com_Printf("Tiger = %s\n", hash);
			Com_PrintError("%s checksum missmatch! PunkBuster will not startup in securemode when the checksum is invalid.\n", dlname2);
			return 1;
		}

		dlname2 = PbSv6makefn(modname, "pbsv" DLL_EXT);

		hash[0] = '\0';
		sizeofhash = sizeof(hash);

		Sec_HashFile(SEC_HASH_TIGER, dlname2, hash, &sizeofhash, qfalse);

		if(Q_stricmp(hash ,PBSV_HASH))
		{
			Com_Printf("Tiger = %s\n", hash);
			Com_PrintError("%s checksum missmatch! PunkBuster will not startup in securemode when the checksum is invalid.\n", dlname2);
			return 1;
		}

	}

	dlname = PbSv6makefn(modname, "pbsv" DLL_EXT);
	pbsv.hLibModule = Sys_LoadLibrary( dlname );

	if ( pbsv.hLibModule == NULL )
	{
		return 1;
	}

	if(com_securemode)
	{

		/* Remove system() */
		imagebase = LIBRARY_ADDRESS_BY_HANDLE( pbsv.hLibModule );

		if(Sys_MemoryProtectWrite( (void*)(imagebase + 0x4c6e0), 0xdfdf7 ) == qfalse)
		{
			return 1;
		}

		SetCall((DWORD)(imagebase + 0x114346), PB_SystemDummy);
		SetCall((DWORD)(imagebase + 0xc23cb), PB_SystemDummy);

		if(Sys_MemoryProtectExec( (void*)(imagebase + 0x4c6e0), 0xdfdf7 ) == qfalse)
		{
			return 1;
		}
	}


	pbsv.sa = Sys_GetProcedure( "sa" );
    pbsv.sb = Sys_GetProcedure( "sb" );
	
    if ( pbsv.sa && pbsv.sb ){
    
		pbsv.wantdisable = 0;
		return 0;
    }else{
	
        PbSvUnload();
	return 1;
	}

}
void Sec_Update( qboolean getbasefiles ){
    char buff[SEC_UPDATE_INITIALBUFFSIZE];
    char *ptr,*ptr2, *testfile;
	char filepathbuf[MAX_OSPATH];
    char baseurl[1024];
    char name1[256],name2[256];
    sec_file_t files, *currFile = &files;
    qboolean dlExec = qfalse;
    int len;
    char hash[128];
    long unsigned size;
	ftRequest_t* filetransferobj;
	ftRequest_t* curfileobj;
	int transret;
	mvabuf;

	
    if(!Sec_Initialized()){
	return;
    }
    
#ifdef CAN_UPDATE
    Com_Printf("\n-----------------------------\n");
    Com_Printf(" CoD4X Auto Update\n");
    Com_Printf(" Current version: %g\n",SEC_VERSION);
    Com_Printf(" Current build: %d\n",BUILD_NUMBER);
    Com_Printf(" Current type: %s\n",SEC_TYPE == 's' ? "stable      " : "experimental");
    Com_Printf("-----------------------------\n\n");

    canupdate = Cvar_RegisterBool("allowupdating", qtrue, 0, "This enables autoupdating of CoD4 server with new versions.");

    if(getbasefiles == qtrue)
    {

        Com_sprintf(buff, sizeof(buff), "http://" SEC_UPDATE_HOST SEC_UPDATE_GETGROUNDVERSION);

    }else{

        if(canupdate->boolean == qfalse)
            return;

        Com_sprintf(buff, sizeof(buff), "http://" SEC_UPDATE_HOST SEC_UPDATE_GETVERSION);
    }
#else
    if(getbasefiles == qtrue)
    {
        Com_sprintf(buff, sizeof(buff), "http://" SEC_UPDATE_HOST SEC_UPDATE_GETGROUNDVERSION);
    }else{
        return;
    }
#endif
	
	filetransferobj = FileDownloadRequest( buff );

    if(filetransferobj == NULL){
		return;
    }

	do {
		transret = FileDownloadSendReceive( filetransferobj );
		usleep(20000);
	} while (transret == 0);

    if(transret < 0)
	{
		FileDownloadFreeRequest(filetransferobj);
		return;
    }
    /* Need to catch errors */
 //   FS_WriteFile("tmp.txt", va("%d", status), 1);

    // TODO: Do something with the status?

//    FS_WriteFile("tmp2.txt", packet.header, packet.headerLength);
//    FS_WriteFile("tmp3.txt", packet.content, packet.contentLength);
    if(filetransferobj->code <= 0){
		Com_PrintError("Receiving data. Error code: %d.\n", filetransferobj->code);
		FileDownloadFreeRequest(filetransferobj);
		return;
    }
    if(filetransferobj->code == 204){
		Com_Printf("\nServer is up to date.\n\n");
		FileDownloadFreeRequest(filetransferobj);
		return;
    }
    else if(filetransferobj->code != 200){
		Com_PrintWarning("The update server's malfunction.\nStatus code: %d.\n", filetransferobj->code);
		FileDownloadFreeRequest(filetransferobj);
		return;
    }

    Com_Memset(&files, 0, sizeof(files));

    /* We need to parse filenames etc */
    ptr = Sec_StrTok((char*)(filetransferobj->recvmsg.data + filetransferobj->headerLength),"\n",42); // Yes, 42.
    if(ptr == NULL || Q_stricmpn("baseurl: ", ptr, 9))
    {
	    Com_PrintWarning("Sec_Update: Corrupt data from update server. Update aborted.\n");
		FileDownloadFreeRequest(filetransferobj);
		return;
    }
    Q_strncpyz(baseurl, ptr +9, sizeof(baseurl));

    ptr = Sec_StrTok(NULL,"\n",42); // Yes, 42 again.

	while(ptr != NULL){
		
		currFile->next = Sec_GMalloc(sec_file_t,1);
		currFile = currFile->next;
		Com_Memset(currFile,0,sizeof(sec_file_t));
		ptr2 = strchr(ptr,' ');
		if(ptr2 == NULL){
			Com_PrintWarning("Sec_Update: Corrupt data from update server. Update aborted.\nDebug:\"%s\"\n",ptr);
			FileDownloadFreeRequest(filetransferobj);
			return;
		}
		*ptr2++ = 0;
		Q_strncpyz(currFile->path,ptr,sizeof(currFile->path));
		ptr = ptr2;
		ptr2 = strchr(ptr,' ');
		if(ptr2 == NULL){
			Com_PrintWarning("Sec_Update: Corrupt data from update server. Update aborted.\nDebug:\"%s\"\n",ptr);
			FileDownloadFreeRequest(filetransferobj);
			return;
		}
		*ptr2++ = 0;
		if(!isInteger(ptr, 0)){
			Com_PrintWarning("Sec_Update: Corrupt data from update server - size is not a number. Update aborted.\nDebug:\"%s\"\n",ptr);
			FileDownloadFreeRequest(filetransferobj);
			return;
		}
		currFile->size = atoi(ptr);
		Q_strncpyz(currFile->hash,ptr2,sizeof(currFile->hash));
		Q_strncpyz(currFile->name,currFile->path, sizeof(currFile->name));
		//printf("DEBUG: File to download: link: \"%s\", name: \"%s\", size: %d, hash: \"%s\"\n\n",file.path,file.name,file.size,file.hash);

		Com_sprintf(buff, sizeof(buff), SEC_UPDATE_DOWNLOAD(baseurl, currFile->path));
		
		curfileobj = FileDownloadRequest(buff);
		if(curfileobj == NULL)
		{
			FileDownloadFreeRequest(filetransferobj);
			return;	
		}

		Com_Printf("Downloading file: \"%s\"\n\n",currFile->name);

		do {
			transret = FileDownloadSendReceive( curfileobj );
			Com_Printf("%s", FileDownloadGenerateProgress( curfileobj ));
			usleep(20000);
		} while (transret == 0);
		
		Com_Printf("\n");

		if(transret < 0)
		{
			FileDownloadFreeRequest(curfileobj);
			FileDownloadFreeRequest(filetransferobj);
			return;
		}

		Q_strncpyz(buff,currFile->name, sizeof(buff));
		Q_strcat(buff, sizeof(buff),".new");

		if(curfileobj->code != 200){
			Com_PrintError("Downloading has failed! Error code: %d. Update aborted.\n", curfileobj->code);
			FileDownloadFreeRequest(filetransferobj);
			FileDownloadFreeRequest(curfileobj);
			return;
		}

		len = FS_SV_BaseWriteFile(buff, curfileobj->recvmsg.data + curfileobj->headerLength, curfileobj->contentLength);
		if(len != curfileobj->contentLength){

			len = FS_SV_HomeWriteFile(buff, curfileobj->recvmsg.data + curfileobj->headerLength, curfileobj->contentLength);
			if(len != curfileobj->contentLength)
			{
				Com_PrintError("Opening \"%s\" for writing! Update aborted.\n",buff);
				FileDownloadFreeRequest(filetransferobj);
				FileDownloadFreeRequest(curfileobj);
				return;
			}
		}

		ptr = Sec_StrTok(NULL,"\n",42); // Yes, 42 again.

		size = sizeof(hash);
		
		if(!Sec_HashMemory(SEC_HASH_SHA256, curfileobj->recvmsg.data + curfileobj->headerLength, curfileobj->contentLength, hash, &size,qfalse)){
			Com_PrintError("Hashing the file \"%s\". Error code: %s.\nUpdate aborted.\n",currFile->name,Sec_CryptErrStr(SecCryptErr));
			FileDownloadFreeRequest(filetransferobj);
			FileDownloadFreeRequest(curfileobj);
			return;
		}

		FileDownloadFreeRequest(curfileobj);
		
		if(!Q_strncmp(hash, currFile->hash, size)){
			Com_Printf("Successfully downloaded file \"%s\".\n", currFile->name);
		}
		else{
			Com_PrintError("File \"%s\" is corrupt!\nUpdate aborted.\n",currFile->name);
			Com_DPrintf("Hash: \"%s\", correct hash: \"%s\".\n",hash,currFile->hash);
			FileDownloadFreeRequest(filetransferobj);
			return;
		}
		
	}

	FileDownloadFreeRequest(filetransferobj);

    Com_Printf("All files downloaded successfully. Applying update...\n");

    currFile = files.next;
    do{
		Com_Printf("Updating file %s...\n", currFile->name);
		Q_strncpyz(name1, currFile->name, sizeof(name1));

		Q_strcat(name1, sizeof(name1), ".old");

		Q_strncpyz(name2, currFile->name, sizeof(name2));

		Q_strcat(name2, sizeof(name2), ".new");

		testfile = FS_SV_GetFilepath(name1, filepathbuf, sizeof(filepathbuf));
		if(testfile != NULL)
		{ // Old file exists, back it up
			FS_SV_BaseRemove( name1 );
			FS_SV_HomeRemove( name1 );
			testfile = FS_SV_GetFilepath(name1, filepathbuf, sizeof(filepathbuf));
			if(testfile != NULL)
			{
				Com_PrintWarning("Couldn't remove backup file: %s\n", testfile);
			}
			if(FS_SV_HomeFileExists(name1) == qtrue)
			{
				Com_PrintError("Couldn't remove backup file from fs_homepath: %s\n", name1);
			}
		}
		// Check if an old file exists with this name
		testfile = FS_SV_GetFilepath(currFile->name, filepathbuf, sizeof(filepathbuf));
		if(testfile != NULL)
		{ // Old file exists, back it up
			FS_SV_Rename(currFile->name, name1);
		}
		testfile = FS_SV_GetFilepath(currFile->name, filepathbuf, sizeof(filepathbuf));
		// We couldn't back it up. Now we try to just delete it.
		if(testfile != NULL)
		{
			FS_SV_BaseRemove( currFile->name );
			FS_SV_HomeRemove( currFile->name );
			testfile = FS_SV_GetFilepath( currFile->name, filepathbuf, sizeof(filepathbuf) );
			if(testfile != NULL)
			{
				Com_PrintWarning("Couldn't remove file: %s\n", testfile);
			}
			if(FS_SV_HomeFileExists(currFile->name) == qtrue)
			{
				Com_PrintError("Couldn't remove file from fs_homepath: %s\n", currFile->name);
				Com_PrintError("Update has failed!\n");
				return;
			}
		}

		if(Q_strncmp(currFile->name, EXECUTABLE_NAME, 15)){
			/* This is not the executable file */
			FS_SV_Rename(name2, currFile->name);
			testfile = FS_SV_GetFilepath(currFile->name, filepathbuf, sizeof(filepathbuf));
			if(testfile == NULL)
			{
				Com_PrintError("Failed to rename file %s to %s\n", name2,currFile->name);
				Com_PrintError("Update has failed!\n");
				return;
			}
			Com_Printf("Update on file %s successfully applied.\n",currFile->name);

		}else{
			/* This is the executable file */
			testfile = FS_SV_GetFilepath(name2, filepathbuf, sizeof(filepathbuf));
			if(testfile == NULL)
			{
				Com_PrintError("Can not find file %s\n", name2);
				Com_PrintError("Update has failed!\n");
				return;
			}
			if(FS_SetPermissionsExec(name2) == qfalse)
			{
				Com_PrintError("CRITICAL ERROR: failed to change mode of the file \"%s\"! Aborting, manual installation might be required.\n", name2);
				return;
			}
			FS_RenameOSPath(Sys_ExeFile(), va("%s.dead", Sys_ExeFile()));
			FS_RemoveOSPath(va("%s.dead", Sys_ExeFile()));
			FS_RemoveOSPath(Sys_ExeFile());
			if(FS_FileExistsOSPath(Sys_ExeFile()))
			{
				Com_PrintError("Failed to delete file %s\n", Sys_ExeFile());
				Com_PrintError("Update has failed!\n");
				return;
			}
			FS_RenameOSPath(testfile, Sys_ExeFile());
			if(!FS_FileExistsOSPath(Sys_ExeFile()))
			{
				Com_PrintError("Failed to rename file %s\n", testfile);
				Com_PrintError("Update has failed! Manual reinstallation of file %s is required. This server is now broken!\n", Sys_ExeFile());
				return;
			}
			Com_Printf("Update on file %s successfully applied.\n", Sys_ExeFile());
			dlExec = qtrue;
		}
		currFile = currFile->next;

    }while(currFile != NULL);

    Sec_FreeFileStruct(files.next);
    Com_Printf("Finalizing update...\n");


    if(dlExec == qtrue)
    {
		Sys_Restart("System has been updated and will restart now.");
    }else{
        FS_Restart( 0 );
    }
}