/* =================== CL_GetServerCommand Set up argc/argv for the given command =================== */ qboolean CL_GetServerCommand( int serverCommandNumber ) { char *s; const char *cmd; // if we have irretrievably lost a reliable command, drop the connection if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) { Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" ); return qfalse; } if ( serverCommandNumber > clc.serverCommandSequence ) { Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" ); return qfalse; } s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ]; Com_DPrintf( "serverCommand: %i : %s\n", serverCommandNumber, s ); Cmd_TokenizeString( s ); cmd = Cmd_Argv(0); if ( !strcmp( cmd, "disconnect" ) ) { Com_Error (ERR_DISCONNECT,"Server disconnected\n"); } if ( !strcmp( cmd, "cs" ) ) { CL_ConfigstringModified(); // reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString() Cmd_TokenizeString( s ); return qtrue; } // the clientLevelShot command is used during development // to generate 128*128 screenshots from the intermission // point of levels for the menu system to use // we pass it along to the cgame to make apropriate adjustments, // but we also clear the console and notify lines here if ( !strcmp( cmd, "clientLevelShot" ) ) { // don't do it if we aren't running the server locally, // otherwise malicious remote servers could overwrite // the existing thumbnails if ( !com_sv_running->integer ) { return qfalse; } // close the console Con_Close(); // take a special screenshot next frame Cbuf_AddText( "wait ; wait ; wait ; wait ; screenshot levelshot\n" ); return qtrue; } // we may want to put a "connect to other server" command here // cgame can now act on the command return qtrue; }
qboolean demoGetServerCommand( int cmdNumber ) { demoPlay_t *play = demo.play.handle; int index = cmdNumber % DEMO_PLAY_CMDS; const char *cmd; if (cmdNumber < play->commandCount - DEMO_PLAY_CMDS || cmdNumber > play->commandCount ) return qfalse; Cmd_TokenizeString( play->commandData + play->commandStart[index] ); cmd = Cmd_Argv( 0 ); if ( !strcmp( cmd, "cs" ) ) { CL_ConfigstringModified(); } return qtrue; }
/* =================== CL_GetServerCommand Set up argc/argv for the given command =================== */ qboolean CL_GetServerCommand( int serverCommandNumber ) { char *s; char *cmd; static char bigConfigString[BIG_INFO_STRING]; int argc; // if we have irretrievably lost a reliable command, drop the connection if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) { // when a demo record was started after the client got a whole bunch of // reliable commands then the client never got those first reliable commands if ( clc.demoplaying ) return qfalse; Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" ); return qfalse; } if ( serverCommandNumber > clc.serverCommandSequence ) { Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" ); return qfalse; } s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ]; clc.lastExecutedServerCommand = serverCommandNumber; Com_DPrintf( "serverCommand: %i : %s\n", serverCommandNumber, s ); rescan: Cmd_TokenizeString( s ); cmd = Cmd_Argv(0); argc = Cmd_Argc(); if ( !strcmp( cmd, "disconnect" ) ) { // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=552 // allow server to indicate why they were disconnected if ( argc >= 2 ) Com_Error( ERR_SERVERDISCONNECT, "Server disconnected - %s", Cmd_Argv( 1 ) ); else Com_Error( ERR_SERVERDISCONNECT, "Server disconnected\n" ); } if ( !strcmp( cmd, "bcs0" ) ) { Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2) ); return qfalse; } if ( !strcmp( cmd, "bcs1" ) ) { s = Cmd_Argv(2); if( strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING ) { Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" ); } strcat( bigConfigString, s ); return qfalse; } if ( !strcmp( cmd, "bcs2" ) ) { s = Cmd_Argv(2); if( strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING ) { Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" ); } strcat( bigConfigString, s ); strcat( bigConfigString, "\"" ); s = bigConfigString; goto rescan; } if ( !strcmp( cmd, "cs" ) ) { CL_ConfigstringModified(); // reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString() Cmd_TokenizeString( s ); return qtrue; } if ( !strcmp( cmd, "map_restart" ) ) { // clear notify lines and outgoing commands before passing // the restart to the cgame Con_ClearNotify(); Com_Memset( cl.cmds, 0, sizeof( cl.cmds ) ); return qtrue; } // the clientLevelShot command is used during development // to generate 128*128 screenshots from the intermission // point of levels for the menu system to use // we pass it along to the cgame to make apropriate adjustments, // but we also clear the console and notify lines here if ( !strcmp( cmd, "clientLevelShot" ) ) { // don't do it if we aren't running the server locally, // otherwise malicious remote servers could overwrite // the existing thumbnails if ( !com_sv_running->integer ) { return qfalse; } // close the console Con_Close(); // take a special screenshot next frame Cbuf_AddText( "wait ; wait ; wait ; wait ; screenshot levelshot\n" ); return qtrue; } // we may want to put a "connect to other server" command here // cgame can now act on the command return qtrue; }
/* =================== CL_GetServerCommand Set up argc/argv for the given command =================== */ qboolean CL_GetServerCommand( int serverCommandNumber ) { char *s; char *cmd; static char bigConfigString[BIG_INFO_STRING]; // if we have irretrievably lost a reliable command, drop the connection if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) { int i = 0; // when a demo record was started after the client got a whole bunch of // reliable commands then the client never got those first reliable commands if ( clc.demoplaying ) return qfalse; while (i < MAX_RELIABLE_COMMANDS) { //spew out the reliable command buffer if (clc.reliableCommands[i][0]) { Com_Printf("%i: %s\n", i, clc.reliableCommands[i]); } i++; } Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" ); return qfalse; } if ( serverCommandNumber > clc.serverCommandSequence ) { Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" ); return qfalse; } s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ]; clc.lastExecutedServerCommand = serverCommandNumber; Com_DPrintf( "serverCommand: %i : %s\n", serverCommandNumber, s ); rescan: Cmd_TokenizeString( s ); cmd = Cmd_Argv(0); if ( !strcmp( cmd, "disconnect" ) ) { char strEd[MAX_STRINGED_SV_STRING]; CL_CheckSVStringEdRef(strEd, Cmd_Argv(1)); Com_Error (ERR_SERVERDISCONNECT, "%s: %s\n", SE_GetString("MP_SVGAME_SERVER_DISCONNECTED"), strEd ); } if ( !strcmp( cmd, "bcs0" ) ) { Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2) ); return qfalse; } if ( !strcmp( cmd, "bcs1" ) ) { s = Cmd_Argv(2); if( strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING ) { Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" ); } strcat( bigConfigString, s ); return qfalse; } if ( !strcmp( cmd, "bcs2" ) ) { s = Cmd_Argv(2); if( strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING ) { Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" ); } strcat( bigConfigString, s ); strcat( bigConfigString, "\"" ); s = bigConfigString; goto rescan; } if ( !strcmp( cmd, "cs" ) ) { CL_ConfigstringModified(); // reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString() Cmd_TokenizeString( s ); return qtrue; } if ( !strcmp( cmd, "map_restart" ) ) { // clear notify lines and outgoing commands before passing // the restart to the cgame Con_ClearNotify(); // reparse the string, because Con_ClearNotify() may have done another Cmd_TokenizeString() Cmd_TokenizeString( s ); Com_Memset( cl.cmds, 0, sizeof( cl.cmds ) ); return qtrue; } // the clientLevelShot command is used during development // to generate 128*128 screenshots from the intermission // point of levels for the menu system to use // we pass it along to the cgame to make apropriate adjustments, // but we also clear the console and notify lines here if ( !strcmp( cmd, "clientLevelShot" ) ) { // don't do it if we aren't running the server locally, // otherwise malicious remote servers could overwrite // the existing thumbnails if ( !com_sv_running->integer ) { return qfalse; } // close the console Con_Close(); // take a special screenshot next frame Cbuf_AddText( "wait ; wait ; wait ; wait ; screenshot levelshot\n" ); return qtrue; } // we may want to put a "connect to other server" command here // cgame can now act on the command /* return qtrue; } static void CG_ServerCommand( void ) { */ char text[MAX_SAY_TEXT]; if ( !strcmp(cmd, "sxd") || //siege extended data, contains extra info certain classes may want to know about other clients !strcmp(cmd, "sb") || //siege briefing display !strcmp( cmd, "scl" ) || !strcmp( cmd, "spc" ) || !strcmp( cmd, "nfr" ) || //"nfr" == "new force rank" (want a short string) !strcmp( cmd, "kg2" ) || //Kill a ghoul2 instance in this slot. //If it has been occupied since this message was sent somehow, the worst that can (should) happen //is the instance will have to reinit with its current info. !strcmp(cmd, "kls") || //kill looping sounds !strcmp(cmd, "ircg") || //this means param 2 is the body index and we want to copy to bodyqueue on it !strcmp(cmd, "rcg") || //rcg - Restore Client Ghoul (make sure limbs are reattached and ragdoll state is reset - this must be done reliably) !strcmp(cmd, "scores") || !strcmp(cmd, "tinfo") || !strcmp(cmd, "map_restart") || !strcmp(cmd, "remapShader") || !strcmp(cmd, "loaddefered") ) { return qfalse; } if ( !strcmp( cmd, "cp" ) ) { //CL_CenterPrint( Cmd_Argv(1) ); //CON_CenterPrint(7, Cmd_Argv(1)); return qfalse; } if ( !strcmp( cmd, "cps" ) ) { char *x = (char *)Cmd_Argv(1); if (x[0] == '@') { x++; } //CL_CenterPrint( Cmd_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); //CON_Printf(Cmd_Argv(1), printf, BACKGROUND_INTENSITY); //CON_CenterPrint(7, Cmd_Argv(1)); return qfalse; } if ( !strcmp( cmd, "print" ) ) { Com_Printf( "%s", Cmd_Argv(1) ); return qfalse; } #ifndef LUA_VERSION if ( !strcmp( cmd, "chat" ) || !strcmp( cmd, "tchat" )) { time_t derp = time(NULL); struct tm *lt = localtime(&derp); Q_strncpyz( text, Cmd_Argv(1), MAX_SAY_TEXT ); CL_RemoveChatEscapeChar( text ); Com_Printf( "[^5%02i:%02i:%02i^7] %s\n", lt->tm_hour, lt->tm_min, lt->tm_sec, text ); return qfalse; } #endif //chat with location, possibly localized. if ( !strcmp( cmd, "lchat" ) || !strcmp( cmd, "ltchat" )) { char name[MAX_STRING_CHARS]; char loc[MAX_STRING_CHARS]; char color[8]; char message[MAX_STRING_CHARS]; if (Cmd_Argc() < 4) { return qtrue; } strcpy(name, Cmd_Argv(1)); strcpy(loc, Cmd_Argv(2)); strcpy(color, Cmd_Argv(3)); strcpy(message, Cmd_Argv(4)); Q_strncpyz( text, Cmd_Argv(1), MAX_SAY_TEXT ); Com_sprintf(text, MAX_SAY_TEXT, "%s<%s>^%s%s", name, loc, color, message); CL_RemoveChatEscapeChar( text ); Com_Printf( "%s\n", text ); return qfalse; } //Com_Printf( "Unknown client game command: %s\n", cmd ); return qtrue; }
/* =================== CL_GetServerCommand Set up argc/argv for the given command =================== */ qboolean CL_GetServerCommand( int serverCommandNumber ) { const char *s; char *cmd; static char bigConfigString[ BIG_INFO_STRING ]; int argc; // if we have irretrievably lost a reliable command, drop the connection if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) { // when a demo record was started after the client got a whole bunch of // reliable commands then the client never got those first reliable commands if ( clc.demoplaying ) { return qfalse; } Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" ); } if ( serverCommandNumber > clc.serverCommandSequence ) { Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" ); } s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ]; clc.lastExecutedServerCommand = serverCommandNumber; if ( cl_showServerCommands->integer ) { // NERVE - SMF Com_Printf( "serverCommand: %i : %s\n", serverCommandNumber, s ); } rescan: Cmd_TokenizeString( s ); cmd = Cmd_Argv( 0 ); argc = Cmd_Argc(); if ( !strcmp( cmd, "disconnect" ) ) { // NERVE - SMF - allow server to indicate why they were disconnected if ( argc >= 2 ) { Com_Error( ERR_SERVERDISCONNECT, "Server Disconnected – %s", Cmd_Argv( 1 ) ); } else { Com_Error( ERR_SERVERDISCONNECT, "Server disconnected" ); } } if ( !strcmp( cmd, "bcs0" ) ) { Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s %s", Cmd_Argv( 1 ), Cmd_QuoteString( Cmd_Argv( 2 ) ) ); return qfalse; } if ( !strcmp( cmd, "bcs1" ) ) { s = Cmd_QuoteString( Cmd_Argv( 2 ) ); if ( strlen( bigConfigString ) + strlen( s ) >= BIG_INFO_STRING ) { Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" ); } strcat( bigConfigString, s ); return qfalse; } if ( !strcmp( cmd, "bcs2" ) ) { s = Cmd_QuoteString( Cmd_Argv( 2 ) ); if ( strlen( bigConfigString ) + strlen( s ) + 1 >= BIG_INFO_STRING ) { Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" ); } strcat( bigConfigString, s ); strcat( bigConfigString, "\"" ); s = bigConfigString; goto rescan; } if ( !strcmp( cmd, "cs" ) ) { CL_ConfigstringModified(); // reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString() Cmd_TokenizeString( s ); return qtrue; } if ( !strcmp( cmd, "map_restart" ) ) { // clear notify lines and outgoing commands before passing // the restart to the cgame Con_ClearNotify(); memset( cl.cmds, 0, sizeof( cl.cmds ) ); return qtrue; } if ( !strcmp( cmd, "popup" ) ) { // direct server to client popup request, bypassing cgame // trap_UI_Popup(Cmd_Argv(1)); // if ( cls.state == CA_ACTIVE && !clc.demoplaying ) { // VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_CLIPBOARD); // Menus_OpenByName(Cmd_Argv(1)); // } return qfalse; } #ifdef USE_CRYPTO if ( cl_pubkeyID->integer && !strcmp( cmd, "pubkey_request" ) ) { char buffer[ MAX_STRING_CHARS ] = "pubkey "; mpz_get_str( buffer + 7, 16, public_key.n ); CL_AddReliableCommand( buffer ); return qfalse; } if ( cl_pubkeyID->integer && !strcmp( cmd, "pubkey_decrypt" ) ) { char buffer[ MAX_STRING_CHARS ] = "pubkey_identify "; unsigned int msg_len = MAX_STRING_CHARS - 16; mpz_t message; if ( argc == 1 ) { Com_Printf("%s", _( "^3Server sent a pubkey_decrypt command, but sent nothing to decrypt!\n" )); return qfalse; } mpz_init_set_str( message, Cmd_Argv( 1 ), 16 ); if ( rsa_decrypt( &private_key, &msg_len, ( unsigned char * ) buffer + 16, message ) ) { nettle_mpz_set_str_256_u( message, msg_len, ( unsigned char * ) buffer + 16 ); mpz_get_str( buffer + 16, 16, message ); CL_AddReliableCommand( buffer ); } mpz_clear( message ); return qfalse; } #endif // we may want to put a "connect to other server" command here // cgame can now act on the command return qtrue; }
/* =================== CL_HandleServerCommand CL_GetServerCommand =================== */ bool CL_HandleServerCommand(Str::StringRef text, std::string& newText) { static char bigConfigString[ BIG_INFO_STRING ]; Cmd::Args args(text); if (args.Argc() == 0) { return false; } auto cmd = args.Argv(0); int argc = args.Argc(); if (cmd == "disconnect") { // NERVE - SMF - allow server to indicate why they were disconnected if (argc >= 2) { Com_Error(errorParm_t::ERR_SERVERDISCONNECT, "Server disconnected: %s", args.Argv(1).c_str()); } else { Com_Error(errorParm_t::ERR_SERVERDISCONNECT, "Server disconnected"); } } // bcs0 to bcs2 are used by the server to send info strings that are bigger than the size of a packet. // See also SV_UpdateConfigStrings // bcs0 starts a new big config string // bcs1 continues it // bcs2 finishes it and feeds it back as a new command sent by the server (bcs0 makes it a cs command) if (cmd == "bcs0") { if (argc >= 3) { Com_sprintf(bigConfigString, BIG_INFO_STRING, "cs %s %s", args.Argv(1).c_str(), args.EscapedArgs(2).c_str()); } return false; } if (cmd == "bcs1") { if (argc >= 3) { const char* s = Cmd_QuoteString( args[2].c_str() ); if (strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING) { Com_Error(errorParm_t::ERR_DROP, "bcs exceeded BIG_INFO_STRING"); } Q_strcat(bigConfigString, sizeof(bigConfigString), s); } return false; } if (cmd == "bcs2") { if (argc >= 3) { const char* s = Cmd_QuoteString( args[2].c_str() ); if (strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING) { Com_Error(errorParm_t::ERR_DROP, "bcs exceeded BIG_INFO_STRING"); } Q_strcat(bigConfigString, sizeof(bigConfigString), s); Q_strcat(bigConfigString, sizeof(bigConfigString), "\""); newText = bigConfigString; return CL_HandleServerCommand(bigConfigString, newText); } return false; } if (cmd == "cs") { CL_ConfigstringModified(args); return true; } if (cmd == "map_restart") { // clear outgoing commands before passing // the restart to the cgame memset(cl.cmds, 0, sizeof(cl.cmds)); return true; } if (cmd == "popup") { // direct server to client popup request, bypassing cgame if (cls.state == connstate_t::CA_ACTIVE && !clc.demoplaying && argc >=1) { // TODO: Pass to the cgame } return false; } if (cmd == "pubkey_decrypt") { char buffer[ MAX_STRING_CHARS ] = "pubkey_identify "; NettleLength msg_len = MAX_STRING_CHARS - 16; mpz_t message; if (argc == 1) { Log::Notice("^3Server sent a pubkey_decrypt command, but sent nothing to decrypt!\n"); return false; } mpz_init_set_str(message, args.Argv(1).c_str(), 16); if (rsa_decrypt(&private_key, &msg_len, (unsigned char *) buffer + 16, message)) { nettle_mpz_set_str_256_u(message, msg_len, (unsigned char *) buffer + 16); mpz_get_str(buffer + 16, 16, message); CL_AddReliableCommand(buffer); } mpz_clear(message); return false; } return true; }
/* =================== CL_GetServerCommand Set up argc/argv for the given command =================== */ bool CL_GetServerCommand( int serverCommandNumber ) { const char *s; const char *cmd; static char bigConfigString[BIG_INFO_STRING]; int argc; // if we have irretrievably lost a reliable command, drop the connection if ( serverCommandNumber <= clc.serverCommandSequence - MAX_RELIABLE_COMMANDS ) { // when a demo record was started after the client got a whole bunch of // reliable commands then the client never got those first reliable commands if ( clc.demoplaying ) return false; Com_Error( ERR_DROP, "CL_GetServerCommand: a reliable command was cycled out" ); return false; } if ( serverCommandNumber > clc.serverCommandSequence ) { Com_Error( ERR_DROP, "CL_GetServerCommand: requested a command not received" ); return false; } s = clc.serverCommands[ serverCommandNumber & ( MAX_RELIABLE_COMMANDS - 1 ) ]; clc.lastExecutedServerCommand = serverCommandNumber; Com_DPrintf( "serverCommand: %i : %s\n", serverCommandNumber, s ); rescan: Cmd_TokenizeString2(s, false); cmd = Cmd_Argv(0); argc = Cmd_Argc(); if ( !strcmp( cmd, "disconnect" ) ) { // allow server to indicate why they were disconnected if ( argc >= 2 ) Com_Error( ERR_SERVERDISCONNECT, "Server disconnected - %s", Cmd_Argv( 1 ) ); else Com_Error( ERR_SERVERDISCONNECT, "Server disconnected" ); } if ( !strcmp( cmd, "bcs0" ) ) { Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2) ); return false; } if ( !strcmp( cmd, "bcs1" ) ) { s = Cmd_Argv(2); if( strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING ) Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" ); strcat( bigConfigString, s ); return false; } if ( !strcmp( cmd, "bcs2" ) ) { s = Cmd_Argv(2); if( strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING ) Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" ); strcat( bigConfigString, s ); strcat( bigConfigString, "\"" ); s = bigConfigString; goto rescan; } if ( !strcmp( cmd, "cs" ) ) { CL_ConfigstringModified(); // reparse the string, because CL_ConfigstringModified may have done // another Cmd_TokenizeString() Cmd_TokenizeString2(s, false); return true; } if ( !strcmp( cmd, "map_restart" ) ) { // clear notify lines and outgoing commands before passing // the restart to the cgame Con_ClearNotify(); // reparse the string, because Con_ClearNotify() may have done another // Cmd_TokenizeString() Cmd_TokenizeString2(s, false); ::memset( cl.cmds, 0, sizeof( cl.cmds ) ); return true; } // we may want to put a "connect to other server" command here // cgame can now act on the command return true; }