diff --git a/README.md b/README.md index 35f334c5ec8..55a837b08aa 100644 --- a/README.md +++ b/README.md @@ -91,3 +91,11 @@ For more advanced setups, setting the server `tick_lag` in the config as well as ### SQL Setup The SQL backend for the library and stats tracking requires a MySQL server, as does the optional SQL saves system. Your server details go in config/dbconfig.txt, and initial database setup is done with [flyway](https://flywaydb.org/). Detailed instructions can be found [here](https://github.com/Aurorastation/Aurora.3/tree/master/SQL). + +--- + +### Discord Bot + +The Aurorastation codebase uses a built-in Discord bot to interface with Discord. Some of its features rely on the MySQL database, specifically, channel storage and configuration. So a database is required for its operation. If that is present, then setup is relatively easy: simply set up the `config/discord.txt` file according to the example located in the `config/example/` folder, and populate the database with appropriate channel and server information. + +At present, there is no built in GUI for doing the latter. So direct database modification is required unless you set up the python companion bot. The python companion bot is BOREALIS II, and can be located [here](https://github.com/Aurorastation/BOREALISbot2). Though not required, it makes database modification easier. See commands that start with `channel_`. diff --git a/baystation12.dme b/baystation12.dme index 4d76070f216..690f7bd673a 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -967,7 +967,6 @@ #include "code\modules\admin\player_notes_sql.dm" #include "code\modules\admin\player_panel.dm" #include "code\modules\admin\topic.dm" -#include "code\modules\admin\ToRban.dm" #include "code\modules\admin\callproc\callproc.dm" #include "code\modules\admin\DB ban\ban_mirroring.dm" #include "code\modules\admin\DB ban\functions.dm" diff --git a/bot/borealis/bot.py b/bot/borealis/bot.py deleted file mode 100644 index d559566c1a1..00000000000 --- a/bot/borealis/bot.py +++ /dev/null @@ -1,499 +0,0 @@ -import discord -import socket -import logging -import yaml -import os.path -import struct -import random -import pickle -import _thread -from urllib import parse - -class DiscordBot(discord.Client): - def __init__(self, config, **kwargs): - super(DiscordBot, self).__init__(**kwargs) - - self.read_config(config) - self.listening = False - - def run(self): - self.login(self.credentials['email'], self.credentials['password']) - logging.info("Starting bot.") - - super(DiscordBot, self).run() - - def on_ready(self): - logging.info("Bot ready and running.") - logging.info("Logged in as: {0}.".format(self.user.name)) - self.do_greeting(None) - - _thread.start_new_thread(self.receive_nudges, ()) - - def on_message(self, msg): - words = msg.content.split(' ') - - if words[0] == None: - return - - if words[0][0] == "!": - self.do_command(msg, words) - - return - - def read_config(self, config_path): - if os.path.isfile(config_path) == False: - raise Exception("Invalid config path.") - - logging.info("Reading config from file: {0}.".format(config_path)) - with open(config_path, 'r') as f: - config = yaml.load(f) - - self.last_config = config_path - - self.credentials = config['credentials'] - self.channels = config['channels'] - - self.allow_everyone = config['allow_everyone'] - self.allow_nudging = config['allow_nudging'] - self.nudge_config = config['nudge_config'] - - self.greeting = config['greeting'] - - self.server_info = config['server_info'] - - self.commands = config['commands'] - - self.authorization = config['authorization'] - - def do_greeting(self, channel): - if self.greeting == None or self.greeting == "": - return - - if channel != None: - self.send_message(channel, self.greeting) - else: - self.forward_message("lobby", self.greeting) - - def check_authorization(self, user, required_access): - if required_access == None or isinstance(user, discord.Member) == False: - return False - - for role in user.roles: - if role.name.lower() in self.authorization['admin']: - return True - - if required_access == 1 and role.name.lower() in self.authorization['mod']: - return True - - if required_access == 2 and role.name.lower() in self.authorization['cciaa']: - return True - - return False - - def do_command(self, msg, words): - command = words[0][1:].lower() - response = None - - if command in self.commands['admin_commands'] or command in self.commands['cciaa_commands'] or command in self.commands['mod_commands']: - authorization = 1 - - if command in self.commands['cciaa_commands']: - authorization = 2 - elif command in self.commands['admin_commands']: - authorization = 3 - - if self.check_authorization(msg.author, authorization) == False: - self.send_message(msg.channel, "Error: you lack authorization to use this command.") - return - - #General commands - if command == "help": - response = "```-----------BOREALIS Directives-----------\n" - for sorted_command in sorted(self.commands['public_commands'].keys()): - response += "[+] !{0} - {1}\n".format(sorted_command, self.commands['public_commands'][sorted_command]) - - response += "----------------------------------------```" - elif command == "helpadmin" or command == "helpmod" or command == "helpcciaa": - use_list = "admin_commands" - if command == "helpmod": - use_list = "mod_commands" - elif command == "helpcciaa": - use_list = "cciaa_commands" - - response = "```-------------Restricted Commands-------------\n" - response += "These commands have mark-up syntax! Replace all [placeholders] with pure text, no brackets needed!\n" - response += "Note that these commands are authorized based on your chat server role! If you do not have authorization, you will be informed as such and the command will fail!\n" - response += "----------------------------------------\n" - for sorted_command in sorted(self.commands[use_list].keys()): - response += "[+] !{0} - {1}\n".format(sorted_command, self.commands[use_list][sorted_command]) - - response += "----------------------------------------```" - elif command == "greet": - self.do_greeting(msg.channel) - elif command == "mentionstatus": - response = "I will use the everyone-mention." - if self.allow_everyone == False: - response = "I will not use the everyone-mention." - - response = "{0} - {1}".format(msg.author.mention(), response) - elif command == "nudgestatus": - response = "I am actively receiving nudges." - if self.allow_nudging == False: - response = "I am not receiving nudges." - - response = "{0} - {1}".format(msg.author.mention(), response) - elif command == "playercount": - count = self.ping_server(b"players") - - if count == None: - response = "{0} - Sorry! I was unable to ping the server!".format(msg.author.mention()) - else: - response = "{0} - There are {1} players on the server.".format(msg.author.mention(), count) - elif command == "admincount": - count = self.ping_server(b"admins") - - if count == None: - response = "{0} - Sorry! I was unable to ping the server!".format(msg.author.mention()) - else: - response = "{0} - There are {1} admins and mods on the server.".format(msg.author.mention(), count) - elif command == "cciaacount": - count = self.ping_server(b"cciaa") - - if count == None: - response = "{0} - Sorry! I was unable to ping the server!".format(msg.author.mention()) - else: - response = "{0} - There are {1} duty officers on the server.".format(msg.author.mention(), count) - elif command == "gamemode": - gamemode = self.ping_server(b"gamemode") - - if gamemode == None: - response = "{0} - Sorry! I was unable to ping the server!".format(msg.author.mention()) - else: - response = "{0} - The current gamemode is {1}.".format(msg.author.mention(), gamemode) - elif command == "manifest": - server_reply = self.ping_server(b"manifest") - - if server_reply == None: - response = "{0} - Sorry! I was unable to ping the server!".format(msg.author.mention()) - elif isinstance(server_reply, str): - response = "{0} - The server replied with this: {1}.".format(msg.author.mention(), server_reply) - else: - response = "Current crew manifest:\n\n```\n" - for key in sorted(server_reply.keys()): - response += "{0}:\n".format(key.upper()) - - for chunk in server_reply[key].split('&'): - chunk = chunk.replace("+", " ") - dat = chunk.split('=') - if len(dat) == 2: - response += "{0} as {1}\n".format(parse.unquote(dat[0]), parse.unquote(dat[1])) - response += "\n\n" - response += "```" - elif command == "who": - server_reply = self.ping_server(b"who") - - if server_reply == None: - response = "{0} - Sorry! I was unable to ping the server!".format(msg.author.mention()) - else: - response = "Current player list:\n\n```\n" - for value in server_reply.split('&'): - response += value - response += "\n" - response += "```" - - #Authorized commands: - elif command == "togglenudges": - self.allow_nudging = not self.allow_nudging - - if self.allow_nudging == True: - response = "{0} - Nudge receiver now accepts connections. Now forwarding messages from within the game.".format(msg.author.mention()) - else: - response = "{0} - Nudge receiver no longer accepting connections. No longer forwarding messages from within the game.".format(msg.author.mention()) - elif command == "togglementions": - self.allow_everyone = not self.allow_everyone - - if self.allow_everyone == True: - response = "{0} - Now mentioning everyone when needed.".format(msg.author.mention()) - else: - response = "{0} - No longer mentioning everyone in my messages.".format(msg.author.mention()) - elif command == "refreshconfig": - response = "{0} - Config refreshed, as per your request.".format(msg.author.mention()) - try: - self.read_config(self.last_config) - except Exception as e: - response = "{0} - error refreshing config: {1}".format(msg.author.mention(), e) - elif command == "adminmsg": - if len(words) < 3: - response = "Not enough arguments passed! Couldn't execute the command." - else: - message = "" - i = 2 - while i < len(words): - message += words[i] - - if i < len(words) - 1: - message += "+" - - i += 1 - - to_send = "adminmsg={0}&key={1}&sender={2}&msg={3}".format(words[1], self.server_info["key"], msg.author.name, message) - - server_reply = self.ping_server(bytes(to_send, "utf-8")) - - if server_reply == None: - response = "Sorry! I couldn't execute the command for whatever reason!" - else: - response = "Got a reply back from the server! '{0}'".format(server_reply) - elif command == "mute": - if len(words) < 2: - response = "Not enough argumetns passed! Couldn't execute the command." - else: - server_reply = self.ping_server(bytes("mute={0}&admin={1}&key={2}".format(words[1], msg.author.name, self.server_info["key"]), "utf-8")) - - if server_reply == None: - response = "Sorry! I couldn't execute the command for whatever reason!" - else: - response = "Got a reply back from the server! '{0}'".format(server_reply) - elif command == "restartserver": - logging.info("Server restart command issued by {0}.".format(msg.author.name)) - server_reply = self.ping_server(bytes("restart={0}&key={1}".format(msg.author.name, self.server_info["key"]), "utf-8")) - - if server_reply == None: - response = "I think we did it. I didn't get a response, so I think it worked!" - elif command == "announceserver": - if len(words) < 2: - response = "Not enough arguments passed! Couldn't execute the command." - else: - message = "" - i = 1 - while i < len(words): - message += words[i] - - if i < len(words) - 1: - message += "+" - - i += 1 - - server_reply = self.ping_server(bytes("announce={0}&key={1}&msg={2}".format(msg.author.name, self.server_info["key"], message), "utf-8")) - - if server_reply == None: - response = "Sorry! I couldn't execute the command for whatever reason!" - else: - response = "Got a reply back from the server! '{0}'".format(server_reply) - elif command == "notes": - if len(words) < 2: - response = "Not enough argumetns passed! Couldn't execute the command." - else: - server_reply = self.ping_server(bytes("notes={0}&key={1}".format(words[1], self.server_info["key"]), "utf-8")) - - if server_reply == None: - response = "Sorry! I couldn't execute the command for whatever reason!" - else: - response = server_reply - elif command == "info": - if len(words) < 2: - response = "Not enough arguments passed! Couldn't execute the command." - else: - server_reply = self.ping_server(bytes("info={0}&key={1}".format(words[1], self.server_info["key"]), "utf-8")) - - if server_reply == None: - response = "Sorry! I was unable to ping the server!" - elif isinstance(server_reply, str): - response = "The server replied with this: {0}.".format(server_reply) - else: - response = "Information on {0}:\n\n```\n".format(server_reply["key"]) - for key in sorted(server_reply.keys()): - if key == "damage" and server_reply[key] != "non-living": - for chunk in server_reply[key].split('&'): - chunk = chunk.replace("+", " ") - dat = chunk.split('=') - if len(dat) == 2: - response += "{0} damage at: {1}\n".format(parse.unquote(dat[0]), parse.unquote(dat[1])) - else: - response += "{0} = {1}\n".format(key, server_reply[key]) - response += "```" - elif command == "age": - if len(words) < 2: - response = "Not enough arguments passed! Couldn't execute the command." - else: - server_reply = self.ping_server(bytes("age={0}&key={1}".format(words[1], self.server_info["key"]), "utf-8")) - - if server_reply == None: - response = "Sorry! I was unable to ping the server!" - else: - response = "The server replied with this: {0}.".format(server_reply) - elif command == "faxlist": - received = "received" - if len(words) < 2: - self.send_message(msg.channel, "{0} - You didn't specify whether you want received or sent faxes. Assuming you wanted **received**.".format(msg.author.mention())) - elif words[1].lower() != "received" and words[1].lower() != "sent": - self.send_message(msg.channel, "{0} - You used an invalid key on specifying whether you want received or sent faxes. Assuming you wanted **received**.".format(msg.author.mention())) - else: - received = words[1].lower() - - server_reply = self.ping_server(bytes("faxlist={0}&key={1}".format(received, self.server_info["key"]), "utf-8")) - - if server_reply == None: - response = "Sorry! I couldn't execute the command for whatever reason!" - else: - if isinstance(server_reply, str) == True: - response = server_reply - else: - response = "Here are the faxes I got!" - for key in server_reply: - response += "\n{0} - {1}".format(key, server_reply[key]) - elif command == "getfax": - received = "received" - if len(words) < 3: - response = "Not enough arguments passed! Couldn't execute the command." - elif words[1].isdigit == False: - response = "{0} - You didn't give me an integer! I cannot work with this!".format(msg.author.mention()) - else: - if words[2].lower() != "received" and words[2].lower() != "sent": - self.send_message(msg.channel, "{0} - You used an invalid key on specifying whether you want received or sent faxes. Assuming you wanted **received**.".format(msg.author.mention())) - else: - received = words[2].lower() - - fax_id = words[1] - server_reply = self.ping_server(bytes("getfax={0}&key={1}&received={2}".format(fax_id, self.server_info["key"], received), "utf-8")) - - if server_reply == None: - response = "Sorry! I couldn't execute the command for whatever reason!" - else: - if isinstance(server_reply, str): - response = server_reply - else: - response = "Fax titled '{0}':\n\n```{1}```".format(server_reply["title"], server_reply["content"]) - - if response != None: - self.send_message(msg.channel, response) - elif random.randrange(10) == 8: - self.send_message(msg.channel, "..Were you talking to me...?") - - def forward_message(self, destination, msg): - if destination not in self.channels: - return - - if msg == None: - return - - if self.allow_everyone == False and msg.find("@everyone") != -1: - msg.replace("@everyone", "") - - invite = self.get_invite(self.channels[destination]) - self.accept_invite(invite) - self.send_message(invite.channel, msg) - - def receive_nudges(self): - if self.nudge_config['port'] == None or self.nudge_config['hostname'] == None: - logging.error("Runtime error while starting receive_nudges(): hostname or port unspecified.") - return - - if self.listening == True: - return - else: - self.listening = True - - logging.info("Receive_nudges() started.") - port = self.nudge_config['port'] - host = self.nudge_config['hostname'] - backlog = 5 - size = 1024 - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.bind((host, port)) - s.listen(backlog) - - while True: - client, _ = s.accept() - - if self.allow_nudging == False: - client.close() - continue - - data = client.recv(size) - client.close() - truedata = pickle.loads(data) - to = None - msg = None - - if truedata.get('key', '') != self.nudge_config['key']: - continue - - if truedata.get('channel', None) != None: - to = truedata['channel'] - else: - continue - - msg = truedata['data'] - self.forward_message(to, msg) - - def decode_packet(self, packet): - if packet != "": - if b"\x00" in packet[0:2] or b"\x83" in packet[0:2]: - - sizebytes = struct.unpack('>H', packet[2:4]) # array size of the type identifier and content # ROB: Big-endian! - size = sizebytes[0] - 1 # size of the string/floating-point (minus the size of the identifier byte) - if b'\x2a' in packet[4:5]: # 4-byte big-endian floating-point - unpackint = struct.unpack('f', packet[5:9]) # 4 possible bytes: add them up together, unpack them as a floating-point - - return int(unpackint[0]) - elif b'\x06' in packet[4:5]: # ASCII string - unpackstr = '' # result string - index = 5 # string index - indexend = index + size - - string = packet[5:indexend].decode("utf-8") - string = string.replace('\x00', '') - - return string - return None - - def ping_server(self, question): - try: - - query = b'\x00\x83' - query += struct.pack('>H', len(question) + 6) - query += b'\x00\x00\x00\x00\x00' - query += question - query += b'\x00' - - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((self.server_info['hostname'], self.server_info['port'])) - s.settimeout(30) - - if s == None: - return None - - s.sendall(query) - - data = b'' - while True: - buf = s.recv(1024) - data += buf - szbuf = len(buf) - if szbuf < 1024: - break - - s.close() - - response = self.decode_packet(bytes(data)) - - if response != None: - if isinstance(response, int) == True or (response.find('&') + response.find('=') == -2): - return response - else: - parsed_response = {} - for chunk in response.split('&'): - chunk = chunk.replace("+", " ") - dat = chunk.split('=') - parsed_response[dat[0]] = '' - if len(dat) == 2: - parsed_response[dat[0]] = parse.unquote(dat[1]) - - return parsed_response - else: - return None - except socket.timeout: - return None - except socket.error: - return None diff --git a/bot/borealisbot.py b/bot/borealisbot.py deleted file mode 100644 index 3ac8287316c..00000000000 --- a/bot/borealisbot.py +++ /dev/null @@ -1,18 +0,0 @@ -import borealis.bot as borealisbot -import logging -import os - -def main(): - logging.basicConfig(format='%(asctime)s: %(levelname)-8s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S', level=logging.INFO) - config_path = 'config.yml' - - while True: - try: - bot = borealisbot.DiscordBot(config_path) - bot.run() - except Exception as e: - logging.critical(e) - break - -if __name__ == '__main__': - main() diff --git a/bot/config.example.yml b/bot/config.example.yml deleted file mode 100644 index aee82850f35..00000000000 --- a/bot/config.example.yml +++ /dev/null @@ -1,71 +0,0 @@ -#Email and password used to log into the discord account. -credentials: - email: 'bot@somemail.com' - password: 'apassword' - -#Dictionary of channels to be used. -channels: - lobby: 'https://discord.gg/foo' - admin_channel: 'https://discord.gg/foobar' - -#A greeting message. Displayed whenever the bot starts up, usually sent to the lobby. -greeting: 'Reactor: online. Sensors: online. Connection established. All systems nominal.' - -#Config settings for behaviour control. -allow_everyone: True -allow_nudging: True - -#Config for setting up the nudge_receiver() proc. -nudge_config: - hostname: 'localhost' - port: 5555 - key: 'foobar' - -#Server info for the game. Key must be the same as comms_password in ../config/config.txt. -server_info: - hostname: 'localhost' - port: 4444 - key: 'foobar' - -#All commands the bot is meant to recognize, along with helper text. -#Split into different dictionaries, depending on the access required to use them. -commands: - public_commands: - help: Sends this message to you. - helpadmin: Showcases all admin commands, and their syntax. - helpmod: Showcases all mod commands, and their syntax. - helpcciaa: Showcases all duty officer commands, and their syntax. - greet: Forces me to greet you!. - playercount: Checks the playercount of the server and returns it to you. - admincount: Checks the amount of admins on the server and returns it to you. - docount: Checks the amount of DOs on the server and returns it to you. - gamemode: Tells you the servers current gamemode. - mentionstatus: Tells you whether or not I am set to mention everyone. - nudgestatus: Tells you whether or not I am forwarding messages from within the game. - - admin_commands: - togglenudges: Toggles my status on nudges. - togglementions: Toggles my usage of the everyone mention. - refreshconfig: Refreshes my config file, and loads new values into it. - restartserver: Restarts the main game server. - announceserver: Sends an admin anonuncement to the game server. Syntax !announceserver [message to announce]. - adminmsg: Sends a PM to the player whose CKey is specified. Syntax !adminmsg [player ckey] [message to send]. - - mod_commands: - adminmsg: Sends a PM to the player whose CKey is specified. Syntax !adminmsg [player ckey] [message to send]. - - cciaa_commands: - faxlist: Returns a list of fax IDs and their subjects that have been sent or received this round. Replace [received] with either the word "sent" or "received". Syntax !faxlist [received]. - getfax: Returns the content of the fax with the ID specified. Replace [received] with either the word "sent" or "received" and [fax_id] with a number. Syntax !getfax [fax_id] [received]. - -#Authorized server-groups for specific commands. Cciaa are authorized for cciaa_commands, etcetera. -authorization: - admin: [ - 'administrators' - ] - mod: [ - 'moderators' - ] - cciaa: [ - 'duty officers' - ] diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 868250db649..476815ad0de 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -4,8 +4,6 @@ var/list/gamemode_cache = list() var/server_name = null // server name (for world name / status) var/server_suffix = 0 // generate numeric suffix based on server port - var/nudge_script_path = "nudge.py" // where the nudge.py script is located - var/list/lobby_screens = list("title") // Which lobby screens are available var/log_ooc = 0 // log OOC channel @@ -50,7 +48,6 @@ var/list/gamemode_cache = list() var/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1. var/Ticklag = 0.9 var/Tickcomp = 0 - var/socket_talk = 0 // use socket_talk to communicate with other processes var/list/resource_urls = null var/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round. var/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round. @@ -74,7 +71,6 @@ var/list/gamemode_cache = list() var/mod_tempban_max = 1440 var/mod_job_tempban_max = 1440 var/load_jobs_from_txt = 0 - var/ToRban = 0 var/automute_on = 0 //enables automuting/spam prevention var/macro_trigger = 5 // The grace period between messages before it's counted as abusing a macro. var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access. @@ -98,7 +94,6 @@ var/list/gamemode_cache = list() var/guests_allowed = 1 var/debugparanoid = 0 - var/serverurl var/server var/banappeals var/wikiurl @@ -180,16 +175,10 @@ var/list/gamemode_cache = list() var/nl_start = 19 var/nl_finish = 8 - var/comms_password = "" - var/enter_allowed = 1 - var/use_discord_bot = 0 - var/discord_bot_host = "localhost" - var/discord_bot_port = 0 var/use_discord_pins = 0 var/python_path = "python" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix - var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge. var/use_overmap = 0 var/list/station_levels = list(3, 4, 5, 6, 7) // Defines which Z-levels the station exists on. @@ -461,15 +450,9 @@ var/list/gamemode_cache = list() if ("serversuffix") config.server_suffix = 1 - if ("nudge_script_path") - config.nudge_script_path = value - if ("hostedby") config.hostedby = value - if ("serverurl") - config.serverurl = value - if ("server") config.server = value @@ -614,18 +597,12 @@ var/list/gamemode_cache = list() if("antag_hud_restricted") config.antag_hud_restricted = 1 - if("socket_talk") - socket_talk = text2num(value) - if("tickcomp") Tickcomp = 1 if("humans_need_surnames") humans_need_surnames = 1 - if("tor_ban") - ToRban = 1 - if("automute_on") automute_on = 1 @@ -666,18 +643,6 @@ var/list/gamemode_cache = list() if("uneducated_mice") config.uneducated_mice = 1 - if("comms_password") - config.comms_password = value - - if("use_discord_bot") - config.use_discord_bot = 1 - - if("discord_bot_host") - config.discord_bot_host = value - - if("discord_bot_port") - config.discord_bot_port = value - if("use_discord_pins") config.use_discord_pins = 1 @@ -685,9 +650,6 @@ var/list/gamemode_cache = list() if(value) config.python_path = value - if("use_lib_nudge") - config.use_lib_nudge = 1 - if("allow_cult_ghostwriter") config.cult_ghostwriter = 1 @@ -934,7 +896,6 @@ var/list/gamemode_cache = list() else if (type == "age_restrictions") name = replacetext(name, "_", " ") - age_restrictions += name age_restrictions[name] = text2num(value) else if (type == "discord") @@ -952,6 +913,8 @@ var/list/gamemode_cache = list() discord_bot.robust_debug = 1 if ("subscriber") discord_bot.subscriber_role = value + if ("alert_visibility") + discord_bot.alert_visibility = 1 else log_misc("Unknown setting in discord configuration: '[name]'") diff --git a/code/controllers/subsystems/initialization/misc_early.dm b/code/controllers/subsystems/initialization/misc_early.dm index 0aa26228558..44c4a3c2657 100644 --- a/code/controllers/subsystems/initialization/misc_early.dm +++ b/code/controllers/subsystems/initialization/misc_early.dm @@ -32,15 +32,17 @@ // Create robolimbs for chargen. populate_robolimb_list() - if(config.ToRban) - ToRban_autoupdate() - // Set up antags. populate_antag_type_list() // Populate spawnpoints for char creation. populate_spawn_points() + // Get BOREALIS to warn staff about a lazy admin forgetting visibility to 0 + // before anyone has a chance to change it! + if (discord_bot) + discord_bot.alert_server_visibility() + lobby_image = new/obj/effect/lobby_image() ..() diff --git a/code/controllers/subsystems/job.dm b/code/controllers/subsystems/job.dm index b7e75307d64..e8ffd792d63 100644 --- a/code/controllers/subsystems/job.dm +++ b/code/controllers/subsystems/job.dm @@ -77,8 +77,6 @@ return FALSE if(jobban_isbanned(player, rank)) return FALSE - if(!job.player_old_enough(player.client)) - return FALSE var/position_limit = job.total_positions if(!latejoin) @@ -109,9 +107,6 @@ if(jobban_isbanned(player, job.title)) Debug("FOC isbanned failed, Player: [player]") continue - if(!job.player_old_enough(player.client)) - Debug("FOC player not old enough, Player: [player]") - continue if(flag && !(flag in player.client.prefs.be_special_role)) Debug("FOC flag failed, Player: [player], Flag: [flag], ") continue @@ -136,10 +131,6 @@ Debug("GRJ isbanned failed, Player: [player], Job: [job.title]") continue - if(!job.player_old_enough(player.client)) - Debug("GRJ player not old enough, Player: [player]") - continue - if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1) Debug("GRJ Random job given, Player: [player], Job: [job]") AssignRole(player, job.title) @@ -170,7 +161,7 @@ var/list/weightedCandidates = list() for(var/mob/V in candidates) // Log-out during round-start? What a bad boy, no head position for you! - if(!V.client) + if(!V.client) continue var/age = V.client.prefs.age @@ -280,10 +271,6 @@ Debug("DO isbanned failed, Player: [player], Job:[job.title]") continue - if(!job.player_old_enough(player.client)) - Debug("DO player not old enough, Player: [player], Job:[job.title]") - continue - // If the player wants that job on this level, then try give it to him. if(player.client.prefs.GetJobDepartment(job, level) & job.flag) @@ -606,7 +593,7 @@ /datum/controller/subsystem/jobs/proc/HandleFeedbackGathering() for(var/thing in occupations) var/datum/job/job = thing - + var/tmp_str = "|[job.title]|" var/level1 = 0 //high @@ -614,16 +601,12 @@ var/level3 = 0 //low var/level4 = 0 //never var/level5 = 0 //banned - var/level6 = 0 //account too young for(var/mob/new_player/player in player_list) if(!(player.ready && player.mind && !player.mind.assigned_role)) continue //This player is not ready if(jobban_isbanned(player, job.title)) level5++ continue - if(!job.player_old_enough(player.client)) - level6++ - continue if(player.client.prefs.GetJobDepartment(job, 1) & job.flag) level1++ else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag) @@ -632,7 +615,7 @@ level3++ else level4++ //not selected - tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|YOUNG=[level6]|-" + tmp_str += "HIGH=[level1]|MEDIUM=[level2]|LOW=[level3]|NEVER=[level4]|BANNED=[level5]|-" feedback_add_details("job_preferences",tmp_str) /datum/controller/subsystem/jobs/proc/LateSpawn(mob/living/carbon/human/H, rank) diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index b6435d95c24..9cea59227eb 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -82,13 +82,13 @@ var/datum/controller/subsystem/ticker/SSticker /datum/controller/subsystem/ticker/Recover() // Copy stuff over so we don't lose any state. current_state = SSticker.current_state - + hide_mode = SSticker.hide_mode mode = SSticker.mode post_game = SSticker.post_game login_music = SSticker.login_music - + minds = SSticker.minds Bible_icon_state = SSticker.Bible_icon_state @@ -113,7 +113,7 @@ var/datum/controller/subsystem/ticker/SSticker if (!lobby_ready) lobby_ready = TRUE return - + switch (current_state) if (GAME_STATE_PREGAME, GAME_STATE_SETTING_UP) pregame_tick() @@ -123,7 +123,7 @@ var/datum/controller/subsystem/ticker/SSticker /datum/controller/subsystem/ticker/proc/pregame_tick() if (round_progressing) pregame_timeleft-- - + if (current_state == GAME_STATE_PREGAME && pregame_timeleft == config.vote_autogamemode_timeleft) if (!SSvote.time_remaining) SSvote.autogamemode() @@ -133,7 +133,7 @@ var/datum/controller/subsystem/ticker/SSticker if (pregame_timeleft <= 10 && !tipped) send_tip_of_the_round() tipped = TRUE - + if (pregame_timeleft <= 0 || current_state == GAME_STATE_SETTING_UP) current_state = GAME_STATE_SETTING_UP wait = 2 SECONDS @@ -398,13 +398,6 @@ var/datum/controller/subsystem/ticker/SSticker //Holiday Round-start stuff ~Carn Holiday_Game_Start() - var/admins_number = 0 - for(var/client/C) - if(C.holder && (C.holder.rights & (R_MOD|R_ADMIN))) - admins_number++ - if(admins_number == 0) - discord_bot.send_to_admins("@here Round has started with no admins online.") - log_debug("SSticker: Running [LAZYLEN(roundstart_callbacks)] round-start callbacks.") run_callback_list(roundstart_callbacks) roundstart_callbacks = null @@ -424,7 +417,7 @@ var/datum/controller/subsystem/ticker/SSticker CHECK_TICK /datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed = 0, override = null) - if (cinematic) + if (cinematic) return //already a cinematic in progress! //initialise our cinematic screen object @@ -517,11 +510,11 @@ var/datum/controller/subsystem/ticker/SSticker //Otherwise if its a verb it will continue on afterwards. sleep(300) - if(cinematic) + if(cinematic) QDEL_NULL(cinematic) //end the cinematic - if(temp_buckle) + if(temp_buckle) QDEL_NULL(temp_buckle) //release everybody - + // Round setup stuff. /datum/controller/subsystem/ticker/proc/create_characters() @@ -552,7 +545,7 @@ var/datum/controller/subsystem/ticker/SSticker SSjobs.EquipRank(player, player.mind.assigned_role, 0) UpdateFactionList(player) equip_custom_items(player) - + CHECK_TICK if(captainless) for(var/mob/M in player_list) diff --git a/code/controllers/subsystems/vote.dm b/code/controllers/subsystems/vote.dm index 68653520008..39c7f606bc0 100644 --- a/code/controllers/subsystems/vote.dm +++ b/code/controllers/subsystems/vote.dm @@ -327,7 +327,7 @@ var/datum/controller/subsystem/vote/SSvote return 0 /datum/controller/subsystem/vote/proc/interface(client/C) - if(!C) + if(!C) return var/is_staff = 0 if(C.holder) @@ -403,9 +403,9 @@ var/datum/controller/subsystem/vote/SSvote . += "Close" /datum/controller/subsystem/vote/Topic(href, list/href_list = list(), hsrc) - if(!usr || !usr.client) + if(!usr || !usr.client) return //not necessary but meh...just in-case somebody does something stupid - + switch(href_list["vote"]) if("close") voting -= usr.client @@ -424,8 +424,25 @@ var/datum/controller/subsystem/vote/SSvote if(usr.client.holder) config.allow_vote_mode = !config.allow_vote_mode if("restart") - if(config.allow_vote_restart || usr.client.holder) + if(usr.client.holder) initiate_vote("restart",usr.key) + else if (config.allow_vote_restart) + var/admin_number_present = 0 + var/admin_number_afk = 0 + + for (var/client/X in admins) + if (X.holder.rights & R_ADMIN) + admin_number_present++ + if (X.is_afk()) + admin_number_afk++ + if (X.prefs.toggles & SOUND_ADMINHELP) + X << 'sound/effects/adminhelp.ogg' + + if ((admin_number_present - admin_number_afk) <= 0) + initiate_vote("restart", usr.key) + else + log_and_message_admins("tried to start a restart vote.", usr, null) + to_chat(usr, "There are active admins around! You cannot start a restart vote due to this.") if("gamemode") if(config.allow_vote_mode || usr.client.holder) initiate_vote("gamemode",usr.key) @@ -459,7 +476,7 @@ var/datum/controller/subsystem/vote/SSvote SSvote.setup_vote_window(client) var/datum/browser/vote_window = client.vote_window - + vote_window.set_user(src) vote_window.set_content(SSvote.interface(client)) vote_window.open() diff --git a/code/datums/discord_bot.dm b/code/datums/discord_bot.dm index d917dc6bb02..79aa65ddaae 100644 --- a/code/datums/discord_bot.dm +++ b/code/datums/discord_bot.dm @@ -27,6 +27,22 @@ var/datum/discord_bot/discord_bot = null return 1 +/hook/roundstart/proc/alert_no_admins() + if (!discord_bot) + return 1 + + var/admins_number = 0 + + for (var/C in clients) + var/client/cc = C + if (cc.holder && (cc.holder.rights & (R_MOD|R_ADMIN))) + admins_number++ + + if (!admins_number) + discord_bot.send_to_admins("@here Round has started with no admins or mods online.") + + return 1 + /datum/discord_bot var/list/channels_to_group = list() // Group flag -> list of channel datums map. var/list/channels = list() // Channel ID -> channel datum map. Will ensure that only one datum per channel ID exists. @@ -42,6 +58,10 @@ var/datum/discord_bot/discord_bot = null // Lazy man's rate limiting vars var/list/queue = list() + // Used to determine if BOREALIS should alert staff if the server is created + // with world.visibility == 0. + var/alert_visibility = 0 + /* * Proc update_channels * Used to load channels from the database and construct them with the discord API. @@ -243,6 +263,15 @@ var/datum/discord_bot/discord_bot = null queue.Remove(A) +/** + * Will alert the staff on Discord if the server is initialized in invisible mode. + * Can be toggled via config. + */ +/datum/discord_bot/proc/alert_server_visibility() + if (alert_visibility && !world.visibility) + send_to_admins("Server started as invisible!") + + // A holder class for channels. /datum/discord_channel var/id = "" diff --git a/code/game/antagonist/_antagonist_setup.dm b/code/game/antagonist/_antagonist_setup.dm index a5212256026..4bd05fb781b 100644 --- a/code/game/antagonist/_antagonist_setup.dm +++ b/code/game/antagonist/_antagonist_setup.dm @@ -32,6 +32,8 @@ var/global/list/all_antag_types = list() var/global/list/all_antag_spawnpoints = list() var/global/list/antag_names_to_ids = list() +// This is a bit dumb but without it the job and antag age whitelisting would be even dumber. +var/global/list/bantype_to_antag_age = list() // Global procs. /proc/get_antag_data(var/antag_type) @@ -66,6 +68,13 @@ var/global/list/antag_names_to_ids = list() all_antag_spawnpoints[A.landmark_id] = list() antag_names_to_ids[A.role_text] = A.id + // Set up age restrictions for the different antag bantypes. + if (!bantype_to_antag_age[A.bantype]) + if (config.age_restrictions[lowertext(A.bantype)]) + bantype_to_antag_age[lowertext(A.bantype)] = config.age_restrictions[lowertext(A.bantype)] + else + bantype_to_antag_age[A.bantype] = 0 + /proc/get_antags(var/atype) var/datum/antagonist/antag = all_antag_types[atype] if(antag && islist(antag.current_antagonists)) diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm index dbdcb210c84..05cdfc65877 100644 --- a/code/game/antagonist/antagonist.dm +++ b/code/game/antagonist/antagonist.dm @@ -48,7 +48,6 @@ var/mob_path = /mob/living/carbon/human // Mobtype this antag will use if none is provided. var/feedback_tag = "traitor_objective" // End of round var/bantype = "Syndicate" // Ban to check when spawning this antag. - var/minimum_player_age = 7 // Players need to be at least minimum_player_age days old before they are eligable for auto-spawning var/suspicion_chance = 50 // Prob of being on the initial Command report var/flags = 0 // Various runtime options. @@ -101,8 +100,6 @@ for(var/datum/mind/player in SSticker.mode.get_players_for_role(role_type, id)) if(ghosts_only && !istype(player.current, /mob/dead)) log_debug("[key_name(player)] is not eligible to become a [role_text]: Only ghosts may join as this role!") - else if(config.use_age_restriction_for_antags && player.current.client.player_age < minimum_player_age) - log_debug("[key_name(player)] is not eligible to become a [role_text]: Is only [player.current.client.player_age] day\s old, has to be [minimum_player_age] day\s!") else if(!allow_animals && isanimal(player.current)) log_debug("[key_name(player)] is not eligible to become a [role_text]: Simple animals cannot be this role!") else if(player.special_role) diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index e6fcf91f3b5..5412964b720 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -101,15 +101,6 @@ else return src.access.Copy() -//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1 -/datum/job/proc/player_old_enough(client/C) - return (available_in_days(C) == 0) //Available in 0 days = available right now = player is old enough to play. - -/datum/job/proc/available_in_days(client/C) - if(C && config.use_age_restriction_for_jobs && isnum(C.player_age) && isnum(minimal_player_age)) - return max(0, minimal_player_age - C.player_age) - return 0 - /datum/job/proc/apply_fingerprints(var/mob/living/carbon/human/target) if(!istype(target)) return 0 diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm index ba0816b76c8..6215ca73c00 100644 --- a/code/game/jobs/whitelist.dm +++ b/code/game/jobs/whitelist.dm @@ -96,4 +96,41 @@ var/list/whitelist = list() return 1 return 0 +/** + * A centralized proc for checking whether or not a player is fit for playing + * any antag role or job role dependant on their ckey's age, job's age restriction, + * and config settings. + * + * @param C The client object whose age we want to check. Can also be a mob. + * @param job The job name/antag role name we want to check against. + * + * @return Days left until the player can play the role if they're too young. + * 0 if they're old enough. + */ +/proc/player_old_enough_for_role(client/C, job) + if (!job || !C) + return 0 + + if (ismob(C)) + var/mob/M = C + C = M.client + + if (!istype(C) || C.holder) + return 0 + + var/age_to_beat = 0 + + // Assume it's an antag role. + if (bantype_to_antag_age[lowertext(job)] && config.use_age_restriction_for_antags) + age_to_beat = bantype_to_antag_age[lowertext(job)] + + // Assume it's a job instead! + if (!age_to_beat) + var/datum/job/J = SSjobs.GetJob(job) + if (J && config.use_age_restriction_for_jobs) + age_to_beat = J.minimal_player_age + + var/diff = age_to_beat - C.player_age + return (diff > 0) ? diff : 0 + #undef WHITELISTFILE diff --git a/code/game/socket_talk.dm b/code/game/socket_talk.dm deleted file mode 100644 index 8484b636b8d..00000000000 --- a/code/game/socket_talk.dm +++ /dev/null @@ -1,26 +0,0 @@ -// Module used for fast interprocess communication between BYOND and other processes - -/datum/socket_talk - var - enabled = 0 - New() - ..() - src.enabled = config.socket_talk - - if(enabled) - call("DLLSocket.so","establish_connection")("127.0.0.1","8019") - - proc - send_raw(message) - if(enabled) - return call("DLLSocket.so","send_message")(message) - receive_raw() - if(enabled) - return call("DLLSocket.so","recv_message")() - send_log(var/log, var/message) - return send_raw("type=log&log=[log]&message=[message]") - send_keepalive() - return send_raw("type=keepalive") - - -var/global/datum/socket_talk/socket_talk diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index 2340ba266c6..69b84f3ec77 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -151,7 +151,7 @@ cciaamsg += "\t[C] is a [C.holder.rank]\n" num_cciaa_online++ - if(config.use_discord_bot) + if(discord_bot && discord_bot.active) src << "Adminhelps are also sent to Discord. If no admins are available in game try anyway and an admin on Discord may see it and respond." msg = "Current Admins ([num_admins_online]):\n" + msg diff --git a/code/modules/admin/DB ban/ban_mirroring.dm b/code/modules/admin/DB ban/ban_mirroring.dm index 324025f64f8..315f8da52e5 100644 --- a/code/modules/admin/DB ban/ban_mirroring.dm +++ b/code/modules/admin/DB ban/ban_mirroring.dm @@ -205,10 +205,14 @@ update_connection_data(C, conn_info) if (ding_bannu) - log_and_message_admins("[C.ckey] from [C.address]-[C.computer_id] was caught bandodging. Mirror applied for ban #[ding_bannu], kicking shortly.") - apply_ban_mirror(C.ckey, C.address, C.computer_id, ding_bannu) - spawn(20) - del(C) + if (!C.holder) + log_and_message_admins("[C.ckey] from [C.address]-[C.computer_id] was caught bandodging. Mirror applied for ban #[ding_bannu], kicking shortly.") + apply_ban_mirror(C.ckey, C.address, C.computer_id, ding_bannu) + spawn(20) + del(C) + else + // Stop kicking me off my test server, fuck. + log_and_message_admins("[C.ckey] is a staff but was caught bandodging! Ban ID: #[ding_bannu].") return diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index 66d01cc8411..1155bf6bfde 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -387,30 +387,27 @@ var/alcolor = "#eeeeff" // auto-unbanned light var/adcolor = "#ddddff" // auto-unbanned dark - output += "" - output += "" - output += "" - output += "" - output += "" - output += "" - output += "" - output += "" - var/adminsearch = "" var/playersearch = "" var/ipsearch = "" var/cidsearch = "" var/bantypesearch = "" + var/mirror_player = "" + var/mirror_ip = "" + var/mirror_cid = "" if(!match) if(adminckey) adminsearch = "AND a_ckey = '[adminckey]' " if(playerckey) playersearch = "AND ckey = '[playerckey]' " + mirror_player = "AND mirrors.player_ckey = '[playerckey]' " if(playerip) ipsearch = "AND ip = '[playerip]' " + mirror_ip = "AND mirrors.ban_mirror_ip = '[playerip]' " if(playercid) cidsearch = "AND computerid = '[playercid]' " + mirror_cid = "AND mirrors.ban_mirror_computerid = '[playercid]'" else if(adminckey && lentext(adminckey) >= 3) adminsearch = "AND a_ckey LIKE '[adminckey]%' " @@ -434,6 +431,42 @@ else bantypesearch += "'PERMABAN' " + /** + * Do mirror checks first! Basically find active mirrors and add those to the output before we proceed onto finding bans. + */ + if (!match) + var/DBQuery/mirror_query = dbcon.NewQuery({"SELECT DISTINCT(mirrors.ban_id), bans.ckey FROM ss13_ban_mirrors mirrors + JOIN ss13_ban bans ON mirrors.ban_id = bans.id + WHERE (1 [mirror_player] [mirror_ip] [mirror_cid]) + AND ( + ISNULL(bans.unbanned) AND ( + (bans.bantype = 'PERMABAN') + OR + (bans.bantype = 'TEMPBAN' AND bans.expiration_time > NOW()) + ) + )"}) + mirror_query.Execute() + + var/mirror_count = 0 + var/mirror_data = "
" + while (mirror_query.NextRow()) + mirror_data += "Active mirror for #[mirror_query.item[1]] (View Ban)
" + mirror_count++ + + if (mirror_count) + output += "
[mirror_count] Active Mirrors Found!
" + output += mirror_data + output += "
" + + output += "
TYPECKEYTIME APPLIEDADMINOPTIONS
" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + output += "" + var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, unbanned_reason, edits, ip, computerid FROM ss13_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100") select_query.Execute() diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 28a57e325f1..5e4ad4371d1 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -10,17 +10,7 @@ world/IsBanned(key,address,computer_id) message_admins("Failed Login: [key] - Guests not allowed") return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.") - //check if the IP address is a known TOR node - if(config && config.ToRban && ToRban_isbanned(address)) - log_access("Failed Login: [src] - Banned: ToR",ckey=key_name(src)) - message_admins("Failed Login: [src] - Banned: ToR") - //ban their computer_id and ckey for posterity - AddBan(ckey(key), computer_id, "Use of ToR", "Automated Ban", 0, 0) - return list("reason"="Using ToR", "desc"="\nReason: The network you are using to connect has been banned.\nIf you believe this is a mistake, please request help at [config.banappeals]") - - if(config.ban_legacy_system) - //Ban Checking . = CheckBan( ckey(key), computer_id, address ) if(.) diff --git a/code/modules/admin/ToRban.dm b/code/modules/admin/ToRban.dm deleted file mode 100644 index d127bfe6f41..00000000000 --- a/code/modules/admin/ToRban.dm +++ /dev/null @@ -1,88 +0,0 @@ -//By Carnwennan -//fetches an external list and processes it into a list of ip addresses. -//It then stores the processed list into a savefile for later use -#define TORFILE "data/ToR_ban.bdb" -#define TOR_UPDATE_INTERVAL 216000 //~6 hours - -/proc/ToRban_isbanned(var/ip_address) - var/savefile/F = new(TORFILE) - if(F) - if( ip_address in F.dir ) - return 1 - return 0 - -/proc/ToRban_autoupdate() - var/savefile/F = new(TORFILE) - if(F) - var/last_update - F["last_update"] >> last_update - if((last_update + TOR_UPDATE_INTERVAL) < world.realtime) //we haven't updated for a while - ToRban_update() - return - -/proc/ToRban_update() - spawn(0) - log_misc("Downloading updated ToR data...") - var/http[] = world.Export("https://check.torproject.org/exit-addresses") - - var/list/rawlist = file2list(http["CONTENT"]) - if(rawlist.len) - fdel(TORFILE) - var/savefile/F = new(TORFILE) - for( var/line in rawlist ) - if(!line) continue - if( copytext(line,1,12) == "ExitAddress" ) - var/cleaned = copytext(line,13,length(line)-19) - if(!cleaned) continue - F[cleaned] << 1 - F["last_update"] << world.realtime - log_misc("ToR data updated!") - if(usr) usr << "ToRban updated." - return 1 - log_misc("ToR data update aborted: no data.") - return 0 - -/client/proc/ToRban(task in list("update","toggle","show","remove","remove all","find")) - set name = "ToRban" - set category = "Server" - if(!holder) return - switch(task) - if("update") - ToRban_update() - if("toggle") - if(config) - if(config.ToRban) - config.ToRban = 0 - message_admins("ToR banning disabled.") - else - config.ToRban = 1 - message_admins("ToR banning enabled.") - if("show") - var/savefile/F = new(TORFILE) - var/dat - if( length(F.dir) ) - for( var/i=1, i<=length(F.dir), i++ ) - dat += "" - dat = "
TYPECKEYTIME APPLIEDADMINOPTIONS
#[i] [F.dir[i]]
[dat]
" - else - dat = "No addresses in list." - src << browse(dat,"window=ToRban_show") - if("remove") - var/savefile/F = new(TORFILE) - var/choice = input(src,"Please select an IP address to remove from the ToR banlist:","Remove ToR ban",null) as null|anything in F.dir - if(choice) - F.dir.Remove(choice) - src << "Address removed" - if("remove all") - src << "[TORFILE] was [fdel(TORFILE)?"":"not "]removed." - if("find") - var/input = input(src,"Please input an IP address to search for:","Find ToR ban",null) as null|text - if(input) - if(ToRban_isbanned(input)) - src << "Address is a known ToR address" - else - src << "Address is not a known ToR address" - return - -#undef TORFILE -#undef TOR_UPDATE_INTERVAL diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 404d7e84dfd..cc7d5dfa356 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -742,11 +742,11 @@ proc/admin_notice(var/message, var/rights) set desc="Globally Toggles Hub Visibility" set name="Toggle Hub Visibility" - if(!check_rights(R_ADMIN)) + if(!check_rights(R_SERVER)) return world.visibility = !(world.visibility) - var/long_message = " toggled hub visibility. The server is now [world.visibility ? "visible" : "invisible"] ([world.visibility])." + var/long_message = " toggled hub visibility. The server is now [world.visibility ? "visible" : "invisible"] ([world.visibility])." discord_bot.send_to_admins("[key_name(src)]" + long_message) message_admins("[key_name_admin(usr)]" + long_message, 1) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index fd0a805054d..0d18c2e9333 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -63,7 +63,6 @@ var/list/admin_verbs_admin = list( /datum/admins/proc/toggledsay, //toggles dsay on/off for everyone, /client/proc/game_panel, //game panel, allows to change game-mode etc, /client/proc/cmd_admin_say, //admin-only ooc chat, - /datum/admins/proc/togglehubvisibility, //toggles visibility on the BYOND Hub, /datum/admins/proc/PlayerNotes, /client/proc/cmd_mod_say, /datum/admins/proc/show_player_info, @@ -148,7 +147,6 @@ var/list/admin_verbs_spawn = list( var/list/admin_verbs_server = list( /datum/admins/proc/capture_map, /client/proc/Set_Holiday, - /client/proc/ToRban, /datum/admins/proc/startnow, /datum/admins/proc/restart, /datum/admins/proc/delay, @@ -171,7 +169,8 @@ var/list/admin_verbs_server = list( /client/proc/toggle_recursive_explosions, /client/proc/restart_controller, /client/proc/cmd_ss_panic, - /client/proc/configure_access_control + /client/proc/configure_access_control, + /datum/admins/proc/togglehubvisibility //toggles visibility on the BYOND Hub ) var/list/admin_verbs_debug = list( /client/proc/getruntimelog, // allows us to access runtime logs to somebody, @@ -275,7 +274,6 @@ var/list/admin_verbs_hideable = list( /client/proc/toggle_random_events, /client/proc/cmd_admin_add_random_ai_law, /client/proc/Set_Holiday, - /client/proc/ToRban, /datum/admins/proc/startnow, /datum/admins/proc/restart, /datum/admins/proc/delay, diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm index 9f647814784..0de3b85ba53 100644 --- a/code/modules/admin/banjob.dm +++ b/code/modules/admin/banjob.dm @@ -113,9 +113,13 @@ var/list/jobban_keylist = list() // Global jobban list. if (ckey) if (guest_jobbans(rank)) if (config.guest_jobban && IsGuestKey(ckey)) - return "Guest Job-ban" + return "GUEST JOB-BAN" if (config.usewhitelist && ismob(player) && !check_whitelist(player)) - return "No Whitelist" + return "WHITELISTED" + + var/age_whitelist = player_old_enough_for_role(player, rank) + if (age_whitelist) + return "AGE WHITELISTED" var/static/list/antag_bantypes diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index e142f3df420..146cdb20b82 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1594,12 +1594,16 @@ usr << "Player not found!" return - if (C.adminhelped == 2) + if (C.adminhelped >= 2) log_and_message_admins("has called dibs on [key_name_admin(C)]'s adminhelp!") usr << "You have taken over [key_name_admin(C)]'s adminhelp.'" usr << "[get_options_bar(C, 2, 1, 1)]" C << "Your adminhelp will be tended [usr.client.holder.fakekey ? "shortly" : "by [key_name(usr, 0, 0)]"]. Please allow the staff member a minute or two to write up a response." + + if (C.adminhelped == 3) + discord_bot.send_to_admins("Request for Help from [key_name(C)] is being tended to by [key_name(usr)].") + C.adminhelped = 1 else usr << "The adminhelp has already been claimed!" diff --git a/code/modules/admin/verbs/access_control.dm b/code/modules/admin/verbs/access_control.dm index da20407fae6..6dfa61716b7 100644 --- a/code/modules/admin/verbs/access_control.dm +++ b/code/modules/admin/verbs/access_control.dm @@ -12,13 +12,16 @@ data += "They must be reset every single time the server restarts.
" data += "If you do not know what these do, you shouldn't be touching them!
" + data += "

Hub Visibility Setting:


" + data += "Currently [world.visibility ? "VISIBLE" : "HIDDEN"]. Toggle

" + data += "

IP Intel Settings:



" data += "

Player Age Settings:



" @@ -93,6 +96,8 @@ log_and_message_admins("has set players with [config.access_deny_vms] positive identifiers out of 2 for VM usage to be warned.") else log_and_message_admins("has disabled warnings based on potential VM usage.") + if ("hub") + togglehubvisibility() else to_chat(usr, "Unknown control message sent. Cancelling.") diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index f5d4c6a06f8..8aa0f4e2a7f 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -18,6 +18,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," adminhelped = 2 //Determines if they get the message to reply by clicking the name. /*A wee bit of an update here: we're using the following table for adminhelped values: + 3 - Adminhelp has not been claimed and was sent to discord as well. 2 - Adminhelp has not been claimed by anyone. 1 - Adminhelp has been claimed, initial message has not been sent. 0 - Adminhelp has been claimed, initial message has been sent. @@ -118,6 +119,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," var/admin_number_active = admin_number_present - admin_number_afk log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins.",admin_key=key_name(src)) if(admin_number_active <= 0) - discord_bot.send_to_admins("@everyone Request for Help from [key_name(src)]: [html_decode(original_msg)] - !![admin_number_afk ? "All admins AFK ([admin_number_afk])" : "No admins online"]!!") + discord_bot.send_to_admins("@here Request for Help from [key_name(src)]: [html_decode(original_msg)] - !![admin_number_afk ? "All admins AFK ([admin_number_afk])" : "No admins online"]!!") + adminhelped = 3 feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 3dd6fd0e6fc..382391ab973 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -29,17 +29,32 @@ //log_admin("HELP: [key_name(src)]: [msg]") /proc/Centcomm_announce(var/msg, var/mob/Sender, var/iamessage) - discord_bot.send_to_cciaa("Emergency message from the station: `[msg]`, sent by [Sender]!") - var/msg_cciaa = "[uppertext(boss_short)][iamessage ? " IA" : ""]:[key_name(Sender, 1)] (RPLY): [msg]" msg = "[uppertext(boss_short)]M[iamessage ? " IA" : ""]:[key_name(Sender, 1)] (PP) (VV) (SM) ([admin_jump_link(Sender, src)]) (CA) (BSA) (RPLY): [msg]" + var/cciaa_present = 0 + var/cciaa_afk = 0 for(var/client/C in admins) if(R_ADMIN & C.holder.rights) C << msg else if (R_CCIAA & C.holder.rights) + cciaa_present++ + if (C.is_afk()) + cciaa_afk++ + C << msg_cciaa + discord_bot.send_to_cciaa("Emergency message from the station: `[msg]`, sent by [Sender]!") + + var/discord_msg = "[cciaa_present] agents online." + if (cciaa_present) + if ((cciaa_present - cciaa_afk) <= 0) + discord_msg += " **All AFK!**" + else + discord_msg += " [cciaa_afk] AFK." + + discord_bot.send_to_cciaa(discord_msg) + /proc/Syndicate_announce(var/msg, var/mob/Sender) msg = "ILLEGAL:[key_name(Sender, 1)] (PP) (VV) (SM) ([admin_jump_link(Sender, src)]) (CA) (BSA) (RPLY): [msg]" for(var/client/C in admins) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 8952fa5b50b..69fbbe65e4c 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -209,6 +209,20 @@ return + if (href_list["view_jobban"]) + var/reason = jobban_isbanned(ckey, href_list["view_jobban"]) + if (!reason) + to_chat(src, span("notice", "You do not appear jobbanned from this job. If you are still stopped from entering the role however, please adminhelp.")) + return + + var/data = "
Jobbanned from: [href_list["view_jobban"]]
" + data += "Reason:
" + data += reason + data += "
" + + show_browser(src, data, "jobban_reason") + return + ..() //redirect to hsrc.() /client/proc/handle_spam_prevention(var/message, var/mute_type) diff --git a/code/modules/client/preference_setup/antagonism/01_candidacy.dm b/code/modules/client/preference_setup/antagonism/01_candidacy.dm index 7ca9c1b1d7a..8b8819731bb 100644 --- a/code/modules/client/preference_setup/antagonism/01_candidacy.dm +++ b/code/modules/client/preference_setup/antagonism/01_candidacy.dm @@ -1,3 +1,7 @@ +#define NOBAN 0 +#define AGEBAN 1 +#define RANBAN 2 + /datum/category_item/player_setup_item/antagonism/candidacy name = "Candidacy" sort_order = 1 @@ -39,8 +43,11 @@ for(var/antag_type in all_antag_types) var/datum/antagonist/antag = all_antag_types[antag_type] . += "[antag.role_text]: " - if(is_global_banned || jobban_isbanned(preference_mob(), antag.bantype)) - . += "\[BANNED\]
" + var/ban_reason = jobban_isbanned(preference_mob(), antag.bantype) + if(ban_reason == "AGE WHITELISTED") + . += "\[IN [player_old_enough_for_role(preference_mob(), antag.bantype)] DAYS\]
" + else if(is_global_banned || ban_reason) + . += "\[BANNED\]
" else if(antag.role_type in pref.be_special_role) . += "Yes / No
" else @@ -54,8 +61,16 @@ continue . += "[(ghost_trap.ghost_trap_role)]: " - if(banned_from_ghost_role(preference_mob(), ghost_trap)) - . += "\[BANNED\]
" + var/ban_state = banned_from_ghost_role(preference_mob(), ghost_trap) + if(ban_state == AGEBAN) + var/age_to_beat = 0 + for (var/A in ghost_trap.ban_checks) + age_to_beat = player_old_enough_for_role(preference_mob(), A) + if (age_to_beat) + break + . += "\[IN [age_to_beat] DAYS\]
" + else if (ban_state == RANBAN) + . += "\[BANNED\]
" else if(ghost_trap.pref_check in pref.be_special_role) . += "Yes / No
" else @@ -65,9 +80,12 @@ /datum/category_item/player_setup_item/proc/banned_from_ghost_role(var/mob, var/datum/ghosttrap/ghost_trap) for(var/ban_type in ghost_trap.ban_checks) - if(jobban_isbanned(mob, ban_type)) - return 1 - return 0 + . = jobban_isbanned(mob, ban_type) + if(. == "AGE WHITELISTED") + return AGEBAN + else if (.) + return RANBAN + return NOBAN /datum/category_item/player_setup_item/antagonism/candidacy/OnTopic(var/href,var/list/href_list, var/mob/user) if(href_list["add_special"]) @@ -96,3 +114,7 @@ private_valid_special_roles += ghost_trap.pref_check return private_valid_special_roles + +#undef AGEBAN +#undef RANBAN +#undef NOBAN diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm index 335ba9609f0..7d11f5b490e 100644 --- a/code/modules/client/preference_setup/occupation/occupation.dm +++ b/code/modules/client/preference_setup/occupation/occupation.dm @@ -126,13 +126,17 @@ . += "" var/rank = job.title lastJob = job - if(jobban_isbanned(user, rank)) - . += "[rank] \[BANNED]" + var/ban_reason = jobban_isbanned(user, rank) + if(ban_reason == "WHITELISTED") + . += "[rank] \[WHITELISTED]" continue - if(!job.player_old_enough(user.client)) - var/available_in_days = job.available_in_days(user.client) + else if (ban_reason == "AGE WHITELISTED") + var/available_in_days = player_old_enough_for_role(user.client, rank) . += "[rank] \[IN [(available_in_days)] DAYS]" continue + else if (ban_reason) + . += "[rank] \[BANNED]" + continue if((pref.job_civilian_low & ASSISTANT) && (rank != "Assistant")) . += "[rank]" continue diff --git a/code/modules/ext_scripts/discord.dm b/code/modules/ext_scripts/discord.dm deleted file mode 100644 index 24fddb5788b..00000000000 --- a/code/modules/ext_scripts/discord.dm +++ /dev/null @@ -1,33 +0,0 @@ -#define CHAN_ADMIN "admin_channel" -#define CHAN_CCIAA "cciaa_channel" - -/proc/send_to_discord(var/channel, var/message) - if (!config.use_discord_bot) - return - if (!channel) - log_game("send_to_discord() called without channel arg.") - return - if (!message) - log_game("send_to_discord() called without message arg.") - return - - var/arguments = " --key=\"[config.comms_password]\"" - arguments += " --channel=\"[channel]\"" - if (config.discord_bot_host) - arguments += " --host=\"[config.discord_bot_host]\"" - if (config.discord_bot_port) - arguments += " --port=[config.discord_bot_port]" - - message = replacetext(message, "\"", "\\\"") - - ext_python("discordbot_message.py", "[arguments] [message]") - return - -/proc/send_to_admin_discord(var/message) - send_to_discord(CHAN_ADMIN, message) - -/proc/send_to_cciaa_discord(var/message) - send_to_discord(CHAN_CCIAA, message) - -#undef CHAN_CCIAA -#undef CHAN_ADMIN diff --git a/code/modules/ext_scripts/github.dm b/code/modules/ext_scripts/github.dm deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/code/modules/ext_scripts/irc.dm b/code/modules/ext_scripts/irc.dm deleted file mode 100644 index 79753165088..00000000000 --- a/code/modules/ext_scripts/irc.dm +++ /dev/null @@ -1,35 +0,0 @@ -/proc/send2irc(var/channel, var/msg) - if(config.use_irc_bot && config.irc_bot_host) - if(config.irc_bot_export) - spawn(-1) // spawn here prevents hanging in the case that the bot isn't reachable - world.Export("http://[config.irc_bot_host]:45678?[list2params(list(pwd=config.comms_password, chan=channel, mesg=msg))]") - else - if(config.use_lib_nudge) - var/nudge_lib - if(world.system_type == MS_WINDOWS) - nudge_lib = "lib\\nudge.dll" - else - nudge_lib = "lib/nudge.so" - - spawn(0) - call(nudge_lib, "nudge")("[config.comms_password]","[config.irc_bot_host]","[channel]","[msg]") - else - spawn(0) - ext_python("ircbot_message.py", "[config.comms_password] [config.irc_bot_host] [channel] [msg]") - return - -/proc/send2mainirc(var/msg) - if(config.main_irc) - send2irc(config.main_irc, msg) - return - -/proc/send2adminirc(var/msg) - if(config.admin_irc) - send2irc(config.admin_irc, msg) - return - - -/hook/startup/proc/ircNotify() - send2mainirc("Server starting up on byond://[config.serverurl ? config.serverurl : (config.server ? config.server : "[world.address]:[world.port]")]") - return 1 - diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 1a487bc2cfe..70091d3f6a5 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -310,7 +310,6 @@ if(!job) return 0 if(!job.is_position_available()) return 0 if(jobban_isbanned(src,rank)) return 0 - if(!job.player_old_enough(src.client)) return 0 return 1 diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index ba25f2d0ea1..6ce3a419196 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -320,11 +320,27 @@ var/list/admin_departments = list("[boss_name]", "Tau Ceti Government", "Supply" /obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/obj/item/sent, var/reply_type, font_colour="#006100") var/msg = " [faxname]: [key_name(sender, 1)] (PP) (VV) (SM) (JMP) (CA) (REPLY): Receiving '[sent.name]' via secure connection ... view message" + var/cciaa_present = 0 + var/cciaa_afk = 0 for(var/client/C in admins) - if((R_ADMIN|R_CCIAA) & C.holder.rights) + var/flags = C.holder.rights & (R_ADMIN|R_CCIAA) + if(flags) C << msg + if (flags == R_CCIAA) // Admins sometimes get R_CCIAA, but CCIAA never get R_ADMIN + cciaa_present++ + if (C.is_afk()) + cciaa_afk++ - discord_bot.send_to_cciaa("New fax arrived! [faxname]: \"[sent.name]\" by [sender].") + var/discord_msg = "New fax arrived! [faxname]: \"[sent.name]\" by [sender]. ([cciaa_present] agents online" + if (cciaa_present) + if ((cciaa_present - cciaa_afk) <= 0) + discord_msg += ", **all AFK!**)" + else + discord_msg += ", [cciaa_afk] AFK.)" + else + discord_msg += ".)" + + discord_bot.send_to_cciaa(discord_msg) /obj/machinery/photocopier/faxmachine/proc/do_pda_alerts() if (!alert_pdas || !alert_pdas.len) diff --git a/code/world.dm b/code/world.dm index e335a07e09d..871a363a0bd 100644 --- a/code/world.dm +++ b/code/world.dm @@ -247,7 +247,7 @@ var/inerror = 0 config.load("config/config.txt") config.load("config/game_options.txt","game_options") - if (config.use_age_restriction_for_jobs) + if (config.use_age_restriction_for_jobs || config.use_age_restriction_for_antags) config.load("config/age_restrictions.txt", "age_restrictions") /hook/startup/proc/loadMods() diff --git a/config/example/age_restrictions.txt b/config/example/age_restrictions.txt index 1a197d9109d..6442cf8a79b 100644 --- a/config/example/age_restrictions.txt +++ b/config/example/age_restrictions.txt @@ -57,19 +57,24 @@ Cyborg 0 pAI_candidate 0 positronic_brain 0 -#This is fetched from the special_roles global list. +#Misc +Dionaea 0 + +#This is fetched from the unique bantypes list. +#One entry can effect multiple antag roles! #Antags traitor 0 +Borer 0 +Xenomorph 0 +Syndicate 0 +actor 0 +Emergency_Response_Team 0 operative 0 -changeling 0 -wizard 0 -malf_AI 0 -revolutionary 0 -alien_candidate 0 -cultist 0 -infested_monkey 0 ninja 0 raider 0 -diona 0 +wizard 0 +changeling 0 +cultist 0 loyalist 0 -vampire 0 +revolutionary 0 +vampires 0 diff --git a/config/example/config.txt b/config/example/config.txt index 6594583b885..4f66a31f001 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -209,10 +209,6 @@ GUEST_BAN ## set a server location for world reboot. Don't include the byond://, just give the address and port. #SERVER server.net:port -## set a server URL for the IRC bot to use; like SERVER, don't include the byond:// -## Unlike SERVER, this one shouldn't break auto-reconnect -#SERVERURL server.net:port - ## forum address # FORUMURL http://example.com @@ -250,12 +246,6 @@ TICKLAG 0.9 ## Defines if Tick Compensation is used. It results in a minor slowdown of movement of all mobs, but attempts to result in a level movement speed across all ticks. Recommended if tickrate is lowered. TICKCOMP 0 -## Whether the server will talk to other processes through socket_talk -SOCKET_TALK 0 - -## Uncomment this to ban use of ToR -#TOR_BAN - ## Comment this out to disable automuting #AUTOMUTE_ON @@ -289,17 +279,10 @@ NL_START_HOUR 19 ##Remove the # to let ghosts spin chairs #GHOST_INTERACTION -## Password used for authorizing ircbot and other external tools. -#COMMS_PASSWORD - ## Path to the python2 executable on the system. Leave blank for default. ## Default is "python" on Windows, "/usr/bin/env python2" on UNIX. #PYTHON_PATH -## Uncomment to use the C library nudge instead of the python script. -## This helps security and stability on Linux, but you need to compile the library first. -#USE_LIB_NUDGE - ## Uncommen to allow ghosts to write in blood during Cult rounds. ALLOW_CULT_GHOSTWRITER @@ -408,15 +391,6 @@ STARLIGHT 0 ## Uncomment this to house player preferences and characters on the SQL database. # SQL_SAVES -## Uncomment this to use the discord bot. -# USE_DISCORD_BOT - -## The host address of the discord bot. -# DISCORD_BOT_HOST - -## The port number which the discord bot is listening for nudges. -# DISCORD_BOT_PORT - ## Uncomment this and fill in the web interface's URL to use the web interface. # WEBINT_URL http://www.address.com/ diff --git a/config/example/discord.txt b/config/example/discord.txt index ea66b2cc9ab..cedbf958b55 100644 --- a/config/example/discord.txt +++ b/config/example/discord.txt @@ -10,3 +10,6 @@ ## The subscriber role ID goes here. # SUBSCRIBER + +## Toggles if the bot should alert staff in case the server is started as invisible. +# ALERT_VISIBILITY diff --git a/html/changelogs/skull132-adminstuff.yml b/html/changelogs/skull132-adminstuff.yml new file mode 100644 index 00000000000..8b0c0dbd614 --- /dev/null +++ b/html/changelogs/skull132-adminstuff.yml @@ -0,0 +1,7 @@ +author: Skull132 +delete-after: True + +changes: + - rscadd: "You can now view the reason for your active job ban by clicking on the [BANNED] text on job/role selection." + - tweak: "Whitelisted jobs now display as [WHITELISTED] instead of [BANNED] if you are short a whitelist." + - tweak: "A restart vote can no longer be called if there are active admins on the server. They will be notified of your attempt, however." diff --git a/lib/DLLSocket/DLLSocket.cbp b/lib/DLLSocket/DLLSocket.cbp deleted file mode 100644 index 6415a5ebd67..00000000000 --- a/lib/DLLSocket/DLLSocket.cbp +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - diff --git a/lib/DLLSocket/compile.sh b/lib/DLLSocket/compile.sh deleted file mode 100644 index 0ff309bdb9f..00000000000 --- a/lib/DLLSocket/compile.sh +++ /dev/null @@ -1 +0,0 @@ -g++ -static -shared -O3 -fPIC main.cpp -o DLLSocket.so diff --git a/lib/DLLSocket/main.cpp b/lib/DLLSocket/main.cpp deleted file mode 100644 index e3aafb8791a..00000000000 --- a/lib/DLLSocket/main.cpp +++ /dev/null @@ -1,133 +0,0 @@ -// OS-specific networking includes -// ------------------------------- -#ifdef __WIN32 - #include - typedef int socklen_t; -#else - extern "C" { - #include - #include - #include - #include - #include - #include - #include - #include - } - - typedef int SOCKET; - typedef sockaddr_in SOCKADDR_IN; - typedef sockaddr SOCKADDR; - #define SOCKET_ERROR -1 -#endif - -// Socket used for all communications -SOCKET sock; - -// Address of the remote server -SOCKADDR_IN addr; - -// Buffer used to return dynamic strings to the caller -#define BUFFER_SIZE 1024 -char return_buffer[BUFFER_SIZE]; - -// exposed functions -// ------------------------------ - -const char* SUCCESS = "1\0"; // string representing success - -#ifdef __WIN32 - #define DLL_EXPORT __declspec(dllexport) -#else - #define DLL_EXPORT __attribute__ ((visibility ("default"))) -#endif - -// arg1: ip(in the xx.xx.xx.xx format) -// arg2: port(a short) -// return: NULL on failure, SUCCESS otherwise -extern "C" DLL_EXPORT const char* establish_connection(int n, char *v[]) -{ - // extract args - // ------------ - if(n < 2) return 0; - const char* ip = v[0]; - const char* port_s = v[1]; - unsigned short port = atoi(port_s); - - // set up network stuff - // -------------------- - #ifdef __WIN32 - WSADATA wsa; - WSAStartup(MAKEWORD(2,0),&wsa); - #endif - sock = socket(AF_INET,SOCK_DGRAM,0); - - // make the socket non-blocking - // ---------------------------- - #ifdef __WIN32 - unsigned long iMode=1; - ioctlsocket(sock,FIONBIO,&iMode); - #else - fcntl(sock, F_SETFL, O_NONBLOCK); - #endif - - // establish a connection to the server - // ------------------------------------ - memset(&addr,0,sizeof(SOCKADDR_IN)); - addr.sin_family=AF_INET; - addr.sin_port=htons(port); - - // convert the string representation of the ip to a byte representation - addr.sin_addr.s_addr=inet_addr(ip); - - return SUCCESS; -} - -// arg1: string message to send -// return: NULL on failure, SUCCESS otherwise -extern "C" DLL_EXPORT const char* send_message(int n, char *v[]) -{ - // extract the args - if(n < 1) return 0; - const char* msg = v[0]; - - // send the message - int rc = sendto(sock,msg,strlen(msg),0,(SOCKADDR*)&addr,sizeof(SOCKADDR)); - - // check for errors - if (rc != -1) { - return SUCCESS; - } - else { - return 0; - } -} - -// no args -// return: message if any received, NULL otherwise -extern "C" DLL_EXPORT const char* recv_message(int n, char *v[]) -{ - SOCKADDR_IN sender; // we will store the sender address here - - socklen_t sender_byte_length = sizeof(sender); - - // Try receiving messages until we receive one that's valid, or there are no more messages - while(1) { - int rc = recvfrom(sock, return_buffer, BUFFER_SIZE,0,(SOCKADDR*) &sender,&sender_byte_length); - if(rc > 0) { - // we could read something - - if(sender.sin_addr.s_addr != addr.sin_addr.s_addr) { - continue; // not our connection, ignore and try again - } else { - return_buffer[rc] = 0; // 0-terminate the string - return return_buffer; - } - } - else { - break; // no more messages, stop trying to receive - } - } - - return 0; -} diff --git a/lib/DLLSocket/server_controller.py b/lib/DLLSocket/server_controller.py deleted file mode 100644 index 943f37f6777..00000000000 --- a/lib/DLLSocket/server_controller.py +++ /dev/null @@ -1,51 +0,0 @@ -import subprocess -import socket -import urlparse - -UDP_IP="127.0.0.1" -UDP_PORT=8019 - -sock = socket.socket( socket.AF_INET, # Internet - socket.SOCK_DGRAM ) # UDP -sock.bind( (UDP_IP,UDP_PORT) ) - -last_ticker_state = None - -def handle_message(data, addr): - global last_ticker_state - - params = urlparse.parse_qs(data) - print(data) - - try: - if params["type"][0] == "log" and str(params["log"][0]) and str(params["message"][0]): - open(params["log"][0],"a+").write(params["message"][0]+"\n") - except IOError: - pass - except KeyError: - pass - - try: - if params["type"][0] == "ticker_state" and str(params["message"][0]): - last_ticker_state = str(params["message"][0]) - except KeyError: - pass - - try: - if params["type"][0] == "startup" and last_ticker_state: - open("crashlog.txt","a+").write("Server exited, last ticker state was: "+last_ticker_state+"\n") - except KeyError: - pass - -sock.settimeout(60*6) # 10 minute timeout -while True: - try: - data, addr = sock.recvfrom( 1024 ) # buffer size is 1024 bytes - handle_message(data,addr) - except socket.timeout: - # try to start the server again - print("Server timed out.. attempting restart.") - if last_ticker_state: - open("crashmsg.txt","a+").write("Server crashed, trying to reboot. last ticker state: "+last_ticker_state+"\n") - subprocess.call("killall -9 DreamDaemon") - subprocess.call("./start") \ No newline at end of file diff --git a/lib/src/netutil.c b/lib/src/netutil.c deleted file mode 100644 index 4028e89b5e0..00000000000 --- a/lib/src/netutil.c +++ /dev/null @@ -1,109 +0,0 @@ -#include "netutil.h" -#include "string.h" - -int net_ready = 0; -void net_init() -{ - #ifdef _WIN32 - WSADATA wsa; - WSAStartup(MAKEWORD(2,0),&wsa); - #endif - net_ready = 1; -} - -socket_t connect_sock(char * host, char * port) -{ - if(!net_ready) - { - net_init(); - } - - socket_t out_sock = -1; - struct addrinfo addr_in; - struct addrinfo * addr_proc; - int gai_status; - - memset(&addr_in, 0, sizeof(addr_in)); - - addr_in.ai_family = AF_UNSPEC; - addr_in.ai_socktype = SOCK_STREAM; - addr_in.ai_flags = AI_PASSIVE; - - gai_status = getaddrinfo(host, port, &addr_in, &addr_proc); - - if(gai_status) - { - return -1; - } - - struct addrinfo * ai_p; - for(ai_p = addr_proc; ai_p != 0; ai_p = ai_p->ai_next) - { - out_sock = socket(ai_p->ai_family, ai_p->ai_socktype, - ai_p->ai_protocol); - - if((int)out_sock == -1) - { - continue; - } - else if(connect(out_sock, ai_p->ai_addr, ai_p->ai_addrlen) == -1) - { - close_socket(out_sock); - continue; - } - else - { - break; - } - } - - if(!out_sock) - { - freeaddrinfo(addr_proc); - return -1; - } - - freeaddrinfo(addr_proc); - return out_sock; -} - -void send_n(socket_t sock, const char * buf, size_t n) -{ - size_t to_send = n; - const char * buf_i = buf; - while(to_send) - { - int sent = send(sock, buf_i, to_send, 0); - if(sent != -1) - { - to_send -= sent; - buf_i += sent; - } - else - { - return; - } - } - return; -} - -void recv_n(socket_t sock, char * buf, size_t n) -{ - size_t total = 0; - char * buf_i = buf; - while(total < n) - { - int recved = recv(sock, buf_i, n - total, 0); - if(recved > 0) - { - total += recved; - buf_i += recved; - } - else - { - return; - } - } - return; -} - diff --git a/lib/src/netutil.h b/lib/src/netutil.h deleted file mode 100644 index 6e97b1e3fab..00000000000 --- a/lib/src/netutil.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef NETUTIL_H -#define NETUTIL_H - -#ifdef _WIN32 - -#include -#include -typedef SOCKET socket_t; - -#define close_socket(sock) closesocket(sock) - -#else - -#include -#include -#include -#include -typedef int socket_t; - -#define close_socket(sock) close(sock) - -#endif - -extern int net_ready; -void init_net(); - -socket_t connect_sock(char * host, char * port); - -void send_n(socket_t sock, const char * buf, size_t n); -void recv_n(socket_t sock, char * buf, size_t n); - -#endif - diff --git a/lib/src/nudge.c b/lib/src/nudge.c deleted file mode 100644 index d9efb90b73f..00000000000 --- a/lib/src/nudge.c +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include - -#include "netutil.h" - -#ifdef _WIN32 - #define DLL_EXPORT __declspec(dllexport) -#else - #define DLL_EXPORT __attribute__ ((visibility ("default"))) -#endif - -size_t san_c(const char * input) -{ - unsigned int count = strlen(input); - - const char * i; - for(i = input; *i; i++) - { - if(*i == '\\' || *i == '\'') - { - count++; - } - } - - return count; -} - -char * san_cpy(char * out_buf, const char * in_buf) -{ - const char * i_in = in_buf; - char * i_out = out_buf; - while(*i_in) - { - if(*i_in == '\\' || *i_in == '\'') - { - *(i_out++) = '\\'; - } - *(i_out++) = *(i_in++); - } - return i_out; -} - -DLL_EXPORT const char * nudge(int n, char *v[]) -{ - if(n != 4) - { - return ""; - } - - size_t out_c = san_c(v[0]) + san_c(v[2]) + san_c(v[3]); - - char * san_out = malloc(out_c + 57); - - char * san_i = san_out; - strcpy(san_i, "(dp1\nS'ip'\np2\nS'"); - san_i += 16; - san_i = san_cpy(san_i, v[2]); - strcpy(san_i, "'\np3\nsS'data'\np4\n(lp5\nS'"); - san_i += 24; - san_i = san_cpy(san_i, v[0]); - strcpy(san_i, "'\np6\naS'"); - san_i += 8; - san_i = san_cpy(san_i, v[3]); - strcpy(san_i, "'\np7\nas."); - - socket_t nudge_sock = connect_sock(v[1], "45678"); - send_n(nudge_sock, san_out, out_c + 56); - close_socket(nudge_sock); - - free(san_out); - - return "1"; -} - diff --git a/scripts/discordbot_message.py b/scripts/discordbot_message.py deleted file mode 100644 index f6162a808a2..00000000000 --- a/scripts/discordbot_message.py +++ /dev/null @@ -1,49 +0,0 @@ -# nudge.py --channel="nudges|ahelps" --id="Server ID" --key="access key" Message! More message! -# Credit to the gents at VGStation13/N3XIS for this code. - -import sys -import pickle -import socket -import argparse -import html - -def pack(host, port, key, channel, message): - - data = {} - - data['key'] = key - data['channel'] = channel - - try: - d = [] - for in_data in message: # The rest of the arguments is data - d += [html.unescape(in_data)] - data['data'] = ' '.join(d) - - # Buffer overflow prevention. - if len(data['data']) > 400: - data['data'] = data['data'][:400] - except: - data['data'] = "NO DATA SPECIFIED" - pickled = pickle.dumps(data) - nudge(host, port, pickled) - -def nudge(hostname, port, data): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((hostname, port)) - s.send(data) - s.close() - -if __name__ == "__main__" and len(sys.argv) > 1: # If not imported and more than one argument - argp = argparse.ArgumentParser() - - argp.add_argument('message', nargs='*', type=str, help='String to send to the server.') - - argp.add_argument('--host', dest='hostname', default='localhost', help='Hostname expecting a nudge.') - argp.add_argument('--port', dest='port', type=int, default=5555, help='Port expecting a nudge.') - argp.add_argument('--channel', dest='channel', default='lobby', help='Channel flag to direct this message to.') - argp.add_argument('--key', dest='key', default='', help='Access key of the bot or receiving script.') - - args = argp.parse_args() - - pack(args.hostname, args.port, args.key, args.channel, args.message)