Files
Bubberstation/code/modules/admin/verbs/adminpm.dm
Jordan Brown 916d1b4cd7 TGS3 DM changes (#26534)
* TGS3

* Fix line endings

* Enable 16-bit long topics

* Cleans up topic socket usage

* Reduces and refines the IRC status throttle

* Increase the CP status delay to a reasonable amount

* Fixes the testmerge command not having a keyword

* Clean up rebooting a bit

* Get error codes from windows when symlinking fails

* Clean up world announces

* Aborting compilation will kill the DD process

* Add support for changing the project name

* Removes the log page

* Add support for compile cancellation

* Version bumps and docs

* Add merge-pr repo CL command

* Fixes DM cancel command's help message

* Refactor command line to show better formatted help text

* Corrects a typo

* Multi-key game options must be manually edited

* Moving of the server installation from the control panel

* Fix a bug with server moving

* Corrects webclient disposal syntax

* Service now handles the PR Json the game uses properly

* PR listing command for CL

* Fixes reversed testmerge and update help entries

* Windows scheduling to help avoid reboot crashes

* Generalization of chat infastructure

* Brings a file name in line with everything else

* Shutdown exceptions no longer keep the service online

* Enable provider switching on the backend. More thread safety

* Support for switching, password encryption and defaults.

* Removes boilerplate on log writing

* Discord integration

* Update the installer dependencies

* Version bump

* Adds support for getting the latest byond version

* Fixes issue with not being able to set discord channels

* Fix being able to reconnect if chat is disabled

* Extra validation for interface types

* Add the Chat page for the control panel

* Various cleanup

* Set read ACL on the data directory

* Remove redundant namespace usage

* Fixes some buttons not updating the server page

* Future proof against upcoming removal of repo data directory

* Normalize Main declaration

* Update the IRC library

* Enables CTCP

* Removes useless hack

* Logging + enable IRC private messages

* Jobs config

* And finally the maps config

* Save the last config panel visited

* Not gonna use these

* Minor formatting cleanup

* Fixes the chat page not refereshing after clicking reconnect

* Fixes server page not initializing correctly

* Repo now defaults to tgstation github when not found

* Revert "Set read ACL on the data directory"

This reverts commit 15b0021ec51532bca14690a884caa81e811fbc46.

* Design the admin config page

* Prep format the repo's admin_ranks.txt

* Add a negative permissions field

* IRC now RFC quits before disconnecting

* Turns out that fixed the disconnect lag

* Updates the admin ranks config api to work for us

* Done with this config shit

* @optimumtact

* Fix this

* Fix the .wxs

* Try to get md5/sha1 working.

* Add FCIV to appveyor

* Generalize the command class

* Revert "Generalize the command class"

This reverts commit 5c61f6df58d66f0fea4170c8aee0cd5beaa99b5d.

* ITS THE FUCKING SEX NUMBER!!!!

* Final touches

* No THESE are the final touches

* Do not advertise

* Revert "Do not advertise"

This reverts commit f64281d486f9ca27e39f19635ab4deacb2d7e1ac.

* Hopefully the last version bump for long time

* Fix line endings

* Fix default dbconfig.txt

* Fix Discord not checking the right admin channel

* Fix discord listening on ALL channels instead of configured ones

* Package the discord fixes for @JamieH

* Format the testmerge data a little better

* Apply 7 character clamping of commit strings

* Fold admin hard reboot into regular reboot list

* Backward ahelp compatibility with the adminbus bot

* Removes an unecessary semicolon

* Fix stray merge conflict in the config

* Fix Newtonsoft being included by the commandline

* Improve byond update logging

* Chat cleanup

* Fixes some setup non-errors from being displayed

* Repository no longer counts being busy as being valid

* Repository no longer valid while cloning

* Fixes a nudge socket change issue

* Frontend cleanup

* Fixes CanStart race condition

* Fixes compile cancel delays

* Various fixes

* More fixes

* Better readme

* More readme

* Fix a config command description

* Add missing repo status command

* Never delete the backups

* Log the compiles

* More logging

* Stuff

* A thing happened, but I'm not sure what

* Tiny

* INB4 second squash

* Version bump

* Shallow clones should speed things up

* Regular clones

* This is how it's set on travis

* Fix this dupe

* Add backup tag support to backend and command line

* Add some missing repo commands, fix GetHead. Fix reset on branches

* Remove the interfaces for commit and push

* Remove that generate changelog checkbox

* Yeah, that's a misunderstanding

* Make changelog pushing a config, with no way to enable for now

* Add Reset and Recompile option

* Update readme

* Repo page cleanup

* Fixed NudgePort message possible repeating
Fixed Reset and Recompile option always being visible

* Fixed compilation copy not overwriting files
Fixed compiler trying to unecessarily delete the whole A/B folder
Improved game folder initialization speed

* Selectively stage the html folder

* Make the restriction a config

* Switch to using LibGit2Sharp+SSH

* WIP SSH support

* Removes some success chat messages

* Make repo authentication purely file based

* Quick IRC fix

* Should all work in theory...

* More fine grained

* Remove the username thing

* Use the right default email for tgstation-server

* Update the readme

* That's worthy of a version bump

* Speling

* Makes it do as the readme says

* Fix testmerge list not having a scrollbar

* Trying out commit message based deployment [TGSDeploy]

* Whoops

* Testing

* Better

* Version Bump [TGSDeploy]

* Need to set the var at parent scope [TGSDeploy]

* Use the commit message

* Try this [TGSDeploy]

* Try just this

* This maybe? [TGSDeploy]

* >like [TGSDeploy]

* Wildcard, bitches [TGSDeploy]

* Saner title [TGSDeploy]

* Readme update

* This should loin ya

* Fix it [TGSDeploy]

* Readme, cleanup, and doc updates

* Improve DD crash handling

* Version bump [TGSDeploy]

* TGS3 Config Changes

* Line endings

* Map config code change

* Missed a few

* Security and Visibility selectors for the Server page

* Fixes OCD

* Fax it

* Fixes

* Version bump [TGSDeploy]

* eh

* The word comment has lost it's meaning to me

* This is a terrible name but whatever

* Support config changes

* This is part of the code so it belongs with the code

* ExportService now has a return value

* Copying of the logs dir during compile for #27674

* Version bump [TGSDeploy]

* Removes some uneedful

* Moves daemon config to BYOND folder, much safer

* Fix a config comment translation miss

* Fix project settings issue

* Fix config apply button not showing up after repo clone

* Fix anchoring for Backup Tags: label

* Version Bump [TGSDeploy]

* Nudge port only listens while server is running

* Fix some instances of the control panel crashing when the service stops

* Add start menu shortcuts

* Remove the actual server

* Remove appveyor

* Fix gitignore

* And this

* Readd HTTPS_Get for now

* Readd legacy support

* Fix

* Fix this stuff

* Last thing

* Line endings

* Final touches

* Dat newline

* More stuff

* Where'd that go?

* Real final touches
2017-06-01 21:16:07 +02:00

295 lines
11 KiB
Plaintext

#define IRCREPLYCOUNT 2
//allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm
/client/proc/cmd_admin_pm_context(mob/M in GLOB.mob_list)
set category = null
set name = "Admin PM Mob"
if(!holder)
to_chat(src, "<font color='red'>Error: Admin-PM-Context: Only administrators may use this command.</font>")
return
if( !ismob(M) || !M.client )
return
cmd_admin_pm(M.client,null)
SSblackbox.add_details("admin_verb","Admin PM Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//shows a list of clients we could send PMs to, then forwards our choice to cmd_admin_pm
/client/proc/cmd_admin_pm_panel()
set category = "Admin"
set name = "Admin PM"
if(!holder)
to_chat(src, "<font color='red'>Error: Admin-PM-Panel: Only administrators may use this command.</font>")
return
var/list/client/targets[0]
for(var/client/T)
if(T.mob)
if(isnewplayer(T.mob))
targets["(New Player) - [T]"] = T
else if(isobserver(T.mob))
targets["[T.mob.name](Ghost) - [T]"] = T
else
targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T
else
targets["(No Mob) - [T]"] = T
var/target = input(src,"To whom shall we send a message?","Admin PM",null) as null|anything in sortList(targets)
cmd_admin_pm(targets[target],null)
SSblackbox.add_details("admin_verb","Admin PM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_ahelp_reply(whom)
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<font color='red'>Error: Admin-PM: You are unable to use admin PM-s (muted).</font>")
return
var/client/C
if(istext(whom))
if(cmptext(copytext(whom,1,2),"@"))
whom = findStealthKey(whom)
C = GLOB.directory[whom]
else if(istype(whom,/client))
C = whom
if(!C)
if(holder)
to_chat(src, "<font color='red'>Error: Admin-PM: Client not found.</font>")
return
var/datum/admin_help/AH = C.current_ticket
if(AH)
message_admins("[key_name_admin(src)] has started replying to [key_name(C, 0, 0)]'s admin help.")
var/msg = input(src,"Message:", "Private message to [key_name(C, 0, 0)]") as text|null
if (!msg)
message_admins("[key_name_admin(src)] has cancelled their reply to [key_name(C, 0, 0)]'s admin help.")
return
cmd_admin_pm(whom, msg)
//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(whom, msg)
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<font color='red'>Error: Admin-PM: You are unable to use admin PM-s (muted).</font>")
return
if(!holder && !current_ticket) //no ticket? https://www.youtube.com/watch?v=iHSPf6x1Fdo
to_chat(src, "<font color='red'>You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.</font>")
to_chat(src, "<font color='blue'>Message: [msg]</font>")
return
var/client/recipient
var/irc = 0
if(istext(whom))
if(cmptext(copytext(whom,1,2),"@"))
whom = findStealthKey(whom)
if(whom == "IRCKEY")
irc = 1
else
recipient = GLOB.directory[whom]
else if(istype(whom,/client))
recipient = whom
if(irc)
if(!ircreplyamount) //to prevent people from spamming irc
return
if(!msg)
msg = input(src,"Message:", "Private message to Administrator") as text|null
if(!msg)
return
if(holder)
to_chat(src, "<font color='red'>Error: Use the admin IRC channel, nerd.</font>")
return
else
if(!recipient)
if(holder)
to_chat(src, "<font color='red'>Error: Admin-PM: Client not found.</font>")
to_chat(src, msg)
else
current_ticket.MessageNoRecipient(msg)
return
//get message text, limit it's length.and clean/escape html
if(!msg)
msg = input(src,"Message:", "Private message to [key_name(recipient, 0, 0)]") as text|null
if(!msg)
return
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<font color='red'>Error: Admin-PM: You are unable to use admin PM-s (muted).</font>")
return
if(!recipient)
if(holder)
to_chat(src, "<font color='red'>Error: Admin-PM: Client not found.</font>")
else
current_ticket.MessageNoRecipient(msg)
return
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
return
//clean the message if it's not sent by a high-rank admin
if(!check_rights(R_SERVER|R_DEBUG,0)||irc)//no sending html to the poor bots
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg)
return
var/rawmsg = msg
if(holder)
msg = emoji_parse(msg)
var/keywordparsedmsg = keywords_lookup(msg)
if(irc)
to_chat(src, "<font color='blue'>PM to-<b>Admins</b>: [rawmsg]</font>")
var/datum/admin_help/AH = admin_ticket_log(src, "<font color='red'>Reply PM from-<b>[key_name(src, TRUE, TRUE)] to <i>IRC</i>: [keywordparsedmsg]</font>")
ircreplyamount--
send2irc("[AH ? "#[AH.id] " : ""]Reply: [ckey]", rawmsg)
else
if(recipient.holder)
if(holder) //both are admins
to_chat(recipient, "<font color='red'>Admin PM from-<b>[key_name(src, recipient, 1)]</b>: [keywordparsedmsg]</font>")
to_chat(src, "<font color='blue'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: [keywordparsedmsg]</font>")
//omg this is dumb, just fill in both their tickets
var/interaction_message = "<font color='purple'>PM from-<b>[key_name(src, recipient, 1)]</b> to-<b>[key_name(recipient, src, 1)]</b>: [keywordparsedmsg]</font>"
admin_ticket_log(src, interaction_message)
if(recipient != src) //reeee
admin_ticket_log(recipient, interaction_message)
else //recipient is an admin but sender is not
var/replymsg = "<font color='red'>Reply PM from-<b>[key_name(src, recipient, 1)]</b>: [keywordparsedmsg]</font>"
admin_ticket_log(src, replymsg)
to_chat(recipient, replymsg)
to_chat(src, "<font color='blue'>PM to-<b>Admins</b>: [msg]</font>")
//play the recieving admin the adminhelp sound (if they have them enabled)
if(recipient.prefs.toggles & SOUND_ADMINHELP)
recipient << 'sound/effects/adminhelp.ogg'
else
if(holder) //sender is an admin but recipient is not. Do BIG RED TEXT
if(!recipient.current_ticket)
new /datum/admin_help(msg, recipient, TRUE)
to_chat(recipient, "<font color='red' size='4'><b>-- Administrator private message --</b></font>")
to_chat(recipient, "<font color='red'>Admin PM from-<b>[key_name(src, recipient, 0)]</b>: [msg]</font>")
to_chat(recipient, "<font color='red'><i>Click on the administrator's name to reply.</i></font>")
to_chat(src, "<font color='blue'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: [msg]</font>")
admin_ticket_log(recipient, "<font color='blue'>PM From [key_name_admin(src)]: [keywordparsedmsg]</font>")
//always play non-admin recipients the adminhelp sound
recipient << 'sound/effects/adminhelp.ogg'
//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
if(config.popup_admin_pm)
spawn() //so we don't hold the caller proc up
var/sender = src
var/sendername = key
var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as text|null //show message and await a reply
if(recipient && reply)
if(sender)
recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them
else
adminhelp(reply) //sender has left, adminhelp instead
return
else //neither are admins
to_chat(src, "<font color='red'>Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.</font>")
return
if(irc)
log_admin_private("PM: [key_name(src)]->IRC: [rawmsg]")
for(var/client/X in GLOB.admins)
to_chat(X, "<B><font color='blue'>PM: [key_name(src, X, 0)]-&gt;IRC:</B> \blue [keywordparsedmsg]</font>" )
else
window_flash(recipient, ignorepref = TRUE)
log_admin_private("PM: [key_name(src)]->[key_name(recipient)]: [rawmsg]")
//we don't use message_admins here because the sender/receiver might get it too
for(var/client/X in GLOB.admins)
if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipient
to_chat(X, "<B><font color='blue'>PM: [key_name(src, X, 0)]-&gt;[key_name(recipient, X, 0)]:</B> \blue [keywordparsedmsg]</font>" )
/proc/IrcPm(target,msg,sender)
var/client/C = GLOB.directory[target]
var/datum/admin_help/ticket = C ? C.current_ticket : GLOB.ahelp_tickets.CKey2ActiveTicket(target)
var/compliant_msg = trim(lowertext(msg))
var/irc_tagged = "[sender](IRC)"
var/list/splits = splittext(compliant_msg, " ")
if(splits.len && splits[1] == "ticket")
if(splits.len < 2)
return "Usage: ticket <close|resolve|icissue|reject>"
switch(splits[2])
if("close")
if(ticket)
ticket.Close(irc_tagged)
return "Ticket #[ticket.id] successfully closed"
if("resolve")
if(ticket)
ticket.Resolve(irc_tagged)
return "Ticket #[ticket.id] successfully resolved"
if("icissue")
if(ticket)
ticket.ICIssue(irc_tagged)
return "Ticket #[ticket.id] successfully marked as IC issue"
if("reject")
if(ticket)
ticket.Reject(irc_tagged)
return "Ticket #[ticket.id] successfully rejected"
else
return "Usage: ticket <close|resolve|icissue|reject>"
return "Error: Ticket could not be found"
var/static/stealthkey
var/adminname = config.showircname ? irc_tagged : "Administrator"
if(!C)
return "Error: No client"
if(!stealthkey)
stealthkey = GenIrcStealthKey()
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg)
return "Error: No message"
message_admins("IRC message from [sender] to [key_name_admin(C)] : [msg]")
log_admin_private("IRC PM: [sender] -> [key_name(C)] : [msg]")
msg = emoji_parse(msg)
to_chat(C, "<font color='red' size='4'><b>-- Administrator private message --</b></font>")
to_chat(C, "<font color='red'>Admin PM from-<b><a href='?priv_msg=[stealthkey]'>[adminname]</A></b>: [msg]</font>")
to_chat(C, "<font color='red'><i>Click on the administrator's name to reply.</i></font>")
admin_ticket_log(C, "<font color='blue'>PM From [irc_tagged]: [msg]</font>")
window_flash(C, ignorepref = TRUE)
//always play non-admin recipients the adminhelp sound
C << 'sound/effects/adminhelp.ogg'
C.ircreplyamount = IRCREPLYCOUNT
return "Message Successful"
/proc/GenIrcStealthKey()
var/num = (rand(0,1000))
var/i = 0
while(i == 0)
i = 1
for(var/P in GLOB.stealthminID)
if(num == GLOB.stealthminID[P])
num++
i = 0
var/stealth = "@[num2text(num)]"
GLOB.stealthminID["IRCKEY"] = stealth
return stealth
#undef IRCREPLYCOUNT