From 9a94312431f63fd4dabe7788c6cc57f6fd092197 Mon Sep 17 00:00:00 2001 From: "baloh.matevz@gmail.com" Date: Fri, 22 Jun 2012 05:54:43 +0000 Subject: [PATCH] - Added spam-prevention code. If someone sends the same message 5 times in a row, they will get the message "You are nearing the spam filter limit for identical messages." If they continue to send the same message (if they send it 10 times in total) they will get an auto-mute for the channel they are sending it through. The number of identical messages which triggers a warning and automute can be configured in setup.dm - Added channel-specific admin muting. Admins can now mute someone from IC (say, me and whisper), OOC, PRAY, ADMINHELP (adminhelp, admin pm and asay) and DEADCHAT (say while dead and dsay) - Added a (?) to adminhelps and prayers which displays the same quick overview that all the other (?)-s show, but for the person adminhelping or praying. git-svn-id: http://tgstation13.googlecode.com/svn/trunk@3888 316c924e-a436-60f5-8080-3fe189b3f50e --- code/game/verbs/ooc.dm | 10 ++- code/modules/admin/admin.dm | 50 +++++------- code/modules/admin/verbs/adminhelp.dm | 11 ++- code/modules/admin/verbs/adminpm.dm | 7 +- code/modules/admin/verbs/adminsay.dm | 7 +- code/modules/admin/verbs/deadsay.dm | 6 +- code/modules/admin/verbs/pray.dm | 10 ++- code/modules/admin/verbs/randomverbs.dm | 76 +++++++++++++++---- code/modules/client/client defines.dm | 12 ++- code/modules/client/client procs.dm | 14 ++++ code/modules/mob/dead/observer/say.dm | 10 ++- code/modules/mob/living/carbon/human/emote.dm | 9 ++- .../mob/living/carbon/human/whisper.dm | 11 ++- code/modules/mob/living/say.dm | 9 ++- .../modules/mob/living/silicon/robot/emote.dm | 9 ++- code/modules/mob/living/silicon/say.dm | 9 ++- code/setup.dm | 11 +++ 17 files changed, 193 insertions(+), 78 deletions(-) diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm index b6c1c00339c..984e8418a60 100644 --- a/code/game/verbs/ooc.dm +++ b/code/game/verbs/ooc.dm @@ -27,9 +27,13 @@ else if (!dooc_allowed && !src.client.holder && (src.client.deadchat != 0)) usr << "\red OOC for dead mobs has been turned off." return - else if (src.client && (src.client.muted || src.client.muted_complete)) - src << "You are muted." - return + else if (src.client) + if(src.client.muted_ooc) + src << "\red You cannot use OOC (muted by admins)." + return + + if (src.client.handle_spam_prevention(msg,MUTE_OOC)) + return else if (findtext(msg, "byond://") && !src.client.holder) src << "Advertising other servers is not allowed." log_admin("[key_name(src)] has attempted to advertise in OOC: [msg]") diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index f81c58ffb7e..7c86e0ac061 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -752,34 +752,23 @@ var/global/BSACooldown = 0 message_admins("\blue [key_name_admin(usr)] removed [t] from the goonlist.") remove_goon(t) */ - if (href_list["mute2"]) - if ((src.rank in list( "Moderator", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) - var/mob/M = locate(href_list["mute2"]) + if (href_list["mute"]) + if ((src.rank in list( "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) + var/mob/M = locate(href_list["mute"]) + var/mute_type = href_list["mute_type"] + if(istext(mute_type)) + mute_type = text2num(mute_type) + if(!isnum(mute_type)) + return if (ismob(M)) - if ((M.client && M.client.holder && (M.client.holder.level >= src.level))) - alert("You cannot perform this action. You must be of a higher administrative rank!", null, null, null, null, null) - return if(!M.client) src << "This mob doesn't have a client tied to it." return - M.client.muted = !M.client.muted - log_admin("[key_name(usr)] has [(M.client.muted ? "muted" : "voiced")] [key_name(M)].") - message_admins("\blue [key_name_admin(usr)] has [(M.client.muted ? "muted" : "voiced")] [key_name_admin(M)].", 1) - M << "You have been [(M.client.muted ? "muted" : "voiced")]. Please resolve this in adminhelp." - if (href_list["mute_complete"]) - if ((src.rank in list( "Moderator", "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) - var/mob/M = locate(href_list["mute_complete"]) - if (ismob(M)) if ((M.client && M.client.holder && (M.client.holder.level >= src.level))) alert("You cannot perform this action. You must be of a higher administrative rank!", null, null, null, null, null) return - if(!M.client) - src << "This mob doesn't have a client tied to it." - return - M.client.muted_complete = !M.client.muted_complete - log_admin("[key_name(usr)] has [(M.client.muted_complete ? "completely muted" : "voiced (complete)")] [key_name(M)].") - message_admins("\blue [key_name_admin(usr)] has [(M.client.muted_complete ? "completely muted" : "voiced (complete)")] [key_name_admin(M)].", 1) - M << "You have been [(M.client.muted_complete ? "completely muted" : "voiced (complete)")]. You are unable to speak or even adminhelp" + + cmd_admin_mute(M, mute_type) if (href_list["c_mode"]) if ((src.rank in list( "Temporary Admin", "Admin Candidate", "Trial Admin", "Badmin", "Game Admin", "Game Master" ))) @@ -1234,6 +1223,10 @@ var/global/BSACooldown = 0 if (href_list["adminmoreinfo"]) var/mob/M = locate(href_list["adminmoreinfo"]) + if(!M) + usr << "\blue The mob no longer exists." + return + if(src && src.owner) var/location_description = "" var/special_role_description = "" @@ -2279,14 +2272,13 @@ var/global/BSACooldown = 0 if(M.client) body += "| Prison | " - body += "Mute: " - if(M.client.muted_complete) - body += "Completely Muted: (Allow adminhelp)" - else - if(M.client.muted) - body += "Soft Mute: (Unmute) (Mute adminhelps)" - else - body += "Voiced: (Mute)" + body += "
Mute: " + body += "\[IC | " + body += "OOC | " + body += "PRAY | " + body += "ADMINHELP | " + body += "DEADCHAT\]" + body += "(toggle all)" body += "

" body += "Jump to | " diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 0fbe6e98981..ef915f3698a 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -1,14 +1,17 @@ //This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE! -var/list/adminhelp_ignored_words = list("unknown","the","a","an", "monkey", "alien") +var/list/adminhelp_ignored_words = list("unknown","the","a","an", "monkey", "alien", "as") /client/verb/adminhelp(msg as text) set category = "Admin" set name = "Adminhelp" - if (muted_complete) - src << "Error: Admin-PM: You are completely muted." + if (muted_adminhelp) + src << "Error: Admin-PM: You cannot send adminhelps (Muted by admins)." + return + + if (src.handle_spam_prevention(msg,MUTE_ADMINHELP)) return if(!msg) return @@ -80,7 +83,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an", "monkey", "ali if (X.holder) if(X.sound_adminhelp) X << 'adminhelp.ogg' - var/msg_to_send = "\blue HELP: [key_name(src, X)] (PP) (VV) (SM) (JMP) (CA): [msg]" + var/msg_to_send = "\blue HELP: [key_name(src, X)] (?) (PP) (VV) (SM) (JMP) (CA): [msg]" msg_to_send = dd_replaceText(msg_to_send, "HOLDERREF", "\ref[X.holder]") msg_to_send = dd_replaceText(msg_to_send, "ADMINREF", "\ref[X]") X << msg_to_send diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 8411ad31577..3894a31bed2 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -36,8 +36,11 @@ //takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM. //Fetching a message if needed. src is the sender and C is the target client /client/proc/cmd_admin_pm(var/client/C, var/msg) - if(src.muted_complete) - src << "Error: Admin-PM: You are completely muted." + if(src.muted_adminhelp) + src << "Error: Admin-PM: You are unable to use admin PM-s (muted by admins)." + return + + if (src.handle_spam_prevention(msg,MUTE_ADMINHELP)) return if( !C || !istype(C,/client) ) diff --git a/code/modules/admin/verbs/adminsay.dm b/code/modules/admin/verbs/adminsay.dm index 40f4ee1a588..f82d6ef0456 100644 --- a/code/modules/admin/verbs/adminsay.dm +++ b/code/modules/admin/verbs/adminsay.dm @@ -7,8 +7,11 @@ src << "Only administrators may use this command." return - if (src.muted || src.muted_complete) - src << "You are muted." + if (src.muted_adminhelp) + src << "You cannot send ASAY messages (muted by admins)." + return + + if (src.handle_spam_prevention(msg,MUTE_ADMINHELP)) return msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN) diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index 4ef4d3e72c7..9e4d5dc876a 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -7,7 +7,11 @@ return if(!src.mob) return - if(src.muted || src.muted_complete) + if(src.muted_deadchat) + src << "\red You cannot send DSAY messages (muted by admins)." + return + + if (src.handle_spam_prevention(msg,MUTE_DEADCHAT)) return msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN) diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index f6f9cfa87dd..68d02a9afd6 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -7,14 +7,18 @@ if (!msg) return - if (usr.client && (usr.client.muted || usr.client.muted_complete)) - return + if (usr.client) + if(usr.client.muted_pray) + return + + if (src.client.handle_spam_prevention(msg,MUTE_PRAY)) + return var/icon/cross = icon('storage.dmi',"bible") for (var/mob/M in world) if (M.client && M.client.holder && M.client.seeprayers) - M << "\blue \icon[cross] PRAY: [key_name(src, M)] (PP) (VV) (SM) (JMP) (CA) (SC): [msg]" + M << "\blue \icon[cross] PRAY: [key_name(src, M)] (?) (PP) (VV) (SM) (JMP) (CA) (SC): [msg]" usr << "Your prayers have been received by the gods." feedback_add_details("admin_verb","PR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 7aa60025c2d..dff13da6bc8 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -123,25 +123,73 @@ message_admins("[key_name_admin(usr)] has toggled [key_name_admin(M)]'s nodamage to [(M.nodamage ? "On" : "Off")]", 1) feedback_add_details("admin_verb","GOD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/cmd_admin_mute(mob/M as mob in world) - set category = "Special Verbs" - set name = "Admin Mute" - if(!holder) - src << "Only administrators may use this command." - return - if (M.client && M.client.holder && (M.client.holder.level >= holder.level)) - alert("You cannot perform this action. You must be of a higher administrative rank!", null, null, null, null, null) - return +proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0) + if(!automute) + if(usr && usr.client) + if(!usr.client.holder) + src << "Only administrators may use this command." + return + if (M.client && M.client.holder && (M.client.holder.level >= usr.client.holder.level)) + alert("You cannot perform this action. You must be of a higher administrative rank!", null, null, null, null, null) + return if(!M.client) src << "This mob doesn't have a client tied to it." return - M.client.muted = !M.client.muted - log_admin("[key_name(src)] has [(M.client.muted ? "muted" : "voiced")] [key_name(M)].") - message_admins("[key_name_admin(src)] has [(M.client.muted ? "muted" : "voiced")] [key_name_admin(M)].", 1) + var/muteunmute = 0 //0 = unmuted; 1 = muted + var/mute_string = "unknown" - M << "You have been [(M.client.muted ? "muted" : "voiced")]." - feedback_add_details("admin_verb","MUTE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + //The '| automute' thing ensures that if an automute is being applied by code, it always mutes to prevent any potential for automute to unmute someone who was muted. + switch(mute_type) + if(MUTE_IC) + M.client.muted_ic = !M.client.muted_ic | automute + muteunmute = M.client.muted_ic + mute_string = "IC (say and emote)" + if(MUTE_OOC) + M.client.muted_ooc = !M.client.muted_ooc | automute + muteunmute = M.client.muted_ooc + mute_string = "OOC" + if(MUTE_PRAY) + M.client.muted_pray = !M.client.muted_pray | automute + muteunmute = M.client.muted_pray + mute_string = "pray" + if(MUTE_ADMINHELP) + M.client.muted_adminhelp = !M.client.muted_adminhelp | automute + muteunmute = M.client.muted_adminhelp + mute_string = "adminhelp, admin PM and ASAY" + if(MUTE_DEADCHAT) + M.client.muted_deadchat = !M.client.muted_deadchat | automute + muteunmute = M.client.muted_deadchat + mute_string = "deadchat and DSAY" + if(MUTE_ALL) + mute_string = "everything" + if( M.client.muted_ic ) + M.client.muted_ic = 1 + M.client.muted_ooc = 1 + M.client.muted_pray = 1 + M.client.muted_adminhelp = 1 + M.client.muted_deadchat = 1 + muteunmute = 1 + else + M.client.muted_ic = 0 + M.client.muted_ooc = 0 + M.client.muted_pray = 0 + M.client.muted_adminhelp = 0 + M.client.muted_deadchat = 0 + muteunmute = 0 + + if(!automute) + log_admin("[key_name(usr)] has [(muteunmute ? "muted" : "voiced")] [key_name(M)] from [mute_string]") + message_admins("[key_name_admin(usr)] has [(muteunmute ? "muted" : "voiced")] [key_name_admin(M)] from [mute_string].", 1) + + M << "You have been [(muteunmute ? "muted" : "voiced")] from [mute_string] by [(usr.client.stealth)?"an admin":"[usr.client]"]." + feedback_add_details("admin_verb","MUTE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + else + log_admin("SPAM AUTOMUTE: [(muteunmute ? "muted" : "voiced")] [key_name(M)] from [mute_string]") + message_admins("SPAM AUTOMUTE: [(muteunmute ? "muted" : "voiced")] [key_name_admin(M)] from [mute_string].", 1) + + M << "You have been [(muteunmute ? "muted" : "voiced")] from [mute_string] by the SPAM AUTOMUTE system. Contact an admin." + feedback_add_details("admin_verb","AUTOMUTE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_add_random_ai_law() diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 07f851d6580..f267a6bd766 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -9,8 +9,16 @@ var/fakekey = null var/seeprayers = 0 var/ooccolor = "#b82e00" - var/muted = null //Can't talk in OOC, say, whisper, emote... anything except for adminhelp and admin-pm. An admin punishment - var/muted_complete = null //Can't talk in any way shape or form (muted + can't adminhelp or respond to admin pm-s). An admin punishment + + var/muted_ic //can't use 'say' while alive or emotes. + var/muted_ooc //can't speak in ooc + var/muted_deadchat //can't use 'say' while dead or DSAY + var/muted_pray //can't send prayers + var/muted_adminhelp //can't send adminhelps, PM-s or use ASAY + + var/last_message = "" //Contains the last message sent by this client - used to protect against copy-paste spamming. + var/last_message_count = 0 //contins a number of how many times a message identical to last_message was sent. + var/warned = 0 var/sound_adminhelp = 0 //If set to 1 this will play a sound when adminhelps are received. diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index ec367a706fc..90d1c2b6bd4 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -52,6 +52,20 @@ ..() //redirect to [locate(hsrc)]/Topic() +/client/proc/handle_spam_prevention(var/message, var/mute_type) + if(src.last_message == message) + src.last_message_count++ + if(src.last_message_count >= SPAM_TRIGGER_AUTOMUTE) + src << "\red You have exceeded the spam filter limit for identical messages. An auto-mute was applied." + cmd_admin_mute(src.mob, mute_type, 1) + return 1 + if(src.last_message_count >= SPAM_TRIGGER_WARNING) + src << "\red You are nearing the spam filter limit for identical messages." + return 0 + else + last_message = message + src.last_message_count = 0 + return 0 //This stops files larger than UPLOAD_LIMIT being sent from client to server via input(), client.Import() etc. /client/AllowUpload(filename, filelength) diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm index 9c015e7e880..4a39d8f0fb5 100644 --- a/code/modules/mob/dead/observer/say.dm +++ b/code/modules/mob/dead/observer/say.dm @@ -9,9 +9,13 @@ log_say("Ghost/[src.key] : [message]") - if (src.client && (src.client.muted || src.client.muted_complete)) - src << "You are muted." - return + if (src.client) + if(src.client.muted_deadchat) + src << "\red You cannot talk in deadchat (muted by admins)." + return + + if (src.client.handle_spam_prevention(message,MUTE_DEADCHAT)) + return . = src.say_dead(message) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 1da2e94e0f0..194f609a780 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -65,9 +65,12 @@ if ("me") if(silent) return - if (src.client && (client.muted || client.muted_complete)) - src << "You are muted." - return + if (src.client) + if (client.muted_ic) + src << "\red You cannot send IC messages (muted by admins)." + return + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return if (stat) return if(!(message)) diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm index 3de25582982..0c79f8e1af3 100644 --- a/code/modules/mob/living/carbon/human/whisper.dm +++ b/code/modules/mob/living/carbon/human/whisper.dm @@ -10,9 +10,14 @@ log_whisper("[src.name]/[src.key] : [message]") - if (src.client && (src.client.muted || src.client.muted_complete)) - src << "You are muted." - return + if (src.client) + if (src.client.muted_ic) + src << "\red You cannot whisper (muted by admins)." + return + + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return + if (src.stat == 2) return src.say_dead(message) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 42dbffffd4c..fac157c90df 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -92,9 +92,12 @@ var/list/department_radio_keys = list( if (silent) return - if (src.client && (client.muted || src.client.muted_complete)) - src << "You are muted." - return + if (src.client) + if(client.muted_ic) + src << "\red You cannot speak in IC (muted by admins)." + return + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return // stat == 2 is handled above, so this stops transmission of uncontious messages if (stat) diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm index 89571eff031..db694473ff9 100644 --- a/code/modules/mob/living/silicon/robot/emote.dm +++ b/code/modules/mob/living/silicon/robot/emote.dm @@ -70,9 +70,12 @@ if ("me") if(silent) return - if (src.client && (client.muted || client.muted_complete)) - src << "You are muted." - return + if (src.client) + if(client.muted_ic) + src << "You cannot send IC messages (muted by admins)." + return + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return if (stat) return if(!(message)) diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 069cb12d227..96369dc814d 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -2,9 +2,12 @@ if (!message) return - if (src.client && (client.muted || src.client.muted_complete)) - src << "You are muted." - return + if (src.client) + if(client.muted_ic) + src << "You cannot send IC messages (muted by admins)." + return + if (src.client.handle_spam_prevention(message,MUTE_IC)) + return if (stat == 2) message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) diff --git a/code/setup.dm b/code/setup.dm index 889878a2ad0..9dfa29e1947 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -361,3 +361,14 @@ var/list/liftable_structures = list(\ /obj/structure/filingcabinet, \ /obj/structure/reagent_dispensers, \ /obj/machinery/portable_atmospherics/canister) + +//A set of constants used to determine which type of mute an admin wishes to apply: +#define MUTE_IC 1 +#define MUTE_OOC 2 +#define MUTE_PRAY 3 +#define MUTE_ADMINHELP 4 +#define MUTE_DEADCHAT 5 +#define MUTE_ALL 6 + +#define SPAM_TRIGGER_WARNING 5 +#define SPAM_TRIGGER_AUTOMUTE 10 \ No newline at end of file