From def4ab65924e414e3e39d06fbbb85962b37493bc Mon Sep 17 00:00:00 2001 From: Samual Date: Mon, 19 Dec 2011 11:57:17 -0500 Subject: [PATCH] Many more updates regarding client verification... also make adminmsg able to send to multiple players at once --- qcsrc/common/util.qc | 9 ++++ qcsrc/server/command/common.qc | 33 +++++++------ qcsrc/server/command/sv_cmd.qc | 85 +++++++++++++++++++--------------- 3 files changed, 76 insertions(+), 51 deletions(-) diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index afcefd0d3..a609827cf 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -2128,3 +2128,12 @@ entity ReadCSQCEntity() } #endif +// escape the string to make it safe for consoles +string MakeConsoleSafe(string input) +{ + input = strreplace("\n", "", input); + input = strreplace("\\", "\\\\", input); + input = strreplace("$", "$$", input); + input = strreplace("\"", "\\\"", input); + return input; +} diff --git a/qcsrc/server/command/common.qc b/qcsrc/server/command/common.qc index 95c9ceb52..affad72a6 100644 --- a/qcsrc/server/command/common.qc +++ b/qcsrc/server/command/common.qc @@ -1,8 +1,9 @@ // ==================================================== // Shared code for server commands, written by Samual -// Last updated: December 17th, 2011 +// Last updated: December 19th, 2011 // ==================================================== +// select the proper prefix for usage and other messages string GetCommandPrefix(entity caller) { if(caller) @@ -11,14 +12,29 @@ string GetCommandPrefix(entity caller) return "sv_cmd"; } +// if client return player nickname, or if server return admin nickname string GetCallerName(entity caller) { if(caller) return caller.netname; else - return ((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname); + return admin_name(); //((autocvar_sv_adminnick != "") ? autocvar_sv_adminnick : autocvar_hostname); } +// verify that the client provided is acceptable for use +float VerifyClientEntity(entity client, float must_be_real, float allow_bots) +{ + if not(client.flags & FL_CLIENT) + return CLIENT_DOESNT_EXIST; + else if(must_be_real && (clienttype(client) != CLIENTTYPE_REAL)) + return CLIENT_NOT_REAL; + else if(!allow_bots && (clienttype(client) == CLIENTTYPE_BOT)) + return CLIENT_IS_BOT; + + return CLIENT_ACCEPTABLE; +} + +// if the client is not acceptable, return a string to be used for error messages string GetClientErrorString(float clienterror, string original_input) { switch(clienterror) @@ -30,6 +46,7 @@ string GetClientErrorString(float clienterror, string original_input) } } +// is this entity number even in the possible range of entities? float VerifyClientNumber(float tmp_number) { if((tmp_number < 1) || (tmp_number > maxclients)) @@ -38,18 +55,6 @@ float VerifyClientNumber(float tmp_number) return TRUE; } -float VerifyClientEntity(entity client, float must_be_real, float allow_bots) -{ - if not(client.flags & FL_CLIENT) - return CLIENT_DOESNT_EXIST; - else if(must_be_real && (clienttype(client) != CLIENTTYPE_REAL)) - return CLIENT_NOT_REAL; - else if(!allow_bots && (clienttype(client) == CLIENTTYPE_BOT)) - return CLIENT_IS_BOT; - - return CLIENT_ACCEPTABLE; -} - // find a player which matches the input string, and return their entity entity GetFilteredEntity(string input) { diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc index 480372cab..e0549d7c9 100644 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@ -94,48 +94,59 @@ void modelbug() // Command Sub-Functions // ======================= -void GameCommand_adminmsg(float request, float argc) // todo: re-write this, plus support multiple clients at once like moveplayer +void GameCommand_adminmsg(float request, float argc) { switch(request) { case CMD_REQUEST_COMMAND: { entity client; - float entno = stof(argv(1)); - float n, i; - string s; + float accepted; - if(argc >= 3 && argc <= 4) { - if((entno < 0) | (entno > maxclients)) { - print("Player ", argv(1), " doesn't exist\n"); - return; - } - n = 0; - for(i = (entno ? entno : 1); i <= (entno ? entno : maxclients); ++i) + string targets = strreplace(",", " ", argv(1)); + string original_targets = strreplace(" ", ", ", targets); + string admin_message = argv(2); + float infobartime = stof(argv(3)); + + string successful, t; + + if((targets) && (admin_message)) + { + for(;targets;) { - client = edict_num(i); - if(client.flags & FL_CLIENT) + t = car(targets); targets = cdr(targets); + + // Check to see if the player is a valid target + client = GetFilteredEntity(t); + accepted = VerifyClientEntity(client, TRUE, FALSE); + + if not(accepted) { - if(argc == 4) - { - // make the string console safe - s = argv(2); - s = strreplace("\n", "", s); - s = strreplace("\\", "\\\\", s); - s = strreplace("$", "$$", s); - s = strreplace("\"", "\\\"", s); - stuffcmd(client, sprintf("\ninfobar %f \"%s\"\n", stof(argv(3)), s)); - } - else - { - centerprint(client, strcat("^3", admin_name(), ":\n^7", argv(2))); - sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: ", argv(2), "\n")); - } - dprint("Message sent to ", client.netname, "\n"); - ++n; + print("adminmsg: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n")); + continue; } + + // send the centerprint/console print or infomessage + if(infobartime) + { + stuffcmd(client, sprintf("\ninfobar %f \"%s\"\n", infobartime, MakeConsoleSafe(admin_message))); + } + else + { + centerprint(client, strcat("^3", admin_name(), ":\n^7", admin_message)); + sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: ", admin_message, "\n")); + } + + successful = strcat(successful, (successful ? ", " : ""), client.netname); + dprint("Message sent to ", client.netname, "\n"); + continue; } - if(!n) { print(strcat("Client (", argv(1) ,") not found.\n")); } + + if(successful) + bprint("Successfully sent message '", admin_message, "' to ", successful, ".\n"); + else + print("No players given (", original_targets, ") could recieve the message.\n"); + return; } } @@ -144,12 +155,12 @@ void GameCommand_adminmsg(float request, float argc) // todo: re-write this, plu print("Incorrect parameters for ^2adminmsg^7\n"); case CMD_REQUEST_USAGE: { - print("\nUsage:^3 sv_cmd adminmsg client \"message\" [infobartime]\n"); - print(" 'client' is the entity number or name of the player to send the message to.\n"); + print("\nUsage:^3 sv_cmd adminmsg clients \"message\" [infobartime]\n"); + print(" 'clients' is a list (separated by commas) of player entity ID's or nicknames\n"); print(" If infobartime is provided, the message will be sent to infobar.\n"); print(" Otherwise, it will just be sent as a centerprint message.\n"); - print("Examples: adminmsg 4 \"this infomessage will last for ten seconds\" 10\n"); - print(" adminmsg 2 \"this message will be a centerprint\"\n"); + print("Examples: adminmsg 2,4 \"this infomessage will last for ten seconds\" 10\n"); + print(" adminmsg 2,5 \"this message will be a centerprint\"\n"); return; } } @@ -949,11 +960,11 @@ void GameCommand_moveplayer(float request, float argc) // Check to see if the player is a valid target client = GetFilteredEntity(t); - accepted = VerifyClientEntity(client, TRUE, FALSE); + accepted = VerifyClientEntity(client, FALSE, TRUE); if not(accepted) { - print("moveplayer: ", GetClientErrorString(accepted, argv(1)), ", skipping to next player.\n"); + print("moveplayer: ", GetClientErrorString(accepted, t), (targets ? ", skipping to next player.\n" : ".\n")); continue; } -- 2.39.2