aboutsummaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authoroldmud0 <oldmud0@users.noreply.github.com>2018-11-10 23:15:54 -0600
committeroldmud0 <oldmud0@users.noreply.github.com>2018-11-10 23:15:54 -0600
commitde348c22d5f1287cc38734e6e3b77fc492629721 (patch)
treea0c57e47c29404ce1312bebf9528fdf0c62b2615 /server
parent56ec03a23a0f687b79d3ce324e517563a41c0032 (diff)
Coalesce server changes into patch file (this is not a monorepo)
Diffstat (limited to 'server')
-rw-r--r--server/__init__.py0
-rw-r--r--server/aoprotocol.py807
-rw-r--r--server/area_manager.py412
-rw-r--r--server/ban_manager.py54
-rw-r--r--server/client_manager.py457
-rw-r--r--server/commands.py1255
-rw-r--r--server/constants.py11
-rw-r--r--server/districtclient.py79
-rw-r--r--server/evidence.py100
-rw-r--r--server/exceptions.py32
-rw-r--r--server/fantacrypt.py45
-rw-r--r--server/logger.py78
-rw-r--r--server/masterserverclient.py89
-rw-r--r--server/tsuserver.py305
-rw-r--r--server/websocket.py215
15 files changed, 0 insertions, 3939 deletions
diff --git a/server/__init__.py b/server/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/server/__init__.py
+++ /dev/null
diff --git a/server/aoprotocol.py b/server/aoprotocol.py
deleted file mode 100644
index 2cf6fb43..00000000
--- a/server/aoprotocol.py
+++ /dev/null
@@ -1,807 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import asyncio
-import re
-from time import localtime, strftime
-from enum import Enum
-
-from . import commands
-from . import logger
-from .exceptions import ClientError, AreaError, ArgumentError, ServerError
-from .fantacrypt import fanta_decrypt
-from .evidence import EvidenceList
-from .websocket import WebSocket
-import unicodedata
-
-
-class AOProtocol(asyncio.Protocol):
- """
- The main class that deals with the AO protocol.
- """
-
- class ArgType(Enum):
- STR = 1,
- STR_OR_EMPTY = 2,
- INT = 3
-
- def __init__(self, server):
- super().__init__()
- self.server = server
- self.client = None
- self.buffer = ''
- self.ping_timeout = None
- self.websocket = None
-
- def data_received(self, data):
- """ Handles any data received from the network.
-
- Receives data, parses them into a command and passes it
- to the command handler.
-
- :param data: bytes of data
- """
-
-
- if self.websocket is None:
- self.websocket = WebSocket(self.client, self)
- if not self.websocket.handshake(data):
- self.websocket = False
- else:
- self.client.websocket = self.websocket
-
- buf = data
-
- if not self.client.is_checked and self.server.ban_manager.is_banned(self.client.ipid):
- self.client.transport.close()
- else:
- self.client.is_checked = True
-
- if self.websocket:
- buf = self.websocket.handle(data)
-
- if buf is None:
- buf = b''
-
- if not isinstance(buf, str):
- # try to decode as utf-8, ignore any erroneous characters
- self.buffer += buf.decode('utf-8', 'ignore')
- else:
- self.buffer = buf
-
- if len(self.buffer) > 8192:
- self.client.disconnect()
- for msg in self.get_messages():
- if len(msg) < 2:
- continue
- # general netcode structure is not great
- if msg[0] in ('#', '3', '4'):
- if msg[0] == '#':
- msg = msg[1:]
- spl = msg.split('#', 1)
- msg = '#'.join([fanta_decrypt(spl[0])] + spl[1:])
- logger.log_debug('[INC][RAW]{}'.format(msg), self.client)
- try:
- cmd, *args = msg.split('#')
- self.net_cmd_dispatcher[cmd](self, args)
- except KeyError:
- logger.log_debug('[INC][UNK]{}'.format(msg), self.client)
-
- def connection_made(self, transport):
- """ Called upon a new client connecting
-
- :param transport: the transport object
- """
- self.client = self.server.new_client(transport)
- self.ping_timeout = asyncio.get_event_loop().call_later(self.server.config['timeout'], self.client.disconnect)
- asyncio.get_event_loop().call_later(0.25, self.client.send_command, 'decryptor', 34) # just fantacrypt things)
-
- def connection_lost(self, exc):
- """ User disconnected
-
- :param exc: reason
- """
- self.server.remove_client(self.client)
- self.ping_timeout.cancel()
-
- def get_messages(self):
- """ Parses out full messages from the buffer.
-
- :return: yields messages
- """
- while '#%' in self.buffer:
- spl = self.buffer.split('#%', 1)
- self.buffer = spl[1]
- yield spl[0]
- # exception because bad netcode
- askchar2 = '#615810BC07D12A5A#'
- if self.buffer == askchar2:
- self.buffer = ''
- yield askchar2
-
- def validate_net_cmd(self, args, *types, needs_auth=True):
- """ Makes sure the net command's arguments match expectations.
-
- :param args: actual arguments to the net command
- :param types: what kind of data types are expected
- :param needs_auth: whether you need to have chosen a character
- :return: returns True if message was validated
- """
- if needs_auth and self.client.char_id == -1:
- return False
- if len(args) != len(types):
- return False
- for i, arg in enumerate(args):
- if len(arg) == 0 and types[i] != self.ArgType.STR_OR_EMPTY:
- return False
- if types[i] == self.ArgType.INT:
- try:
- args[i] = int(arg)
- except ValueError:
- return False
- return True
-
- def net_cmd_hi(self, args):
- """ Handshake.
-
- HI#<hdid:string>#%
-
- :param args: a list containing all the arguments
- """
- if not self.validate_net_cmd(args, self.ArgType.STR, needs_auth=False):
- return
- self.client.hdid = args[0]
- if self.client.hdid not in self.client.server.hdid_list:
- self.client.server.hdid_list[self.client.hdid] = []
- if self.client.ipid not in self.client.server.hdid_list[self.client.hdid]:
- self.client.server.hdid_list[self.client.hdid].append(self.client.ipid)
- self.client.server.dump_hdids()
- for ipid in self.client.server.hdid_list[self.client.hdid]:
- if self.server.ban_manager.is_banned(ipid):
- self.client.send_command('BD')
- self.client.disconnect()
- return
- logger.log_server('Connected. HDID: {}.'.format(self.client.hdid), self.client)
- self.client.send_command('ID', self.client.id, self.server.software, self.server.get_version_string())
- self.client.send_command('PN', self.server.get_player_count() - 1, self.server.config['playerlimit'])
-
- def net_cmd_id(self, args):
- """ Client version and PV
-
- ID#<pv:int>#<software:string>#<version:string>#%
-
- """
-
- self.client.is_ao2 = False
-
- if len(args) < 2:
- return
-
- version_list = args[1].split('.')
-
- if len(version_list) < 3:
- return
-
- release = int(version_list[0])
- major = int(version_list[1])
- minor = int(version_list[2])
-
- if args[0] != 'AO2':
- return
- if release < 2:
- return
- elif release == 2:
- if major < 2:
- return
- elif major == 2:
- if minor < 5:
- return
-
- self.client.is_ao2 = True
-
- self.client.send_command('FL', 'yellowtext', 'customobjections', 'flipping', 'fastloading', 'noencryption', 'deskmod', 'evidence', 'modcall_reason', 'cccc_ic_support', 'arup', 'casing_alerts')
-
- def net_cmd_ch(self, _):
- """ Periodically checks the connection.
-
- CHECK#%
-
- """
- self.client.send_command('CHECK')
- self.ping_timeout.cancel()
- self.ping_timeout = asyncio.get_event_loop().call_later(self.server.config['timeout'], self.client.disconnect)
-
- def net_cmd_askchaa(self, _):
- """ Ask for the counts of characters/evidence/music
-
- askchaa#%
-
- """
- char_cnt = len(self.server.char_list)
- evi_cnt = 0
- music_cnt = sum([len(x) for x in self.server.music_pages_ao1])
- self.client.send_command('SI', char_cnt, evi_cnt, music_cnt)
-
- def net_cmd_askchar2(self, _):
- """ Asks for the character list.
-
- askchar2#%
-
- """
- self.client.send_command('CI', *self.server.char_pages_ao1[0])
-
- def net_cmd_an(self, args):
- """ Asks for specific pages of the character list.
-
- AN#<page:int>#%
-
- """
- if not self.validate_net_cmd(args, self.ArgType.INT, needs_auth=False):
- return
- if len(self.server.char_pages_ao1) > args[0] >= 0:
- self.client.send_command('CI', *self.server.char_pages_ao1[args[0]])
- else:
- self.client.send_command('EM', *self.server.music_pages_ao1[0])
-
- def net_cmd_ae(self, _):
- """ Asks for specific pages of the evidence list.
-
- AE#<page:int>#%
-
- """
- pass # todo evidence maybe later
-
- def net_cmd_am(self, args):
- """ Asks for specific pages of the music list.
-
- AM#<page:int>#%
-
- """
- if not self.validate_net_cmd(args, self.ArgType.INT, needs_auth=False):
- return
- if len(self.server.music_pages_ao1) > args[0] >= 0:
- self.client.send_command('EM', *self.server.music_pages_ao1[args[0]])
- else:
- self.client.send_done()
- self.client.send_area_list()
- self.client.send_motd()
-
- def net_cmd_rc(self, _):
- """ Asks for the whole character list(AO2)
-
- AC#%
-
- """
-
- self.client.send_command('SC', *self.server.char_list)
-
- def net_cmd_rm(self, _):
- """ Asks for the whole music list(AO2)
-
- AM#%
-
- """
-
- self.client.send_command('SM', *self.server.music_list_ao2)
-
-
- def net_cmd_rd(self, _):
- """ Asks for server metadata(charscheck, motd etc.) and a DONE#% signal(also best packet)
-
- RD#%
-
- """
-
- self.client.send_done()
- self.client.send_area_list()
- self.client.send_motd()
-
- def net_cmd_cc(self, args):
- """ Character selection.
-
- CC#<client_id:int>#<char_id:int>#<hdid:string>#%
-
- """
- if not self.validate_net_cmd(args, self.ArgType.INT, self.ArgType.INT, self.ArgType.STR, needs_auth=False):
- return
- cid = args[1]
- try:
- self.client.change_character(cid)
- except ClientError:
- return
-
- def net_cmd_ms(self, args):
- """ IC message.
-
- Refer to the implementation for details.
-
- """
- if self.client.is_muted: # Checks to see if the client has been muted by a mod
- self.client.send_host_message("You have been muted by a moderator")
- return
- if not self.client.area.can_send_message(self.client):
- return
-
- target_area = []
-
- if self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, self.ArgType.STR,
- self.ArgType.STR,
- self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT,
- self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT,
- self.ArgType.INT, self.ArgType.INT, self.ArgType.INT):
- # Vanilla validation monstrosity.
- msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color = args
- showname = ""
- charid_pair = -1
- offset_pair = 0
- nonint_pre = 0
- elif self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, self.ArgType.STR,
- self.ArgType.STR,
- self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT,
- self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT,
- self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.STR_OR_EMPTY):
- # 1.3.0 validation monstrosity.
- msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname = args
- charid_pair = -1
- offset_pair = 0
- nonint_pre = 0
- if len(showname) > 0 and not self.client.area.showname_changes_allowed:
- self.client.send_host_message("Showname changes are forbidden in this area!")
- return
- elif self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, self.ArgType.STR,
- self.ArgType.STR,
- self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT,
- self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT,
- self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT, self.ArgType.INT):
- # 1.3.5 validation monstrosity.
- msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair = args
- nonint_pre = 0
- if len(showname) > 0 and not self.client.area.showname_changes_allowed:
- self.client.send_host_message("Showname changes are forbidden in this area!")
- return
- elif self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, self.ArgType.STR,
- self.ArgType.STR,
- self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT,
- self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT,
- self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT):
- # 1.4.0 validation monstrosity.
- msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre = args
- if len(showname) > 0 and not self.client.area.showname_changes_allowed:
- self.client.send_host_message("Showname changes are forbidden in this area!")
- return
- else:
- return
- if self.client.area.is_iniswap(self.client, pre, anim, folder) and folder != self.client.get_char_name():
- self.client.send_host_message("Iniswap is blocked in this area")
- return
- if len(self.client.charcurse) > 0 and folder != self.client.get_char_name():
- self.client.send_host_message("You may not iniswap while you are charcursed!")
- return
- if not self.client.area.blankposting_allowed:
- if text == ' ':
- self.client.send_host_message("Blankposting is forbidden in this area!")
- return
- if text.isspace():
- self.client.send_host_message("Blankposting is forbidden in this area, and putting more spaces in does not make it not blankposting.")
- return
- if len(re.sub(r'[{}\\`|(~~)]','', text).replace(' ', '')) < 3 and text != '<' and text != '>':
- self.client.send_host_message("While that is not a blankpost, it is still pretty spammy. Try forming sentences.")
- return
- if text.startswith('/a '):
- part = text.split(' ')
- try:
- aid = int(part[1])
- if self.client in self.server.area_manager.get_area_by_id(aid).owners:
- target_area.append(aid)
- if not target_area:
- self.client.send_host_message('You don\'t own {}!'.format(self.server.area_manager.get_area_by_id(aid).name))
- return
- text = ' '.join(part[2:])
- except ValueError:
- self.client.send_host_message("That does not look like a valid area ID!")
- return
- elif text.startswith('/s '):
- part = text.split(' ')
- for a in self.server.area_manager.areas:
- if self.client in a.owners:
- target_area.append(a.id)
- if not target_area:
- self.client.send_host_message('You don\'t any areas!')
- return
- text = ' '.join(part[1:])
- if msg_type not in ('chat', '0', '1'):
- return
- if anim_type not in (0, 1, 2, 5, 6):
- return
- if cid != self.client.char_id:
- return
- if sfx_delay < 0:
- return
- if button not in (0, 1, 2, 3, 4):
- return
- if evidence < 0:
- return
- if ding not in (0, 1):
- return
- if color not in (0, 1, 2, 3, 4, 5, 6, 7, 8):
- return
- if len(showname) > 15:
- self.client.send_host_message("Your IC showname is way too long!")
- return
- if nonint_pre == 1:
- if button in (1, 2, 3, 4, 23):
- if anim_type == 1 or anim_type == 2:
- anim_type = 0
- elif anim_type == 6:
- anim_type = 5
- if self.client.area.non_int_pres_only:
- if anim_type == 1 or anim_type == 2:
- anim_type = 0
- nonint_pre = 1
- elif anim_type == 6:
- anim_type = 5
- nonint_pre = 1
- if not self.client.area.shouts_allowed:
- # Old clients communicate the objecting in anim_type.
- if anim_type == 2:
- anim_type = 1
- elif anim_type == 6:
- anim_type = 5
- # New clients do it in a specific objection message area.
- button = 0
- # Turn off the ding.
- ding = 0
- if color == 2 and not (self.client.is_mod or self.client in self.client.area.owners):
- color = 0
- if color == 6:
- text = re.sub(r'[^\x00-\x7F]+',' ', text) #remove all unicode to prevent redtext abuse
- if len(text.strip( ' ' )) == 1:
- color = 0
- else:
- if text.strip( ' ' ) in ('<num>', '<percent>', '<dollar>', '<and>'):
- color = 0
- if self.client.pos:
- pos = self.client.pos
- else:
- if pos not in ('def', 'pro', 'hld', 'hlp', 'jud', 'wit', 'jur', 'sea'):
- return
- msg = text[:256]
- if self.client.shaken:
- msg = self.client.shake_message(msg)
- if self.client.disemvowel:
- msg = self.client.disemvowel_message(msg)
- self.client.pos = pos
- if evidence:
- if self.client.area.evi_list.evidences[self.client.evi_list[evidence] - 1].pos != 'all':
- self.client.area.evi_list.evidences[self.client.evi_list[evidence] - 1].pos = 'all'
- self.client.area.broadcast_evidence_list()
-
- # Here, we check the pair stuff, and save info about it to the client.
- # Notably, while we only get a charid_pair and an offset, we send back a chair_pair, an emote, a talker offset
- # and an other offset.
- self.client.charid_pair = charid_pair
- self.client.offset_pair = offset_pair
- if anim_type not in (5, 6):
- self.client.last_sprite = anim
- self.client.flip = flip
- self.client.claimed_folder = folder
- other_offset = 0
- other_emote = ''
- other_flip = 0
- other_folder = ''
-
- confirmed = False
- if charid_pair > -1:
- for target in self.client.area.clients:
- if target.char_id == self.client.charid_pair and target.charid_pair == self.client.char_id and target != self.client and target.pos == self.client.pos:
- confirmed = True
- other_offset = target.offset_pair
- other_emote = target.last_sprite
- other_flip = target.flip
- other_folder = target.claimed_folder
- break
-
- if not confirmed:
- charid_pair = -1
- offset_pair = 0
-
- self.client.area.send_command('MS', msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid,
- sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname,
- charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre)
-
- self.client.area.send_owner_command('MS', msg_type, pre, folder, anim, '[' + self.client.area.abbreviation + ']' + msg, pos, sfx, anim_type, cid,
- sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname,
- charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre)
-
- self.server.area_manager.send_remote_command(target_area, 'MS', msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid,
- sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname,
- charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre)
-
- self.client.area.set_next_msg_delay(len(msg))
- logger.log_server('[IC][{}][{}]{}'.format(self.client.area.abbreviation, self.client.get_char_name(), msg), self.client)
-
- if (self.client.area.is_recording):
- self.client.area.recorded_messages.append(args)
-
- def net_cmd_ct(self, args):
- """ OOC Message
-
- CT#<name:string>#<message:string>#%
-
- """
- if self.client.is_ooc_muted: # Checks to see if the client has been muted by a mod
- self.client.send_host_message("You have been muted by a moderator")
- return
- if not self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.STR):
- return
- if self.client.name != args[0] and self.client.fake_name != args[0]:
- if self.client.is_valid_name(args[0]):
- self.client.name = args[0]
- self.client.fake_name = args[0]
- else:
- self.client.fake_name = args[0]
- if self.client.name == '':
- self.client.send_host_message('You must insert a name with at least one letter')
- return
- if len(self.client.name) > 30:
- self.client.send_host_message('Your OOC name is too long! Limit it to 30 characters.')
- return
- for c in self.client.name:
- if unicodedata.category(c) == 'Cf':
- self.client.send_host_message('You cannot use format characters in your name!')
- return
- if self.client.name.startswith(self.server.config['hostname']) or self.client.name.startswith('<dollar>G') or self.client.name.startswith('<dollar>M'):
- self.client.send_host_message('That name is reserved!')
- return
- if args[1].startswith(' /'):
- self.client.send_host_message('Your message was not sent for safety reasons: you left a space before that slash.')
- return
- if args[1].startswith('/'):
- spl = args[1][1:].split(' ', 1)
- cmd = spl[0].lower()
- arg = ''
- if len(spl) == 2:
- arg = spl[1][:256]
- try:
- called_function = 'ooc_cmd_{}'.format(cmd)
- getattr(commands, called_function)(self.client, arg)
- except AttributeError:
- print('Attribute error with ' + called_function)
- self.client.send_host_message('Invalid command.')
- except (ClientError, AreaError, ArgumentError, ServerError) as ex:
- self.client.send_host_message(ex)
- else:
- if self.client.shaken:
- args[1] = self.client.shake_message(args[1])
- if self.client.disemvowel:
- args[1] = self.client.disemvowel_message(args[1])
- self.client.area.send_command('CT', self.client.name, args[1])
- self.client.area.send_owner_command('CT', '[' + self.client.area.abbreviation + ']' + self.client.name, args[1])
- logger.log_server(
- '[OOC][{}][{}]{}'.format(self.client.area.abbreviation, self.client.get_char_name(),
- args[1]), self.client)
-
- def net_cmd_mc(self, args):
- """ Play music.
-
- MC#<song_name:int>#<???:int>#%
-
- """
- try:
- area = self.server.area_manager.get_area_by_name(args[0])
- self.client.change_area(area)
- except AreaError:
- if self.client.is_muted: # Checks to see if the client has been muted by a mod
- self.client.send_host_message("You have been muted by a moderator")
- return
- if not self.client.is_dj:
- self.client.send_host_message('You were blockdj\'d by a moderator.')
- return
- if self.client.area.cannot_ic_interact(self.client):
- self.client.send_host_message("You are not on the area's invite list, and thus, you cannot change music!")
- return
- if not self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.INT) and not self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.INT, self.ArgType.STR):
- return
- if args[1] != self.client.char_id:
- return
- if self.client.change_music_cd():
- self.client.send_host_message('You changed song too many times. Please try again after {} seconds.'.format(int(self.client.change_music_cd())))
- return
- try:
- name, length = self.server.get_song_data(args[0])
-
- if self.client.area.jukebox:
- showname = ''
- if len(args) > 2:
- showname = args[2]
- if len(showname) > 0 and not self.client.area.showname_changes_allowed:
- self.client.send_host_message("Showname changes are forbidden in this area!")
- return
- self.client.area.add_jukebox_vote(self.client, name, length, showname)
- logger.log_server('[{}][{}]Added a jukebox vote for {}.'.format(self.client.area.abbreviation, self.client.get_char_name(), name), self.client)
- else:
- if len(args) > 2:
- showname = args[2]
- if len(showname) > 0 and not self.client.area.showname_changes_allowed:
- self.client.send_host_message("Showname changes are forbidden in this area!")
- return
- self.client.area.play_music_shownamed(name, self.client.char_id, showname, length)
- self.client.area.add_music_playing_shownamed(self.client, showname, name)
- else:
- self.client.area.play_music(name, self.client.char_id, length)
- self.client.area.add_music_playing(self.client, name)
- logger.log_server('[{}][{}]Changed music to {}.'
- .format(self.client.area.abbreviation, self.client.get_char_name(), name), self.client)
- except ServerError:
- return
- except ClientError as ex:
- self.client.send_host_message(ex)
-
- def net_cmd_rt(self, args):
- """ Plays the Testimony/CE animation.
-
- RT#<type:string>#%
-
- """
- if not self.client.area.shouts_allowed:
- self.client.send_host_message("You cannot use the testimony buttons here!")
- return
- if self.client.is_muted: # Checks to see if the client has been muted by a mod
- self.client.send_host_message("You have been muted by a moderator")
- return
- if not self.client.can_wtce:
- self.client.send_host_message('You were blocked from using judge signs by a moderator.')
- return
- if self.client.area.cannot_ic_interact(self.client):
- self.client.send_host_message("You are not on the area's invite list, and thus, you cannot use the WTCE buttons!")
- return
- if not self.validate_net_cmd(args, self.ArgType.STR) and not self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.INT):
- return
- if args[0] == 'testimony1':
- sign = 'WT'
- elif args[0] == 'testimony2':
- sign = 'CE'
- elif args[0] == 'judgeruling':
- sign = 'JR'
- else:
- return
- if self.client.wtce_mute():
- self.client.send_host_message('You used witness testimony/cross examination signs too many times. Please try again after {} seconds.'.format(int(self.client.wtce_mute())))
- return
- if len(args) == 1:
- self.client.area.send_command('RT', args[0])
- elif len(args) == 2:
- self.client.area.send_command('RT', args[0], args[1])
- self.client.area.add_to_judgelog(self.client, 'used {}'.format(sign))
- logger.log_server("[{}]{} Used WT/CE".format(self.client.area.abbreviation, self.client.get_char_name()), self.client)
-
- def net_cmd_hp(self, args):
- """ Sets the penalty bar.
-
- HP#<type:int>#<new_value:int>#%
-
- """
- if self.client.is_muted: # Checks to see if the client has been muted by a mod
- self.client.send_host_message("You have been muted by a moderator")
- return
- if self.client.area.cannot_ic_interact(self.client):
- self.client.send_host_message("You are not on the area's invite list, and thus, you cannot change the Confidence bars!")
- return
- if not self.validate_net_cmd(args, self.ArgType.INT, self.ArgType.INT):
- return
- try:
- self.client.area.change_hp(args[0], args[1])
- self.client.area.add_to_judgelog(self.client, 'changed the penalties')
- logger.log_server('[{}]{} changed HP ({}) to {}'
- .format(self.client.area.abbreviation, self.client.get_char_name(), args[0], args[1]), self.client)
- except AreaError:
- return
-
- def net_cmd_pe(self, args):
- """ Adds a piece of evidence.
-
- PE#<name: string>#<description: string>#<image: string>#%
-
- """
- if len(args) < 3:
- return
- #evi = Evidence(args[0], args[1], args[2], self.client.pos)
- self.client.area.evi_list.add_evidence(self.client, args[0], args[1], args[2], 'all')
- self.client.area.broadcast_evidence_list()
-
- def net_cmd_de(self, args):
- """ Deletes a piece of evidence.
-
- DE#<id: int>#%
-
- """
-
- self.client.area.evi_list.del_evidence(self.client, self.client.evi_list[int(args[0])])
- self.client.area.broadcast_evidence_list()
-
- def net_cmd_ee(self, args):
- """ Edits a piece of evidence.
-
- EE#<id: int>#<name: string>#<description: string>#<image: string>#%
-
- """
-
- if len(args) < 4:
- return
-
- evi = (args[1], args[2], args[3], 'all')
-
- self.client.area.evi_list.edit_evidence(self.client, self.client.evi_list[int(args[0])], evi)
- self.client.area.broadcast_evidence_list()
-
-
- def net_cmd_zz(self, args):
- """ Sent on mod call.
-
- """
- if self.client.is_muted: # Checks to see if the client has been muted by a mod
- self.client.send_host_message("You have been muted by a moderator")
- return
-
- if not self.client.can_call_mod():
- self.client.send_host_message("You must wait 30 seconds between mod calls.")
- return
-
- current_time = strftime("%H:%M", localtime())
-
- if len(args) < 1:
- self.server.send_all_cmd_pred('ZZ', '[{}] {} ({}) in {} without reason (not using the Case Café client?)'
- .format(current_time, self.client.get_char_name(), self.client.get_ip(), self.client.area.name), pred=lambda c: c.is_mod)
- self.client.set_mod_call_delay()
- logger.log_server('[{}]{} called a moderator.'.format(self.client.area.abbreviation, self.client.get_char_name()), self.client)
- else:
- self.server.send_all_cmd_pred('ZZ', '[{}] {} ({}) in {} with reason: {}'
- .format(current_time, self.client.get_char_name(), self.client.get_ip(), self.client.area.name, args[0][:100]), pred=lambda c: c.is_mod)
- self.client.set_mod_call_delay()
- logger.log_server('[{}]{} called a moderator: {}.'.format(self.client.area.abbreviation, self.client.get_char_name(), args[0]), self.client)
-
- def net_cmd_opKICK(self, args):
- self.net_cmd_ct(['opkick', '/kick {}'.format(args[0])])
-
- def net_cmd_opBAN(self, args):
- self.net_cmd_ct(['opban', '/ban {}'.format(args[0])])
-
- net_cmd_dispatcher = {
- 'HI': net_cmd_hi, # handshake
- 'ID': net_cmd_id, # client version
- 'CH': net_cmd_ch, # keepalive
- 'askchaa': net_cmd_askchaa, # ask for list lengths
- 'askchar2': net_cmd_askchar2, # ask for list of characters
- 'AN': net_cmd_an, # character list
- 'AE': net_cmd_ae, # evidence list
- 'AM': net_cmd_am, # music list
- 'RC': net_cmd_rc, # AO2 character list
- 'RM': net_cmd_rm, # AO2 music list
- 'RD': net_cmd_rd, # AO2 done request, charscheck etc.
- 'CC': net_cmd_cc, # select character
- 'MS': net_cmd_ms, # IC message
- 'CT': net_cmd_ct, # OOC message
- 'MC': net_cmd_mc, # play song
- 'RT': net_cmd_rt, # WT/CE buttons
- 'HP': net_cmd_hp, # penalties
- 'PE': net_cmd_pe, # add evidence
- 'DE': net_cmd_de, # delete evidence
- 'EE': net_cmd_ee, # edit evidence
- 'ZZ': net_cmd_zz, # call mod button
- 'opKICK': net_cmd_opKICK, # /kick with guard on
- 'opBAN': net_cmd_opBAN, # /ban with guard on
- }
diff --git a/server/area_manager.py b/server/area_manager.py
deleted file mode 100644
index cfb2be0d..00000000
--- a/server/area_manager.py
+++ /dev/null
@@ -1,412 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import asyncio
-import random
-
-import time
-import yaml
-
-from server.exceptions import AreaError
-from server.evidence import EvidenceList
-from enum import Enum
-
-
-class AreaManager:
- class Area:
- def __init__(self, area_id, server, name, background, bg_lock, evidence_mod = 'FFA', locking_allowed = False, iniswap_allowed = True, showname_changes_allowed = False, shouts_allowed = True, jukebox = False, abbreviation = '', non_int_pres_only = False):
- self.iniswap_allowed = iniswap_allowed
- self.clients = set()
- self.invite_list = {}
- self.id = area_id
- self.name = name
- self.background = background
- self.bg_lock = bg_lock
- self.server = server
- self.music_looper = None
- self.next_message_time = 0
- self.hp_def = 10
- self.hp_pro = 10
- self.doc = 'No document.'
- self.status = 'IDLE'
- self.judgelog = []
- self.current_music = ''
- self.current_music_player = ''
- self.current_music_player_ipid = -1
- self.evi_list = EvidenceList()
- self.is_recording = False
- self.recorded_messages = []
- self.evidence_mod = evidence_mod
- self.locking_allowed = locking_allowed
- self.showname_changes_allowed = showname_changes_allowed
- self.shouts_allowed = shouts_allowed
- self.abbreviation = abbreviation
- self.cards = dict()
-
- """
- #debug
- self.evidence_list.append(Evidence("WOW", "desc", "1.png"))
- self.evidence_list.append(Evidence("wewz", "desc2", "2.png"))
- self.evidence_list.append(Evidence("weeeeeew", "desc3", "3.png"))
- """
-
- self.is_locked = self.Locked.FREE
- self.blankposting_allowed = True
- self.non_int_pres_only = non_int_pres_only
- self.jukebox = jukebox
- self.jukebox_votes = []
- self.jukebox_prev_char_id = -1
-
- self.owners = []
-
- class Locked(Enum):
- FREE = 1,
- SPECTATABLE = 2,
- LOCKED = 3
-
- def new_client(self, client):
- self.clients.add(client)
- self.server.area_manager.send_arup_players()
-
- def remove_client(self, client):
- self.clients.remove(client)
- if len(self.clients) == 0:
- self.change_status('IDLE')
-
- def unlock(self):
- self.is_locked = self.Locked.FREE
- self.blankposting_allowed = True
- self.invite_list = {}
- self.server.area_manager.send_arup_lock()
- self.send_host_message('This area is open now.')
-
- def spectator(self):
- self.is_locked = self.Locked.SPECTATABLE
- for i in self.clients:
- self.invite_list[i.id] = None
- for i in self.owners:
- self.invite_list[i.id] = None
- self.server.area_manager.send_arup_lock()
- self.send_host_message('This area is spectatable now.')
-
- def lock(self):
- self.is_locked = self.Locked.LOCKED
- for i in self.clients:
- self.invite_list[i.id] = None
- for i in self.owners:
- self.invite_list[i.id] = None
- self.server.area_manager.send_arup_lock()
- self.send_host_message('This area is locked now.')
-
- def is_char_available(self, char_id):
- return char_id not in [x.char_id for x in self.clients]
-
- def get_rand_avail_char_id(self):
- avail_set = set(range(len(self.server.char_list))) - set([x.char_id for x in self.clients])
- if len(avail_set) == 0:
- raise AreaError('No available characters.')
- return random.choice(tuple(avail_set))
-
- def send_command(self, cmd, *args):
- for c in self.clients:
- c.send_command(cmd, *args)
-
- def send_owner_command(self, cmd, *args):
- for c in self.owners:
- if not c in self.clients:
- c.send_command(cmd, *args)
-
- def send_host_message(self, msg):
- self.send_command('CT', self.server.config['hostname'], msg, '1')
- self.send_owner_command('CT', '[' + self.abbreviation + ']' + self.server.config['hostname'], msg, '1')
-
- def set_next_msg_delay(self, msg_length):
- delay = min(3000, 100 + 60 * msg_length)
- self.next_message_time = round(time.time() * 1000.0 + delay)
-
- def is_iniswap(self, client, anim1, anim2, char):
- if self.iniswap_allowed:
- return False
- if '..' in anim1 or '..' in anim2:
- return True
- for char_link in self.server.allowed_iniswaps:
- if client.get_char_name() in char_link and char in char_link:
- return False
- return True
-
- def add_jukebox_vote(self, client, music_name, length=-1, showname=''):
- if not self.jukebox:
- return
- if length <= 0:
- self.remove_jukebox_vote(client, False)
- else:
- self.remove_jukebox_vote(client, True)
- self.jukebox_votes.append(self.JukeboxVote(client, music_name, length, showname))
- client.send_host_message('Your song was added to the jukebox.')
- if len(self.jukebox_votes) == 1:
- self.start_jukebox()
-
- def remove_jukebox_vote(self, client, silent):
- if not self.jukebox:
- return
- for current_vote in self.jukebox_votes:
- if current_vote.client.id == client.id:
- self.jukebox_votes.remove(current_vote)
- if not silent:
- client.send_host_message('You removed your song from the jukebox.')
-
- def get_jukebox_picked(self):
- if not self.jukebox:
- return
- if len(self.jukebox_votes) == 0:
- return None
- elif len(self.jukebox_votes) == 1:
- return self.jukebox_votes[0]
- else:
- weighted_votes = []
- for current_vote in self.jukebox_votes:
- i = 0
- while i < current_vote.chance:
- weighted_votes.append(current_vote)
- i += 1
- return random.choice(weighted_votes)
-
- def start_jukebox(self):
- # There is a probability that the jukebox feature has been turned off since then,
- # we should check that.
- # We also do a check if we were the last to play a song, just in case.
- if not self.jukebox:
- if self.current_music_player == 'The Jukebox' and self.current_music_player_ipid == 'has no IPID':
- self.current_music = ''
- return
-
- vote_picked = self.get_jukebox_picked()
-
- if vote_picked is None:
- self.current_music = ''
- return
-
- if vote_picked.client.char_id != self.jukebox_prev_char_id or vote_picked.name != self.current_music or len(self.jukebox_votes) > 1:
- self.jukebox_prev_char_id = vote_picked.client.char_id
- if vote_picked.showname == '':
- self.send_command('MC', vote_picked.name, vote_picked.client.char_id)
- else:
- self.send_command('MC', vote_picked.name, vote_picked.client.char_id, vote_picked.showname)
- else:
- self.send_command('MC', vote_picked.name, -1)
-
- self.current_music_player = 'The Jukebox'
- self.current_music_player_ipid = 'has no IPID'
- self.current_music = vote_picked.name
-
- for current_vote in self.jukebox_votes:
- # Choosing the same song will get your votes down to 0, too.
- # Don't want the same song twice in a row!
- if current_vote.name == vote_picked.name:
- current_vote.chance = 0
- else:
- current_vote.chance += 1
-
- if self.music_looper:
- self.music_looper.cancel()
- self.music_looper = asyncio.get_event_loop().call_later(vote_picked.length, lambda: self.start_jukebox())
-
- def play_music(self, name, cid, length=-1):
- self.send_command('MC', name, cid)
- if self.music_looper:
- self.music_looper.cancel()
- if length > 0:
- self.music_looper = asyncio.get_event_loop().call_later(length,
- lambda: self.play_music(name, -1, length))
-
- def play_music_shownamed(self, name, cid, showname, length=-1):
- self.send_command('MC', name, cid, showname)
- if self.music_looper:
- self.music_looper.cancel()
- if length > 0:
- self.music_looper = asyncio.get_event_loop().call_later(length,
- lambda: self.play_music(name, -1, length))
-
-
- def can_send_message(self, client):
- if self.cannot_ic_interact(client):
- client.send_host_message('This is a locked area - ask the CM to speak.')
- return False
- return (time.time() * 1000.0 - self.next_message_time) > 0
-
- def cannot_ic_interact(self, client):
- return self.is_locked != self.Locked.FREE and not client.is_mod and not client.id in self.invite_list
-
- def change_hp(self, side, val):
- if not 0 <= val <= 10:
- raise AreaError('Invalid penalty value.')
- if not 1 <= side <= 2:
- raise AreaError('Invalid penalty side.')
- if side == 1:
- self.hp_def = val
- elif side == 2:
- self.hp_pro = val
- self.send_command('HP', side, val)
-
- def change_background(self, bg):
- if bg.lower() not in (name.lower() for name in self.server.backgrounds):
- raise AreaError('Invalid background name.')
- self.background = bg
- self.send_command('BN', self.background)
-
- def change_status(self, value):
- allowed_values = ('idle', 'rp', 'casing', 'looking-for-players', 'lfp', 'recess', 'gaming')
- if value.lower() not in allowed_values:
- raise AreaError('Invalid status. Possible values: {}'.format(', '.join(allowed_values)))
- if value.lower() == 'lfp':
- value = 'looking-for-players'
- self.status = value.upper()
- self.server.area_manager.send_arup_status()
-
- def change_doc(self, doc='No document.'):
- self.doc = doc
-
- def add_to_judgelog(self, client, msg):
- if len(self.judgelog) >= 10:
- self.judgelog = self.judgelog[1:]
- self.judgelog.append('{} ({}) {}.'.format(client.get_char_name(), client.get_ip(), msg))
-
- def add_music_playing(self, client, name):
- self.current_music_player = client.get_char_name()
- self.current_music_player_ipid = client.ipid
- self.current_music = name
-
- def add_music_playing_shownamed(self, client, showname, name):
- self.current_music_player = showname + " (" + client.get_char_name() + ")"
- self.current_music_player_ipid = client.ipid
- self.current_music = name
-
- def get_evidence_list(self, client):
- client.evi_list, evi_list = self.evi_list.create_evi_list(client)
- return evi_list
-
- def broadcast_evidence_list(self):
- """
- LE#<name>&<desc>&<img>#<name>
-
- """
- for client in self.clients:
- client.send_command('LE', *self.get_evidence_list(client))
-
- def get_cms(self):
- msg = ''
- for i in self.owners:
- msg = msg + '[' + str(i.id) + '] ' + i.get_char_name() + ', '
- if len(msg) > 2:
- msg = msg[:-2]
- return msg
-
- class JukeboxVote:
- def __init__(self, client, name, length, showname):
- self.client = client
- self.name = name
- self.length = length
- self.chance = 1
- self.showname = showname
-
- def __init__(self, server):
- self.server = server
- self.cur_id = 0
- self.areas = []
- self.load_areas()
-
- def load_areas(self):
- with open('config/areas.yaml', 'r') as chars:
- areas = yaml.load(chars)
- for item in areas:
- if 'evidence_mod' not in item:
- item['evidence_mod'] = 'FFA'
- if 'locking_allowed' not in item:
- item['locking_allowed'] = False
- if 'iniswap_allowed' not in item:
- item['iniswap_allowed'] = True
- if 'showname_changes_allowed' not in item:
- item['showname_changes_allowed'] = False
- if 'shouts_allowed' not in item:
- item['shouts_allowed'] = True
- if 'jukebox' not in item:
- item['jukebox'] = False
- if 'noninterrupting_pres' not in item:
- item['noninterrupting_pres'] = False
- if 'abbreviation' not in item:
- item['abbreviation'] = self.get_generated_abbreviation(item['area'])
- self.areas.append(
- self.Area(self.cur_id, self.server, item['area'], item['background'], item['bglock'], item['evidence_mod'], item['locking_allowed'], item['iniswap_allowed'], item['showname_changes_allowed'], item['shouts_allowed'], item['jukebox'], item['abbreviation'], item['noninterrupting_pres']))
- self.cur_id += 1
-
- def default_area(self):
- return self.areas[0]
-
- def get_area_by_name(self, name):
- for area in self.areas:
- if area.name == name:
- return area
- raise AreaError('Area not found.')
-
- def get_area_by_id(self, num):
- for area in self.areas:
- if area.id == num:
- return area
- raise AreaError('Area not found.')
-
- def get_generated_abbreviation(self, name):
- if name.lower().startswith("courtroom"):
- return "CR" + name.split()[-1]
- elif name.lower().startswith("area"):
- return "A" + name.split()[-1]
- elif len(name.split()) > 1:
- return "".join(item[0].upper() for item in name.split())
- elif len(name) > 3:
- return name[:3].upper()
- else:
- return name.upper()
-
- def send_remote_command(self, area_ids, cmd, *args):
- for a_id in area_ids:
- self.get_area_by_id(a_id).send_command(cmd, *args)
- self.get_area_by_id(a_id).send_owner_command(cmd, *args)
-
- def send_arup_players(self):
- players_list = [0]
- for area in self.areas:
- players_list.append(len(area.clients))
- self.server.send_arup(players_list)
-
- def send_arup_status(self):
- status_list = [1]
- for area in self.areas:
- status_list.append(area.status)
- self.server.send_arup(status_list)
-
- def send_arup_cms(self):
- cms_list = [2]
- for area in self.areas:
- cm = 'FREE'
- if len(area.owners) > 0:
- cm = area.get_cms()
- cms_list.append(cm)
- self.server.send_arup(cms_list)
-
- def send_arup_lock(self):
- lock_list = [3]
- for area in self.areas:
- lock_list.append(area.is_locked.name)
- self.server.send_arup(lock_list)
diff --git a/server/ban_manager.py b/server/ban_manager.py
deleted file mode 100644
index 20c186f9..00000000
--- a/server/ban_manager.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import json
-
-from server.exceptions import ServerError
-
-
-class BanManager:
- def __init__(self):
- self.bans = []
- self.load_banlist()
-
- def load_banlist(self):
- try:
- with open('storage/banlist.json', 'r') as banlist_file:
- self.bans = json.load(banlist_file)
- except FileNotFoundError:
- return
-
- def write_banlist(self):
- with open('storage/banlist.json', 'w') as banlist_file:
- json.dump(self.bans, banlist_file)
-
- def add_ban(self, ip):
- if ip not in self.bans:
- self.bans.append(ip)
- else:
- raise ServerError('This IPID is already banned.')
- self.write_banlist()
-
- def remove_ban(self, ip):
- if ip in self.bans:
- self.bans.remove(ip)
- else:
- raise ServerError('This IPID is not banned.')
- self.write_banlist()
-
- def is_banned(self, ipid):
- return (ipid in self.bans) \ No newline at end of file
diff --git a/server/client_manager.py b/server/client_manager.py
deleted file mode 100644
index 432c39d4..00000000
--- a/server/client_manager.py
+++ /dev/null
@@ -1,457 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-from server import fantacrypt
-from server import logger
-from server.exceptions import ClientError, AreaError
-from enum import Enum
-from server.constants import TargetType
-from heapq import heappop, heappush
-
-import time
-import re
-
-
-
-class ClientManager:
- class Client:
- def __init__(self, server, transport, user_id, ipid):
- self.is_checked = False
- self.transport = transport
- self.hdid = ''
- self.pm_mute = False
- self.id = user_id
- self.char_id = -1
- self.area = server.area_manager.default_area()
- self.server = server
- self.name = ''
- self.fake_name = ''
- self.is_mod = False
- self.is_dj = True
- self.can_wtce = True
- self.pos = ''
- self.evi_list = []
- self.disemvowel = False
- self.shaken = False
- self.charcurse = []
- self.muted_global = False
- self.muted_adverts = False
- self.is_muted = False
- self.is_ooc_muted = False
- self.pm_mute = False
- self.mod_call_time = 0
- self.in_rp = False
- self.ipid = ipid
- self.websocket = None
-
- # Pairing stuff
- self.charid_pair = -1
- self.offset_pair = 0
- self.last_sprite = ''
- self.flip = 0
- self.claimed_folder = ''
-
- # Casing stuff
- self.casing_cm = False
- self.casing_cases = ""
- self.casing_def = False
- self.casing_pro = False
- self.casing_jud = False
- self.casing_jur = False
- self.casing_steno = False
- self.case_call_time = 0
-
- #flood-guard stuff
- self.mus_counter = 0
- self.mus_mute_time = 0
- self.mus_change_time = [x * self.server.config['music_change_floodguard']['interval_length'] for x in range(self.server.config['music_change_floodguard']['times_per_interval'])]
- self.wtce_counter = 0
- self.wtce_mute_time = 0
- self.wtce_time = [x * self.server.config['wtce_floodguard']['interval_length'] for x in range(self.server.config['wtce_floodguard']['times_per_interval'])]
-
- def send_raw_message(self, msg):
- if self.websocket:
- self.websocket.send_text(msg.encode('utf-8'))
- else:
- self.transport.write(msg.encode('utf-8'))
-
- def send_command(self, command, *args):
- if args:
- if command == 'MS':
- for evi_num in range(len(self.evi_list)):
- if self.evi_list[evi_num] == args[11]:
- lst = list(args)
- lst[11] = evi_num
- args = tuple(lst)
- break
- self.send_raw_message('{}#{}#%'.format(command, '#'.join([str(x) for x in args])))
- else:
- self.send_raw_message('{}#%'.format(command))
-
- def send_host_message(self, msg):
- self.send_command('CT', self.server.config['hostname'], msg, '1')
-
- def send_motd(self):
- self.send_host_message('=== MOTD ===\r\n{}\r\n============='.format(self.server.config['motd']))
-
- def send_player_count(self):
- self.send_host_message('{}/{} players online.'.format(
- self.server.get_player_count(),
- self.server.config['playerlimit']))
-
- def is_valid_name(self, name):
- name_ws = name.replace(' ', '')
- if not name_ws or name_ws.isdigit():
- return False
- for client in self.server.client_manager.clients:
- print(client.name == name)
- if client.name == name:
- return False
- return True
-
- def disconnect(self):
- self.transport.close()
-
- def change_character(self, char_id, force=False):
- if not self.server.is_valid_char_id(char_id):
- raise ClientError('Invalid Character ID.')
- if len(self.charcurse) > 0:
- if not char_id in self.charcurse:
- raise ClientError('Character not available.')
- force = True
- if not self.area.is_char_available(char_id):
- if force:
- for client in self.area.clients:
- if client.char_id == char_id:
- client.char_select()
- else:
- raise ClientError('Character not available.')
- old_char = self.get_char_name()
- self.char_id = char_id
- self.pos = ''
- self.send_command('PV', self.id, 'CID', self.char_id)
- self.area.send_command('CharsCheck', *self.get_available_char_list())
- logger.log_server('[{}]Changed character from {} to {}.'
- .format(self.area.abbreviation, old_char, self.get_char_name()), self)
-
- def change_music_cd(self):
- if self.is_mod or self in self.area.owners:
- return 0
- if self.mus_mute_time:
- if time.time() - self.mus_mute_time < self.server.config['music_change_floodguard']['mute_length']:
- return self.server.config['music_change_floodguard']['mute_length'] - (time.time() - self.mus_mute_time)
- else:
- self.mus_mute_time = 0
- times_per_interval = self.server.config['music_change_floodguard']['times_per_interval']
- interval_length = self.server.config['music_change_floodguard']['interval_length']
- if time.time() - self.mus_change_time[(self.mus_counter - times_per_interval + 1) % times_per_interval] < interval_length:
- self.mus_mute_time = time.time()
- return self.server.config['music_change_floodguard']['mute_length']
- self.mus_counter = (self.mus_counter + 1) % times_per_interval
- self.mus_change_time[self.mus_counter] = time.time()
- return 0
-
- def wtce_mute(self):
- if self.is_mod or self in self.area.owners:
- return 0
- if self.wtce_mute_time:
- if time.time() - self.wtce_mute_time < self.server.config['wtce_floodguard']['mute_length']:
- return self.server.config['wtce_floodguard']['mute_length'] - (time.time() - self.wtce_mute_time)
- else:
- self.wtce_mute_time = 0
- times_per_interval = self.server.config['wtce_floodguard']['times_per_interval']
- interval_length = self.server.config['wtce_floodguard']['interval_length']
- if time.time() - self.wtce_time[(self.wtce_counter - times_per_interval + 1) % times_per_interval] < interval_length:
- self.wtce_mute_time = time.time()
- return self.server.config['music_change_floodguard']['mute_length']
- self.wtce_counter = (self.wtce_counter + 1) % times_per_interval
- self.wtce_time[self.wtce_counter] = time.time()
- return 0
-
- def reload_character(self):
- try:
- self.change_character(self.char_id, True)
- except ClientError:
- raise
-
- def change_area(self, area):
- if self.area == area:
- raise ClientError('User already in specified area.')
- if area.is_locked == area.Locked.LOCKED and not self.is_mod and not self.id in area.invite_list:
- raise ClientError("That area is locked!")
- if area.is_locked == area.Locked.SPECTATABLE and not self.is_mod and not self.id in area.invite_list:
- self.send_host_message('This area is spectatable, but not free - you will be unable to send messages ICly unless invited.')
-
- if self.area.jukebox:
- self.area.remove_jukebox_vote(self, True)
-
- old_area = self.area
- if not area.is_char_available(self.char_id):
- try:
- new_char_id = area.get_rand_avail_char_id()
- except AreaError:
- raise ClientError('No available characters in that area.')
-
- self.change_character(new_char_id)
- self.send_host_message('Character taken, switched to {}.'.format(self.get_char_name()))
-
- self.area.remove_client(self)
- self.area = area
- area.new_client(self)
-
- self.send_host_message('Changed area to {}.[{}]'.format(area.name, self.area.status))
- logger.log_server(
- '[{}]Changed area from {} ({}) to {} ({}).'.format(self.get_char_name(), old_area.name, old_area.id,
- self.area.name, self.area.id), self)
- self.area.send_command('CharsCheck', *self.get_available_char_list())
- self.send_command('HP', 1, self.area.hp_def)
- self.send_command('HP', 2, self.area.hp_pro)
- self.send_command('BN', self.area.background)
- self.send_command('LE', *self.area.get_evidence_list(self))
-
- def send_area_list(self):
- msg = '=== Areas ==='
- for i, area in enumerate(self.server.area_manager.areas):
- owner = 'FREE'
- if len(area.owners) > 0:
- owner = 'CM: {}'.format(area.get_cms())
- lock = {area.Locked.FREE: '', area.Locked.SPECTATABLE: '[SPECTATABLE]', area.Locked.LOCKED: '[LOCKED]'}
- msg += '\r\nArea {}: {} (users: {}) [{}][{}]{}'.format(area.abbreviation, area.name, len(area.clients), area.status, owner, lock[area.is_locked])
- if self.area == area:
- msg += ' [*]'
- self.send_host_message(msg)
-
- def get_area_info(self, area_id, mods):
- info = '\r\n'
- try:
- area = self.server.area_manager.get_area_by_id(area_id)
- except AreaError:
- raise
- info += '=== {} ==='.format(area.name)
- info += '\r\n'
-
- lock = {area.Locked.FREE: '', area.Locked.SPECTATABLE: '[SPECTATABLE]', area.Locked.LOCKED: '[LOCKED]'}
- info += '[{}]: [{} users][{}]{}'.format(area.abbreviation, len(area.clients), area.status, lock[area.is_locked])
-
- sorted_clients = []
- for client in area.clients:
- if (not mods) or client.is_mod:
- sorted_clients.append(client)
- for owner in area.owners:
- if not (mods or owner in area.clients):
- sorted_clients.append(owner)
- if not sorted_clients:
- return ''
- sorted_clients = sorted(sorted_clients, key=lambda x: x.get_char_name())
- for c in sorted_clients:
- info += '\r\n'
- if c in area.owners:
- if not c in area.clients:
- info += '[RCM]'
- else:
- info +='[CM]'
- info += '[{}] {}'.format(c.id, c.get_char_name())
- if self.is_mod:
- info += ' ({})'.format(c.ipid)
- info += ': {}'.format(c.name)
-
- return info
-
- def send_area_info(self, area_id, mods):
- #if area_id is -1 then return all areas. If mods is True then return only mods
- info = ''
- if area_id == -1:
- # all areas info
- cnt = 0
- info = '\n== Area List =='
- for i in range(len(self.server.area_manager.areas)):
- if len(self.server.area_manager.areas[i].clients) > 0 or len(self.server.area_manager.areas[i].owners) > 0:
- cnt += len(self.server.area_manager.areas[i].clients)
- info += '{}'.format(self.get_area_info(i, mods))
- info = 'Current online: {}'.format(cnt) + info
- else:
- try:
- info = 'People in this area: {}'.format(len(self.server.area_manager.areas[area_id].clients)) + self.get_area_info(area_id, mods)
- except AreaError:
- raise
- self.send_host_message(info)
-
- def send_area_hdid(self, area_id):
- try:
- info = self.get_area_hdid(area_id)
- except AreaError:
- raise
- self.send_host_message(info)
-
- def send_all_area_hdid(self):
- info = '== HDID List =='
- for i in range (len(self.server.area_manager.areas)):
- if len(self.server.area_manager.areas[i].clients) > 0:
- info += '\r\n{}'.format(self.get_area_hdid(i))
- self.send_host_message(info)
-
- def send_all_area_ip(self):
- info = '== IP List =='
- for i in range (len(self.server.area_manager.areas)):
- if len(self.server.area_manager.areas[i].clients) > 0:
- info += '\r\n{}'.format(self.get_area_ip(i))
- self.send_host_message(info)
-
- def send_done(self):
- self.send_command('CharsCheck', *self.get_available_char_list())
- self.send_command('HP', 1, self.area.hp_def)
- self.send_command('HP', 2, self.area.hp_pro)
- self.send_command('BN', self.area.background)
- self.send_command('LE', *self.area.get_evidence_list(self))
- self.send_command('MM', 1)
-
- self.server.area_manager.send_arup_players()
- self.server.area_manager.send_arup_status()
- self.server.area_manager.send_arup_cms()
- self.server.area_manager.send_arup_lock()
-
- self.send_command('DONE')
-
- def char_select(self):
- self.char_id = -1
- self.send_done()
-
- def get_available_char_list(self):
- if len(self.charcurse) > 0:
- avail_char_ids = set(range(len(self.server.char_list))) and set(self.charcurse)
- else:
- avail_char_ids = set(range(len(self.server.char_list))) - set([x.char_id for x in self.area.clients])
- char_list = [-1] * len(self.server.char_list)
- for x in avail_char_ids:
- char_list[x] = 0
- return char_list
-
- def auth_mod(self, password):
- if self.is_mod:
- raise ClientError('Already logged in.')
- if password == self.server.config['modpass']:
- self.is_mod = True
- else:
- raise ClientError('Invalid password.')
-
- def get_ip(self):
- return self.ipid
-
-
-
- def get_char_name(self):
- if self.char_id == -1:
- return 'CHAR_SELECT'
- return self.server.char_list[self.char_id]
-
- def change_position(self, pos=''):
- if pos not in ('', 'def', 'pro', 'hld', 'hlp', 'jud', 'wit', 'jur', 'sea'):
- raise ClientError('Invalid position. Possible values: def, pro, hld, hlp, jud, wit, jur, sea.')
- self.pos = pos
-
- def set_mod_call_delay(self):
- self.mod_call_time = round(time.time() * 1000.0 + 30000)
-
- def can_call_mod(self):
- return (time.time() * 1000.0 - self.mod_call_time) > 0
-
- def set_case_call_delay(self):
- self.case_call_time = round(time.time() * 1000.0 + 60000)
-
- def can_call_case(self):
- return (time.time() * 1000.0 - self.case_call_time) > 0
-
- def disemvowel_message(self, message):
- message = re.sub("[aeiou]", "", message, flags=re.IGNORECASE)
- return re.sub(r"\s+", " ", message)
-
- def shake_message(self, message):
- import random
- parts = message.split()
- random.shuffle(parts)
- return ' '.join(parts)
-
-
- def __init__(self, server):
- self.clients = set()
- self.server = server
- self.cur_id = [i for i in range(self.server.config['playerlimit'])]
- self.clients_list = []
-
- def new_client(self, transport):
- c = self.Client(self.server, transport, heappop(self.cur_id), self.server.get_ipid(transport.get_extra_info('peername')[0]))
- self.clients.add(c)
- return c
-
-
- def remove_client(self, client):
- if client.area.jukebox:
- client.area.remove_jukebox_vote(client, True)
- for a in self.server.area_manager.areas:
- if client in a.owners:
- a.owners.remove(client)
- client.server.area_manager.send_arup_cms()
- if len(a.owners) == 0:
- if a.is_locked != a.Locked.FREE:
- a.unlock()
- heappush(self.cur_id, client.id)
- self.clients.remove(client)
-
- def get_targets(self, client, key, value, local = False):
- #possible keys: ip, OOC, id, cname, ipid, hdid
- areas = None
- if local:
- areas = [client.area]
- else:
- areas = client.server.area_manager.areas
- targets = []
- if key == TargetType.ALL:
- for nkey in range(6):
- targets += self.get_targets(client, nkey, value, local)
- for area in areas:
- for client in area.clients:
- if key == TargetType.IP:
- if value.lower().startswith(client.get_ip().lower()):
- targets.append(client)
- elif key == TargetType.OOC_NAME:
- if value.lower().startswith(client.name.lower()) and client.name:
- targets.append(client)
- elif key == TargetType.CHAR_NAME:
- if value.lower().startswith(client.get_char_name().lower()):
- targets.append(client)
- elif key == TargetType.ID:
- if client.id == value:
- targets.append(client)
- elif key == TargetType.IPID:
- if client.ipid == value:
- targets.append(client)
- return targets
-
-
- def get_muted_clients(self):
- clients = []
- for client in self.clients:
- if client.is_muted:
- clients.append(client)
- return clients
-
- def get_ooc_muted_clients(self):
- clients = []
- for client in self.clients:
- if client.is_ooc_muted:
- clients.append(client)
- return clients
diff --git a/server/commands.py b/server/commands.py
deleted file mode 100644
index d02eff25..00000000
--- a/server/commands.py
+++ /dev/null
@@ -1,1255 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#possible keys: ip, OOC, id, cname, ipid, hdid
-import random
-import re
-import hashlib
-import string
-from server.constants import TargetType
-
-from server import logger
-from server.exceptions import ClientError, ServerError, ArgumentError, AreaError
-
-def ooc_cmd_a(client, arg):
- if len(arg) == 0:
- raise ArgumentError('You must specify an area.')
- arg = arg.split(' ')
-
- try:
- area = client.server.area_manager.get_area_by_id(int(arg[0]))
- except AreaError:
- raise
-
- message_areas_cm(client, [area], ' '.join(arg[1:]))
-
-def ooc_cmd_s(client, arg):
- areas = []
- for a in client.server.area_manager.areas:
- if client in a.owners:
- areas.append(a)
- if not areas:
- client.send_host_message('You aren\'t a CM in any area!')
- return
- message_areas_cm(client, areas, arg)
-
-def message_areas_cm(client, areas, message):
- for a in areas:
- if not client in a.owners:
- client.send_host_message('You are not a CM in {}!'.format(a.name))
- return
- a.send_command('CT', client.name, message)
- a.send_owner_command('CT', client.name, message)
-
-def ooc_cmd_switch(client, arg):
- if len(arg) == 0:
- raise ArgumentError('You must specify a character name.')
- try:
- cid = client.server.get_char_id_by_name(arg)
- except ServerError:
- raise
- try:
- client.change_character(cid, client.is_mod)
- except ClientError:
- raise
- client.send_host_message('Character changed.')
-
-def ooc_cmd_bg(client, arg):
- if len(arg) == 0:
- raise ArgumentError('You must specify a name. Use /bg <background>.')
- if not client.is_mod and client.area.bg_lock == "true":
- raise AreaError("This area's background is locked")
- try:
- client.area.change_background(arg)
- except AreaError:
- raise
- client.area.send_host_message('{} changed the background to {}.'.format(client.get_char_name(), arg))
- logger.log_server('[{}][{}]Changed background to {}'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-def ooc_cmd_bglock(client,arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- if client.area.bg_lock == "true":
- client.area.bg_lock = "false"
- else:
- client.area.bg_lock = "true"
- client.area.send_host_message('{} [{}] has set the background lock to {}.'.format(client.get_char_name(), client.id, client.area.bg_lock))
- logger.log_server('[{}][{}]Changed bglock to {}'.format(client.area.abbreviation, client.get_char_name(), client.area.bg_lock), client)
-
-def ooc_cmd_evidence_mod(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if not arg:
- client.send_host_message('current evidence mod: {}'.format(client.area.evidence_mod))
- return
- if arg in ['FFA', 'Mods', 'CM', 'HiddenCM']:
- if arg == client.area.evidence_mod:
- client.send_host_message('current evidence mod: {}'.format(client.area.evidence_mod))
- return
- if client.area.evidence_mod == 'HiddenCM':
- for i in range(len(client.area.evi_list.evidences)):
- client.area.evi_list.evidences[i].pos = 'all'
- client.area.evidence_mod = arg
- client.send_host_message('current evidence mod: {}'.format(client.area.evidence_mod))
- return
- else:
- raise ArgumentError('Wrong Argument. Use /evidence_mod <MOD>. Possible values: FFA, CM, Mods, HiddenCM')
- return
-
-def ooc_cmd_allow_iniswap(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- client.area.iniswap_allowed = not client.area.iniswap_allowed
- answer = {True: 'allowed', False: 'forbidden'}
- client.send_host_message('iniswap is {}.'.format(answer[client.area.iniswap_allowed]))
- return
-
-def ooc_cmd_allow_blankposting(client, arg):
- if not client.is_mod and not client in client.area.owners:
- raise ClientError('You must be authorized to do that.')
- client.area.blankposting_allowed = not client.area.blankposting_allowed
- answer = {True: 'allowed', False: 'forbidden'}
- client.area.send_host_message('{} [{}] has set blankposting in the area to {}.'.format(client.get_char_name(), client.id, answer[client.area.blankposting_allowed]))
- return
-
-def ooc_cmd_force_nonint_pres(client, arg):
- if not client.is_mod and not client in client.area.owners:
- raise ClientError('You must be authorized to do that.')
- client.area.non_int_pres_only = not client.area.non_int_pres_only
- answer = {True: 'non-interrupting only', False: 'non-interrupting or interrupting as you choose'}
- client.area.send_host_message('{} [{}] has set pres in the area to be {}.'.format(client.get_char_name(), client.id, answer[client.area.non_int_pres_only]))
- return
-
-def ooc_cmd_roll(client, arg):
- roll_max = 11037
- if len(arg) != 0:
- try:
- val = list(map(int, arg.split(' ')))
- if not 1 <= val[0] <= roll_max:
- raise ArgumentError('Roll value must be between 1 and {}.'.format(roll_max))
- except ValueError:
- raise ArgumentError('Wrong argument. Use /roll [<max>] [<num of rolls>]')
- else:
- val = [6]
- if len(val) == 1:
- val.append(1)
- if len(val) > 2:
- raise ArgumentError('Too many arguments. Use /roll [<max>] [<num of rolls>]')
- if val[1] > 20 or val[1] < 1:
- raise ArgumentError('Num of rolls must be between 1 and 20')
- roll = ''
- for i in range(val[1]):
- roll += str(random.randint(1, val[0])) + ', '
- roll = roll[:-2]
- if val[1] > 1:
- roll = '(' + roll + ')'
- client.area.send_host_message('{} rolled {} out of {}.'.format(client.get_char_name(), roll, val[0]))
- logger.log_server(
- '[{}][{}]Used /roll and got {} out of {}.'.format(client.area.abbreviation, client.get_char_name(), roll, val[0]), client)
-
-def ooc_cmd_rollp(client, arg):
- roll_max = 11037
- if len(arg) != 0:
- try:
- val = list(map(int, arg.split(' ')))
- if not 1 <= val[0] <= roll_max:
- raise ArgumentError('Roll value must be between 1 and {}.'.format(roll_max))
- except ValueError:
- raise ArgumentError('Wrong argument. Use /rollp [<max>] [<num of rolls>]')
- else:
- val = [6]
- if len(val) == 1:
- val.append(1)
- if len(val) > 2:
- raise ArgumentError('Too many arguments. Use /rollp [<max>] [<num of rolls>]')
- if val[1] > 20 or val[1] < 1:
- raise ArgumentError('Num of rolls must be between 1 and 20')
- roll = ''
- for i in range(val[1]):
- roll += str(random.randint(1, val[0])) + ', '
- roll = roll[:-2]
- if val[1] > 1:
- roll = '(' + roll + ')'
- client.send_host_message('{} rolled {} out of {}.'.format(client.get_char_name(), roll, val[0]))
-
- client.area.send_host_message('{} rolled in secret.'.format(client.get_char_name()))
- for c in client.area.owners:
- c.send_host_message('[{}]{} secretly rolled {} out of {}.'.format(client.area.abbreviation, client.get_char_name(), roll, val[0]))
-
- logger.log_server(
- '[{}][{}]Used /rollp and got {} out of {}.'.format(client.area.abbreviation, client.get_char_name(), roll, val[0]), client)
-
-def ooc_cmd_currentmusic(client, arg):
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- if client.area.current_music == '':
- raise ClientError('There is no music currently playing.')
- if client.is_mod:
- client.send_host_message('The current music is {} and was played by {} ({}).'.format(client.area.current_music,
- client.area.current_music_player, client.area.current_music_player_ipid))
- else:
- client.send_host_message('The current music is {} and was played by {}.'.format(client.area.current_music,
- client.area.current_music_player))
-
-def ooc_cmd_jukebox_toggle(client, arg):
- if not client.is_mod and not client in client.area.owners:
- raise ClientError('You must be authorized to do that.')
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- client.area.jukebox = not client.area.jukebox
- client.area.jukebox_votes = []
- client.area.send_host_message('{} [{}] has set the jukebox to {}.'.format(client.get_char_name(), client.id, client.area.jukebox))
-
-def ooc_cmd_jukebox_skip(client, arg):
- if not client.is_mod and not client in client.area.owners:
- raise ClientError('You must be authorized to do that.')
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- if not client.area.jukebox:
- raise ClientError('This area does not have a jukebox.')
- if len(client.area.jukebox_votes) == 0:
- raise ClientError('There is no song playing right now, skipping is pointless.')
- client.area.start_jukebox()
- if len(client.area.jukebox_votes) == 1:
- client.area.send_host_message('{} [{}] has forced a skip, restarting the only jukebox song.'.format(client.get_char_name(), client.id))
- else:
- client.area.send_host_message('{} [{}] has forced a skip to the next jukebox song.'.format(client.get_char_name(), client.id))
- logger.log_server('[{}][{}]Skipped the current jukebox song.'.format(client.area.abbreviation, client.get_char_name()), client)
-
-def ooc_cmd_jukebox(client, arg):
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- if not client.area.jukebox:
- raise ClientError('This area does not have a jukebox.')
- if len(client.area.jukebox_votes) == 0:
- client.send_host_message('The jukebox has no songs in it.')
- else:
- total = 0
- songs = []
- voters = dict()
- chance = dict()
- message = ''
-
- for current_vote in client.area.jukebox_votes:
- if songs.count(current_vote.name) == 0:
- songs.append(current_vote.name)
- voters[current_vote.name] = [current_vote.client]
- chance[current_vote.name] = current_vote.chance
- else:
- voters[current_vote.name].append(current_vote.client)
- chance[current_vote.name] += current_vote.chance
- total += current_vote.chance
-
- for song in songs:
- message += '\n- ' + song + '\n'
- message += '-- VOTERS: '
-
- first = True
- for voter in voters[song]:
- if first:
- first = False
- else:
- message += ', '
- message += voter.get_char_name() + ' [' + str(voter.id) + ']'
- if client.is_mod:
- message += '(' + str(voter.ipid) + ')'
- message += '\n'
-
- if total == 0:
- message += '-- CHANCE: 100'
- else:
- message += '-- CHANCE: ' + str(round(chance[song] / total * 100))
-
- client.send_host_message('The jukebox has the following songs in it:{}'.format(message))
-
-def ooc_cmd_coinflip(client, arg):
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- coin = ['heads', 'tails']
- flip = random.choice(coin)
- client.area.send_host_message('{} flipped a coin and got {}.'.format(client.get_char_name(), flip))
- logger.log_server(
- '[{}][{}]Used /coinflip and got {}.'.format(client.area.abbreviation, client.get_char_name(), flip), client)
-
-def ooc_cmd_motd(client, arg):
- if len(arg) != 0:
- raise ArgumentError("This command doesn't take any arguments")
- client.send_motd()
-
-def ooc_cmd_pos(client, arg):
- if len(arg) == 0:
- client.change_position()
- client.send_host_message('Position reset.')
- else:
- try:
- client.change_position(arg)
- except ClientError:
- raise
- client.area.broadcast_evidence_list()
- client.send_host_message('Position changed.')
-
-def ooc_cmd_forcepos(client, arg):
- if not client in client.area.owners and not client.is_mod:
- raise ClientError('You must be authorized to do that.')
-
- args = arg.split()
-
- if len(args) < 1:
- raise ArgumentError(
- 'Not enough arguments. Use /forcepos <pos> <target>. Target should be ID, OOC-name or char-name. Use /getarea for getting info like "[ID] char-name".')
-
- targets = []
-
- pos = args[0]
- if len(args) > 1:
- targets = client.server.client_manager.get_targets(
- client, TargetType.CHAR_NAME, " ".join(args[1:]), True)
- if len(targets) == 0 and args[1].isdigit():
- targets = client.server.client_manager.get_targets(
- client, TargetType.ID, int(arg[1]), True)
- if len(targets) == 0:
- targets = client.server.client_manager.get_targets(
- client, TargetType.OOC_NAME, " ".join(args[1:]), True)
- if len(targets) == 0:
- raise ArgumentError('No targets found.')
- else:
- for c in client.area.clients:
- targets.append(c)
-
-
-
- for t in targets:
- try:
- t.change_position(pos)
- t.area.broadcast_evidence_list()
- t.send_host_message('Forced into /pos {}.'.format(pos))
- except ClientError:
- raise
-
- client.area.send_host_message(
- '{} forced {} client(s) into /pos {}.'.format(client.get_char_name(), len(targets), pos))
- logger.log_server(
- '[{}][{}]Used /forcepos {} for {} client(s).'.format(client.area.abbreviation, client.get_char_name(), pos, len(targets)), client)
-
-def ooc_cmd_help(client, arg):
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- help_url = 'http://casecafe.byethost14.com/commandlist'
- help_msg = 'The commands available on this server can be found here: {}'.format(help_url)
- client.send_host_message(help_msg)
-
-def ooc_cmd_kick(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /kick <ipid> <ipid> ...')
- args = list(arg.split(' '))
- client.send_host_message('Attempting to kick {} IPIDs.'.format(len(args)))
- for raw_ipid in args:
- try:
- ipid = int(raw_ipid)
- except:
- raise ClientError('{} does not look like a valid IPID.'.format(raw_ipid))
- targets = client.server.client_manager.get_targets(client, TargetType.IPID, ipid, False)
- if targets:
- for c in targets:
- logger.log_server('Kicked {} [{}]({}).'.format(c.get_char_name(), c.id, c.ipid), client)
- logger.log_mod('Kicked {} [{}]({}).'.format(c.get_char_name(), c.id, c.ipid), client)
- client.send_host_message("{} was kicked.".format(c.get_char_name()))
- c.send_command('KK', c.char_id)
- c.disconnect()
- else:
- client.send_host_message("No targets with the IPID {} were found.".format(ipid))
-
-def ooc_cmd_ban(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /ban <ipid> <ipid> ...')
- args = list(arg.split(' '))
- client.send_host_message('Attempting to ban {} IPIDs.'.format(len(args)))
- for raw_ipid in args:
- try:
- ipid = int(raw_ipid)
- except:
- raise ClientError('{} does not look like a valid IPID.'.format(raw_ipid))
- try:
- client.server.ban_manager.add_ban(ipid)
- except ServerError:
- raise
- if ipid != None:
- targets = client.server.client_manager.get_targets(client, TargetType.IPID, ipid, False)
- if targets:
- for c in targets:
- c.send_command('KB', c.char_id)
- c.disconnect()
- client.send_host_message('{} clients was kicked.'.format(len(targets)))
- client.send_host_message('{} was banned.'.format(ipid))
- logger.log_server('Banned {}.'.format(ipid), client)
- logger.log_mod('Banned {}.'.format(ipid), client)
-
-def ooc_cmd_unban(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /unban <ipid> <ipid> ...')
- args = list(arg.split(' '))
- client.send_host_message('Attempting to unban {} IPIDs.'.format(len(args)))
- for raw_ipid in args:
- try:
- client.server.ban_manager.remove_ban(int(raw_ipid))
- except:
- raise ClientError('{} does not look like a valid IPID.'.format(raw_ipid))
- logger.log_server('Unbanned {}.'.format(raw_ipid), client)
- logger.log_mod('Unbanned {}.'.format(raw_ipid), client)
- client.send_host_message('Unbanned {}'.format(raw_ipid))
-
-def ooc_cmd_play(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a song.')
- client.area.play_music(arg, client.char_id, -1)
- client.area.add_music_playing(client, arg)
- logger.log_server('[{}][{}]Changed music to {}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-def ooc_cmd_mute(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /mute <ipid>.')
- args = list(arg.split(' '))
- client.send_host_message('Attempting to mute {} IPIDs.'.format(len(args)))
- for raw_ipid in args:
- if raw_ipid.isdigit():
- ipid = int(raw_ipid)
- clients = client.server.client_manager.get_targets(client, TargetType.IPID, ipid, False)
- if (clients):
- msg = 'Muted the IPID ' + str(ipid) + '\'s following clients:'
- for c in clients:
- c.is_muted = True
- logger.log_server('Muted {} [{}]({}).'.format(c.get_char_name(), c.id, c.ipid), client)
- logger.log_mod('Muted {} [{}]({}).'.format(c.get_char_name(), c.id, c.ipid), client)
- msg += ' ' + c.get_char_name() + ' [' + str(c.id) + '],'
- msg = msg[:-1]
- msg += '.'
- client.send_host_message('{}'.format(msg))
- else:
- client.send_host_message("No targets found. Use /mute <ipid> <ipid> ... for mute.")
- else:
- client.send_host_message('{} does not look like a valid IPID.'.format(raw_ipid))
-
-def ooc_cmd_unmute(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target.')
- args = list(arg.split(' '))
- client.send_host_message('Attempting to unmute {} IPIDs.'.format(len(args)))
- for raw_ipid in args:
- if raw_ipid.isdigit():
- ipid = int(raw_ipid)
- clients = client.server.client_manager.get_targets(client, TargetType.IPID, ipid, False)
- if (clients):
- msg = 'Unmuted the IPID ' + str(ipid) + '\'s following clients::'
- for c in clients:
- c.is_muted = False
- logger.log_server('Unmuted {} [{}]({}).'.format(c.get_char_name(), c.id, c.ipid), client)
- logger.log_mod('Unmuted {} [{}]({}).'.format(c.get_char_name(), c.id, c.ipid), client)
- msg += ' ' + c.get_char_name() + ' [' + str(c.id) + '],'
- msg = msg[:-1]
- msg += '.'
- client.send_host_message('{}'.format(msg))
- else:
- client.send_host_message("No targets found. Use /unmute <ipid> <ipid> ... for unmute.")
- else:
- client.send_host_message('{} does not look like a valid IPID.'.format(raw_ipid))
-
-def ooc_cmd_login(client, arg):
- if len(arg) == 0:
- raise ArgumentError('You must specify the password.')
- try:
- client.auth_mod(arg)
- except ClientError:
- raise
- if client.area.evidence_mod == 'HiddenCM':
- client.area.broadcast_evidence_list()
- client.send_host_message('Logged in as a moderator.')
- logger.log_server('Logged in as moderator.', client)
- logger.log_mod('Logged in as moderator.', client)
-
-def ooc_cmd_g(client, arg):
- if client.muted_global:
- raise ClientError('Global chat toggled off.')
- if len(arg) == 0:
- raise ArgumentError("You can't send an empty message.")
- client.server.broadcast_global(client, arg)
- logger.log_server('[{}][{}][GLOBAL]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-def ooc_cmd_gm(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if client.muted_global:
- raise ClientError('You have the global chat muted.')
- if len(arg) == 0:
- raise ArgumentError("Can't send an empty message.")
- client.server.broadcast_global(client, arg, True)
- logger.log_server('[{}][{}][GLOBAL-MOD]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
- logger.log_mod('[{}][{}][GLOBAL-MOD]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-def ooc_cmd_m(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError("You can't send an empty message.")
- client.server.send_modchat(client, arg)
- logger.log_server('[{}][{}][MODCHAT]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
- logger.log_mod('[{}][{}][MODCHAT]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-def ooc_cmd_lm(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError("Can't send an empty message.")
- client.area.send_command('CT', '{}[MOD][{}]'
- .format(client.server.config['hostname'], client.get_char_name()), arg)
- logger.log_server('[{}][{}][LOCAL-MOD]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
- logger.log_mod('[{}][{}][LOCAL-MOD]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-def ooc_cmd_announce(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError("Can't send an empty message.")
- client.server.send_all_cmd_pred('CT', '{}'.format(client.server.config['hostname']),
- '=== Announcement ===\r\n{}\r\n=================='.format(arg), '1')
- logger.log_server('[{}][{}][ANNOUNCEMENT]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
- logger.log_mod('[{}][{}][ANNOUNCEMENT]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-def ooc_cmd_toggleglobal(client, arg):
- if len(arg) != 0:
- raise ArgumentError("This command doesn't take any arguments")
- client.muted_global = not client.muted_global
- glob_stat = 'on'
- if client.muted_global:
- glob_stat = 'off'
- client.send_host_message('Global chat turned {}.'.format(glob_stat))
-
-
-def ooc_cmd_need(client, arg):
- if client.muted_adverts:
- raise ClientError('You have advertisements muted.')
- if len(arg) == 0:
- raise ArgumentError("You must specify what you need.")
- client.server.broadcast_need(client, arg)
- logger.log_server('[{}][{}][NEED]{}.'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-def ooc_cmd_toggleadverts(client, arg):
- if len(arg) != 0:
- raise ArgumentError("This command doesn't take any arguments")
- client.muted_adverts = not client.muted_adverts
- adv_stat = 'on'
- if client.muted_adverts:
- adv_stat = 'off'
- client.send_host_message('Advertisements turned {}.'.format(adv_stat))
-
-def ooc_cmd_doc(client, arg):
- if len(arg) == 0:
- client.send_host_message('Document: {}'.format(client.area.doc))
- logger.log_server(
- '[{}][{}]Requested document. Link: {}'.format(client.area.abbreviation, client.get_char_name(), client.area.doc), client)
- else:
- client.area.change_doc(arg)
- client.area.send_host_message('{} changed the doc link.'.format(client.get_char_name()))
- logger.log_server('[{}][{}]Changed document to: {}'.format(client.area.abbreviation, client.get_char_name(), arg), client)
-
-
-def ooc_cmd_cleardoc(client, arg):
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- client.area.send_host_message('{} cleared the doc link.'.format(client.get_char_name()))
- logger.log_server('[{}][{}]Cleared document. Old link: {}'
- .format(client.area.abbreviation, client.get_char_name(), client.area.doc), client)
- client.area.change_doc()
-
-
-def ooc_cmd_status(client, arg):
- if len(arg) == 0:
- client.send_host_message('Current status: {}'.format(client.area.status))
- else:
- try:
- client.area.change_status(arg)
- client.area.send_host_message('{} changed status to {}.'.format(client.get_char_name(), client.area.status))
- logger.log_server(
- '[{}][{}]Changed status to {}'.format(client.area.abbreviation, client.get_char_name(), client.area.status), client)
- except AreaError:
- raise
-
-
-def ooc_cmd_online(client, _):
- client.send_player_count()
-
-
-def ooc_cmd_area(client, arg):
- args = arg.split()
- if len(args) == 0:
- client.send_area_list()
- elif len(args) == 1:
- try:
- area = client.server.area_manager.get_area_by_id(int(args[0]))
- client.change_area(area)
- except ValueError:
- raise ArgumentError('Area ID must be a number.')
- except (AreaError, ClientError):
- raise
- else:
- raise ArgumentError('Too many arguments. Use /area <id>.')
-
-def ooc_cmd_pm(client, arg):
- args = arg.split()
- key = ''
- msg = None
- if len(args) < 2:
- raise ArgumentError('Not enough arguments. use /pm <target> <message>. Target should be ID, OOC-name or char-name. Use /getarea for getting info like "[ID] char-name".')
- targets = client.server.client_manager.get_targets(client, TargetType.CHAR_NAME, arg, True)
- key = TargetType.CHAR_NAME
- if len(targets) == 0 and args[0].isdigit():
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(args[0]), False)
- key = TargetType.ID
- if len(targets) == 0:
- targets = client.server.client_manager.get_targets(client, TargetType.OOC_NAME, arg, True)
- key = TargetType.OOC_NAME
- if len(targets) == 0:
- raise ArgumentError('No targets found.')
- try:
- if key == TargetType.ID:
- msg = ' '.join(args[1:])
- else:
- if key == TargetType.CHAR_NAME:
- msg = arg[len(targets[0].get_char_name()) + 1:]
- if key == TargetType.OOC_NAME:
- msg = arg[len(targets[0].name) + 1:]
- except:
- raise ArgumentError('Not enough arguments. Use /pm <target> <message>.')
- c = targets[0]
- if c.pm_mute:
- raise ClientError('This user muted all pm conversation')
- else:
- if c.is_mod:
- c.send_host_message('PM from {} (ID: {}, IPID: {}) in {} ({}): {}'.format(client.name, client.id, client.ipid, client.area.name, client.get_char_name(), msg))
- else:
- c.send_host_message('PM from {} (ID: {}) in {} ({}): {}'.format(client.name, client.id, client.area.name, client.get_char_name(), msg))
- client.send_host_message('PM sent to {}. Message: {}'.format(args[0], msg))
-
-def ooc_cmd_mutepm(client, arg):
- if len(arg) != 0:
- raise ArgumentError("This command doesn't take any arguments")
- client.pm_mute = not client.pm_mute
- client.send_host_message({True:'You stopped receiving PMs', False:'You are now receiving PMs'}[client.pm_mute])
-
-def ooc_cmd_charselect(client, arg):
- if not arg:
- client.char_select()
- else:
- if client.is_mod:
- try:
- client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)[0].char_select()
- except:
- raise ArgumentError('Wrong arguments. Use /charselect <target\'s id>')
-
-def ooc_cmd_reload(client, arg):
- if len(arg) != 0:
- raise ArgumentError("This command doesn't take any arguments")
- try:
- client.reload_character()
- except ClientError:
- raise
- client.send_host_message('Character reloaded.')
-
-def ooc_cmd_randomchar(client, arg):
- if len(arg) != 0:
- raise ArgumentError('This command has no arguments.')
- if len(client.charcurse) > 0:
- free_id = random.choice(client.charcurse)
- else:
- try:
- free_id = client.area.get_rand_avail_char_id()
- except AreaError:
- raise
- try:
- client.change_character(free_id)
- except ClientError:
- raise
- client.send_host_message('Randomly switched to {}'.format(client.get_char_name()))
-
-def ooc_cmd_getarea(client, arg):
- client.send_area_info(client.area.id, False)
-
-def ooc_cmd_getareas(client, arg):
- client.send_area_info(-1, False)
-
-def ooc_cmd_mods(client, arg):
- client.send_area_info(-1, True)
-
-def ooc_cmd_evi_swap(client, arg):
- args = list(arg.split(' '))
- if len(args) != 2:
- raise ClientError("you must specify 2 numbers")
- try:
- client.area.evi_list.evidence_swap(client, int(args[0]), int(args[1]))
- client.area.broadcast_evidence_list()
- except:
- raise ClientError("you must specify 2 numbers")
-
-def ooc_cmd_cm(client, arg):
- if 'CM' not in client.area.evidence_mod:
- raise ClientError('You can\'t become a CM in this area')
- if len(client.area.owners) == 0:
- if len(arg) > 0:
- raise ArgumentError('You cannot \'nominate\' people to be CMs when you are not one.')
- client.area.owners.append(client)
- if client.area.evidence_mod == 'HiddenCM':
- client.area.broadcast_evidence_list()
- client.server.area_manager.send_arup_cms()
- client.area.send_host_message('{} [{}] is CM in this area now.'.format(client.get_char_name(), client.id))
- elif client in client.area.owners:
- if len(arg) > 0:
- arg = arg.split(' ')
- for id in arg:
- try:
- id = int(id)
- c = client.server.client_manager.get_targets(client, TargetType.ID, id, False)[0]
- if c in client.area.owners:
- client.send_host_message('{} [{}] is already a CM here.'.format(c.get_char_name(), c.id))
- else:
- client.area.owners.append(c)
- if client.area.evidence_mod == 'HiddenCM':
- client.area.broadcast_evidence_list()
- client.server.area_manager.send_arup_cms()
- client.area.send_host_message('{} [{}] is CM in this area now.'.format(c.get_char_name(), c.id))
- except:
- client.send_host_message('{} does not look like a valid ID.'.format(id))
- else:
- raise ClientError('You must be authorized to do that.')
-
-
-def ooc_cmd_uncm(client, arg):
- if client in client.area.owners:
- if len(arg) > 0:
- arg = arg.split(' ')
- else:
- arg = [client.id]
- for id in arg:
- try:
- id = int(id)
- c = client.server.client_manager.get_targets(client, TargetType.ID, id, False)[0]
- if c in client.area.owners:
- client.area.owners.remove(c)
- client.server.area_manager.send_arup_cms()
- client.area.send_host_message('{} [{}] is no longer CM in this area.'.format(c.get_char_name(), c.id))
- else:
- client.send_host_message('You cannot remove someone from CMing when they aren\'t a CM.')
- except:
- client.send_host_message('{} does not look like a valid ID.'.format(id))
- else:
- raise ClientError('You must be authorized to do that.')
-
-def ooc_cmd_setcase(client, arg):
- args = re.findall(r'(?:[^\s,"]|"(?:\\.|[^"])*")+', arg)
- if len(args) == 0:
- raise ArgumentError('Please do not call this command manually!')
- else:
- client.casing_cases = args[0]
- client.casing_cm = args[1] == "1"
- client.casing_def = args[2] == "1"
- client.casing_pro = args[3] == "1"
- client.casing_jud = args[4] == "1"
- client.casing_jur = args[5] == "1"
- client.casing_steno = args[6] == "1"
-
-def ooc_cmd_anncase(client, arg):
- if client in client.area.owners:
- if not client.can_call_case():
- raise ClientError('Please wait 60 seconds between case announcements!')
- args = re.findall(r'(?:[^\s,"]|"(?:\\.|[^"])*")+', arg)
- if len(args) == 0:
- raise ArgumentError('Please do not call this command manually!')
- elif len(args) == 1:
- raise ArgumentError('You should probably announce the case to at least one person.')
- else:
- if not args[1] == "1" and not args[2] == "1" and not args[3] == "1" and not args[4] == "1" and not args[5] == "1":
- raise ArgumentError('You should probably announce the case to at least one person.')
- msg = '=== Case Announcement ===\r\n{} [{}] is hosting {}, looking for '.format(client.get_char_name(), client.id, args[0])
-
- lookingfor = []
-
- if args[1] == "1":
- lookingfor.append("defence")
- if args[2] == "1":
- lookingfor.append("prosecutor")
- if args[3] == "1":
- lookingfor.append("judge")
- if args[4] == "1":
- lookingfor.append("juror")
- if args[5] == "1":
- lookingfor.append("stenographer")
-
- msg = msg + ', '.join(lookingfor) + '.\r\n=================='
-
- client.server.send_all_cmd_pred('CASEA', msg, args[1], args[2], args[3], args[4], args[5], '1')
-
- client.set_case_call_delay()
-
- logger.log_server('[{}][{}][CASE_ANNOUNCEMENT]{}, DEF: {}, PRO: {}, JUD: {}, JUR: {}, STENO: {}.'.format(client.area.abbreviation, client.get_char_name(), args[0], args[1], args[2], args[3], args[4], args[5]), client)
- else:
- raise ClientError('You cannot announce a case in an area where you are not a CM!')
-
-def ooc_cmd_unmod(client, arg):
- client.is_mod = False
- if client.area.evidence_mod == 'HiddenCM':
- client.area.broadcast_evidence_list()
- client.send_host_message('you\'re not a mod now')
-
-def ooc_cmd_area_lock(client, arg):
- if not client.area.locking_allowed:
- client.send_host_message('Area locking is disabled in this area.')
- return
- if client.area.is_locked == client.area.Locked.LOCKED:
- client.send_host_message('Area is already locked.')
- if client in client.area.owners:
- client.area.lock()
- return
- else:
- raise ClientError('Only CM can lock the area.')
-
-def ooc_cmd_area_spectate(client, arg):
- if not client.area.locking_allowed:
- client.send_host_message('Area locking is disabled in this area.')
- return
- if client.area.is_locked == client.area.Locked.SPECTATABLE:
- client.send_host_message('Area is already spectatable.')
- if client in client.area.owners:
- client.area.spectator()
- return
- else:
- raise ClientError('Only CM can make the area spectatable.')
-
-def ooc_cmd_area_unlock(client, arg):
- if client.area.is_locked == client.area.Locked.FREE:
- raise ClientError('Area is already unlocked.')
- if not client in client.area.owners:
- raise ClientError('Only CM can unlock area.')
- client.area.unlock()
- client.send_host_message('Area is unlocked.')
-
-def ooc_cmd_invite(client, arg):
- if not arg:
- raise ClientError('You must specify a target. Use /invite <id>')
- if client.area.is_locked == client.area.Locked.FREE:
- raise ClientError('Area isn\'t locked.')
- if not client in client.area.owners and not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- try:
- c = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)[0]
- client.area.invite_list[c.id] = None
- client.send_host_message('{} is invited to your area.'.format(c.get_char_name()))
- c.send_host_message('You were invited and given access to {}.'.format(client.area.name))
- except:
- raise ClientError('You must specify a target. Use /invite <id>')
-
-def ooc_cmd_uninvite(client, arg):
- if not client in client.area.owners and not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if client.area.is_locked == client.area.Locked.FREE:
- raise ClientError('Area isn\'t locked.')
- if not arg:
- raise ClientError('You must specify a target. Use /uninvite <id>')
- arg = arg.split(' ')
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg[0]), True)
- if targets:
- try:
- for c in targets:
- client.send_host_message("You have removed {} from the whitelist.".format(c.get_char_name()))
- c.send_host_message("You were removed from the area whitelist.")
- if client.area.is_locked != client.area.Locked.FREE:
- client.area.invite_list.pop(c.id)
- except AreaError:
- raise
- except ClientError:
- raise
- else:
- client.send_host_message("No targets found.")
-
-def ooc_cmd_area_kick(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if client.area.is_locked == client.area.Locked.FREE:
- raise ClientError('Area isn\'t locked.')
- if not arg:
- raise ClientError('You must specify a target. Use /area_kick <id> [destination #]')
- arg = arg.split(' ')
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg[0]), False)
- if targets:
- try:
- for c in targets:
- if len(arg) == 1:
- area = client.server.area_manager.get_area_by_id(int(0))
- output = 0
- else:
- try:
- area = client.server.area_manager.get_area_by_id(int(arg[1]))
- output = arg[1]
- except AreaError:
- raise
- client.send_host_message("Attempting to kick {} to area {}.".format(c.get_char_name(), output))
- c.change_area(area)
- c.send_host_message("You were kicked from the area to area {}.".format(output))
- if client.area.is_locked != client.area.Locked.FREE:
- client.area.invite_list.pop(c.id)
- except AreaError:
- raise
- except ClientError:
- raise
- else:
- client.send_host_message("No targets found.")
-
-
-def ooc_cmd_ooc_mute(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /ooc_mute <OOC-name>.')
- targets = client.server.client_manager.get_targets(client, TargetType.OOC_NAME, arg, False)
- if not targets:
- raise ArgumentError('Targets not found. Use /ooc_mute <OOC-name>.')
- for target in targets:
- target.is_ooc_muted = True
- client.send_host_message('Muted {} existing client(s).'.format(len(targets)))
-
-def ooc_cmd_ooc_unmute(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /ooc_unmute <OOC-name>.')
- targets = client.server.client_manager.get_ooc_muted_clients()
- if not targets:
- raise ArgumentError('Targets not found. Use /ooc_unmute <OOC-name>.')
- for target in targets:
- target.is_ooc_muted = False
- client.send_host_message('Unmuted {} existing client(s).'.format(len(targets)))
-
-def ooc_cmd_disemvowel(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- elif len(arg) == 0:
- raise ArgumentError('You must specify a target.')
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)
- except:
- raise ArgumentError('You must specify a target. Use /disemvowel <id>.')
- if targets:
- for c in targets:
- logger.log_server('Disemvowelling {}.'.format(c.get_ip()), client)
- logger.log_mod('Disemvowelling {}.'.format(c.get_ip()), client)
- c.disemvowel = True
- client.send_host_message('Disemvowelled {} existing client(s).'.format(len(targets)))
- else:
- client.send_host_message('No targets found.')
-
-def ooc_cmd_undisemvowel(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- elif len(arg) == 0:
- raise ArgumentError('You must specify a target.')
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)
- except:
- raise ArgumentError('You must specify a target. Use /undisemvowel <id>.')
- if targets:
- for c in targets:
- logger.log_server('Undisemvowelling {}.'.format(c.get_ip()), client)
- logger.log_mod('Undisemvowelling {}.'.format(c.get_ip()), client)
- c.disemvowel = False
- client.send_host_message('Undisemvowelled {} existing client(s).'.format(len(targets)))
- else:
- client.send_host_message('No targets found.')
-
-def ooc_cmd_shake(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- elif len(arg) == 0:
- raise ArgumentError('You must specify a target.')
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)
- except:
- raise ArgumentError('You must specify a target. Use /shake <id>.')
- if targets:
- for c in targets:
- logger.log_server('Shaking {}.'.format(c.get_ip()), client)
- logger.log_mod('Shaking {}.'.format(c.get_ip()), client)
- c.shaken = True
- client.send_host_message('Shook {} existing client(s).'.format(len(targets)))
- else:
- client.send_host_message('No targets found.')
-
-def ooc_cmd_unshake(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- elif len(arg) == 0:
- raise ArgumentError('You must specify a target.')
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)
- except:
- raise ArgumentError('You must specify a target. Use /unshake <id>.')
- if targets:
- for c in targets:
- logger.log_server('Unshaking {}.'.format(c.get_ip()), client)
- logger.log_mod('Unshaking {}.'.format(c.get_ip()), client)
- c.shaken = False
- client.send_host_message('Unshook {} existing client(s).'.format(len(targets)))
- else:
- client.send_host_message('No targets found.')
-
-def ooc_cmd_charcurse(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- elif len(arg) == 0:
- raise ArgumentError('You must specify a target (an ID) and at least one character ID. Consult /charids for the character IDs.')
- elif len(arg) == 1:
- raise ArgumentError('You must specific at least one character ID. Consult /charids for the character IDs.')
- args = arg.split()
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(args[0]), False)
- except:
- raise ArgumentError('You must specify a valid target! Make sure it is a valid ID.')
- if targets:
- for c in targets:
- log_msg = ' ' + str(c.get_ip()) + ' to'
- part_msg = ' [' + str(c.id) + '] to'
- for raw_cid in args[1:]:
- try:
- cid = int(raw_cid)
- c.charcurse.append(cid)
- part_msg += ' ' + str(client.server.char_list[cid]) + ','
- log_msg += ' ' + str(client.server.char_list[cid]) + ','
- except:
- ArgumentError('' + str(raw_cid) + ' does not look like a valid character ID.')
- part_msg = part_msg[:-1]
- part_msg += '.'
- log_msg = log_msg[:-1]
- log_msg += '.'
- c.char_select()
- logger.log_server('Charcursing' + log_msg, client)
- logger.log_mod('Charcursing' + log_msg, client)
- client.send_host_message('Charcursed' + part_msg)
- else:
- client.send_host_message('No targets found.')
-
-def ooc_cmd_uncharcurse(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- elif len(arg) == 0:
- raise ArgumentError('You must specify a target (an ID).')
- args = arg.split()
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(args[0]), False)
- except:
- raise ArgumentError('You must specify a valid target! Make sure it is a valid ID.')
- if targets:
- for c in targets:
- if len(c.charcurse) > 0:
- c.charcurse = []
- logger.log_server('Uncharcursing {}.'.format(c.get_ip()), client)
- logger.log_mod('Uncharcursing {}.'.format(c.get_ip()), client)
- client.send_host_message('Uncharcursed [{}].'.format(c.id))
- c.char_select()
- else:
- client.send_host_message('[{}] is not charcursed.'.format(c.id))
- else:
- client.send_host_message('No targets found.')
-
-def ooc_cmd_charids(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) != 0:
- raise ArgumentError("This command doesn't take any arguments")
- msg = 'Here is a list of all available characters on the server:'
- for c in range(0, len(client.server.char_list)):
- msg += '\n[' + str(c) + '] ' + client.server.char_list[c]
- client.send_host_message(msg)
-
-def ooc_cmd_blockdj(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /blockdj <id>.')
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)
- except:
- raise ArgumentError('You must enter a number. Use /blockdj <id>.')
- if not targets:
- raise ArgumentError('Target not found. Use /blockdj <id>.')
- for target in targets:
- target.is_dj = False
- target.send_host_message('A moderator muted you from changing the music.')
- logger.log_server('BlockDJ\'d {} [{}]({}).'.format(target.get_char_name(), target.id, target.get_ip()), client)
- logger.log_mod('BlockDJ\'d {} [{}]({}).'.format(target.get_char_name(), target.id, target.get_ip()), client)
- target.area.remove_jukebox_vote(target, True)
- client.send_host_message('blockdj\'d {}.'.format(targets[0].get_char_name()))
-
-def ooc_cmd_unblockdj(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /unblockdj <id>.')
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)
- except:
- raise ArgumentError('You must enter a number. Use /unblockdj <id>.')
- if not targets:
- raise ArgumentError('Target not found. Use /blockdj <id>.')
- for target in targets:
- target.is_dj = True
- target.send_host_message('A moderator unmuted you from changing the music.')
- logger.log_server('UnblockDJ\'d {} [{}]({}).'.format(target.get_char_name(), target.id, target.get_ip()), client)
- logger.log_mod('UnblockDJ\'d {} [{}]({}).'.format(target.get_char_name(), target.id, target.get_ip()), client)
- client.send_host_message('Unblockdj\'d {}.'.format(targets[0].get_char_name()))
-
-def ooc_cmd_blockwtce(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /blockwtce <id>.')
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)
- except:
- raise ArgumentError('You must enter a number. Use /blockwtce <id>.')
- if not targets:
- raise ArgumentError('Target not found. Use /blockwtce <id>.')
- for target in targets:
- target.can_wtce = False
- target.send_host_message('A moderator blocked you from using judge signs.')
- logger.log_server('BlockWTCE\'d {} [{}]({}).'.format(target.get_char_name(), target.id, target.get_ip()), client)
- logger.log_mod('BlockWTCE\'d {} [{}]({}).'.format(target.get_char_name(), target.id, target.get_ip()), client)
- client.send_host_message('blockwtce\'d {}.'.format(targets[0].get_char_name()))
-
-def ooc_cmd_unblockwtce(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) == 0:
- raise ArgumentError('You must specify a target. Use /unblockwtce <id>.')
- try:
- targets = client.server.client_manager.get_targets(client, TargetType.ID, int(arg), False)
- except:
- raise ArgumentError('You must enter a number. Use /unblockwtce <id>.')
- if not targets:
- raise ArgumentError('Target not found. Use /unblockwtce <id>.')
- for target in targets:
- target.can_wtce = True
- target.send_host_message('A moderator unblocked you from using judge signs.')
- logger.log_server('UnblockWTCE\'d {} [{}]({}).'.format(target.get_char_name(), target.id, target.get_ip()), client)
- logger.log_mod('UnblockWTCE\'d {} [{}]({}).'.format(target.get_char_name(), target.id, target.get_ip()), client)
- client.send_host_message('unblockwtce\'d {}.'.format(targets[0].get_char_name()))
-
-def ooc_cmd_notecard(client, arg):
- if len(arg) == 0:
- raise ArgumentError('You must specify the contents of the note card.')
- client.area.cards[client.get_char_name()] = arg
- client.area.send_host_message('{} wrote a note card.'.format(client.get_char_name()))
-
-def ooc_cmd_notecard_clear(client, arg):
- try:
- del client.area.cards[client.get_char_name()]
- client.area.send_host_message('{} erased their note card.'.format(client.get_char_name()))
- except KeyError:
- raise ClientError('You do not have a note card.')
-
-def ooc_cmd_notecard_reveal(client, arg):
- if not client in client.area.owners and not client.is_mod:
- raise ClientError('You must be a CM or moderator to reveal cards.')
- if len(client.area.cards) == 0:
- raise ClientError('There are no cards to reveal in this area.')
- msg = 'Note cards have been revealed.\n'
- for card_owner, card_msg in client.area.cards.items():
- msg += '{}: {}\n'.format(card_owner, card_msg)
- client.area.cards.clear()
- client.area.send_host_message(msg)
-
-def ooc_cmd_rolla_reload(client, arg):
- if not client.is_mod:
- raise ClientError('You must be a moderator to load the ability dice configuration.')
- rolla_reload(client.area)
- client.send_host_message('Reloaded ability dice configuration.')
-
-def rolla_reload(area):
- try:
- import yaml
- with open('config/dice.yaml', 'r') as dice:
- area.ability_dice = yaml.load(dice)
- except:
- raise ServerError('There was an error parsing the ability dice configuration. Check your syntax.')
-
-def ooc_cmd_rolla_set(client, arg):
- if not hasattr(client.area, 'ability_dice'):
- rolla_reload(client.area)
- available_sets = ', '.join(client.area.ability_dice.keys())
- if len(arg) == 0:
- raise ArgumentError('You must specify the ability set name.\nAvailable sets: {}'.format(available_sets))
- if arg in client.area.ability_dice:
- client.ability_dice_set = arg
- client.send_host_message("Set ability set to {}.".format(arg))
- else:
- raise ArgumentError('Invalid ability set \'{}\'.\nAvailable sets: {}'.format(arg, available_sets))
-
-def ooc_cmd_rolla(client, arg):
- if not hasattr(client.area, 'ability_dice'):
- rolla_reload(client.area)
- if not hasattr(client, 'ability_dice_set'):
- raise ClientError('You must set your ability set using /rolla_set <name>.')
- ability_dice = client.area.ability_dice[client.ability_dice_set]
- max_roll = ability_dice['max'] if 'max' in ability_dice else 6
- roll = random.randint(1, max_roll)
- ability = ability_dice[roll] if roll in ability_dice else "Nothing happens"
- client.area.send_host_message(
- '{} rolled a {} (out of {}): {}.'.format(client.get_char_name(), roll, max_roll, ability))
-
-def ooc_cmd_refresh(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len (arg) > 0:
- raise ClientError('This command does not take in any arguments!')
- else:
- try:
- client.server.refresh()
- client.send_host_message('You have reloaded the server.')
- except ServerError:
- raise
-
-def ooc_cmd_judgelog(client, arg):
- if not client.is_mod:
- raise ClientError('You must be authorized to do that.')
- if len(arg) != 0:
- raise ArgumentError('This command does not take any arguments.')
- jlog = client.area.judgelog
- if len(jlog) > 0:
- jlog_msg = '== Judge Log =='
- for x in jlog:
- jlog_msg += '\r\n{}'.format(x)
- client.send_host_message(jlog_msg)
- else:
- raise ServerError('There have been no judge actions in this area since start of session.')
diff --git a/server/constants.py b/server/constants.py
deleted file mode 100644
index fa07e8ee..00000000
--- a/server/constants.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from enum import Enum
-
-class TargetType(Enum):
- #possible keys: ip, OOC, id, cname, ipid, hdid
- IP = 0
- OOC_NAME = 1
- ID = 2
- CHAR_NAME = 3
- IPID = 4
- HDID = 5
- ALL = 6 \ No newline at end of file
diff --git a/server/districtclient.py b/server/districtclient.py
deleted file mode 100644
index c766ba5f..00000000
--- a/server/districtclient.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import asyncio
-
-from server import logger
-
-
-class DistrictClient:
- def __init__(self, server):
- self.server = server
- self.reader = None
- self.writer = None
- self.message_queue = []
-
- async def connect(self):
- loop = asyncio.get_event_loop()
- while True:
- try:
- self.reader, self.writer = await asyncio.open_connection(self.server.config['district_ip'],
- self.server.config['district_port'], loop=loop)
- await self.handle_connection()
- except (ConnectionRefusedError, TimeoutError):
- pass
- except (ConnectionResetError, asyncio.IncompleteReadError):
- self.writer = None
- self.reader = None
- finally:
- logger.log_debug("Couldn't connect to the district, retrying in 30 seconds.")
- await asyncio.sleep(30)
-
- async def handle_connection(self):
- logger.log_debug('District connected.')
- self.send_raw_message('AUTH#{}'.format(self.server.config['district_password']))
- while True:
- data = await self.reader.readuntil(b'\r\n')
- if not data:
- return
- raw_msg = data.decode()[:-2]
- logger.log_debug('[DISTRICT][INC][RAW]{}'.format(raw_msg))
- cmd, *args = raw_msg.split('#')
- if cmd == 'GLOBAL':
- glob_name = '{}[{}:{}][{}]'.format('<dollar>G', args[1], args[2], args[3])
- if args[0] == '1':
- glob_name += '[M]'
- self.server.send_all_cmd_pred('CT', glob_name, args[4], pred=lambda x: not x.muted_global)
- elif cmd == 'NEED':
- need_msg = '=== Cross Advert ===\r\n{} at {} in {} [{}] needs {}\r\n====================' \
- .format(args[1], args[0], args[2], args[3], args[4])
- self.server.send_all_cmd_pred('CT', '{}'.format(self.server.config['hostname']), need_msg, '1',
- pred=lambda x: not x.muted_adverts)
-
- async def write_queue(self):
- while self.message_queue:
- msg = self.message_queue.pop(0)
- try:
- self.writer.write(msg)
- await self.writer.drain()
- except ConnectionResetError:
- return
-
- def send_raw_message(self, msg):
- if not self.writer:
- return
- self.message_queue.append('{}\r\n'.format(msg).encode())
- asyncio.ensure_future(self.write_queue(), loop=asyncio.get_event_loop())
diff --git a/server/evidence.py b/server/evidence.py
deleted file mode 100644
index b34172ad..00000000
--- a/server/evidence.py
+++ /dev/null
@@ -1,100 +0,0 @@
-class EvidenceList:
- limit = 35
-
- class Evidence:
- def __init__(self, name, desc, image, pos):
- self.name = name
- self.desc = desc
- self.image = image
- self.public = False
- self.pos = pos
-
- def set_name(self, name):
- self.name = name
-
- def set_desc(self, desc):
- self.desc = desc
-
- def set_image(self, image):
- self.image = image
-
- def to_string(self):
- sequence = (self.name, self.desc, self.image)
- return '&'.join(sequence)
-
- def __init__(self):
- self.evidences = []
- self.poses = {'def':['def', 'hld'],
- 'pro':['pro', 'hlp'],
- 'wit':['wit', 'sea'],
- 'sea':['sea', 'wit'],
- 'hlp':['hlp', 'pro'],
- 'hld':['hld', 'def'],
- 'jud':['jud', 'jur'],
- 'jur':['jur', 'jud'],
- 'all':['hlp', 'hld', 'wit', 'jud', 'pro', 'def', 'jur', 'sea', ''],
- 'pos':[]}
-
- def login(self, client):
- if client.area.evidence_mod == 'FFA':
- pass
- if client.area.evidence_mod == 'Mods':
- if not client in client.area.owners:
- return False
- if client.area.evidence_mod == 'CM':
- if not client in client.area.owners and not client.is_mod:
- return False
- if client.area.evidence_mod == 'HiddenCM':
- if not client in client.area.owners and not client.is_mod:
- return False
- return True
-
- def correct_format(self, client, desc):
- if client.area.evidence_mod != 'HiddenCM':
- return True
- else:
- #correct format: <owner = pos>\ndesc
- if desc[:9] == '<owner = ' and desc[9:12] in self.poses and desc[12:14] == '>\n':
- return True
- return False
-
-
- def add_evidence(self, client, name, description, image, pos = 'all'):
- if self.login(client):
- if client.area.evidence_mod == 'HiddenCM':
- pos = 'pos'
- if len(self.evidences) >= self.limit:
- client.send_host_message('You can\'t have more than {} evidence items at a time.'.format(self.limit))
- else:
- self.evidences.append(self.Evidence(name, description, image, pos))
-
- def evidence_swap(self, client, id1, id2):
- if self.login(client):
- self.evidences[id1], self.evidences[id2] = self.evidences[id2], self.evidences[id1]
-
- def create_evi_list(self, client):
- evi_list = []
- nums_list = [0]
- for i in range(len(self.evidences)):
- if client.area.evidence_mod == 'HiddenCM' and self.login(client):
- nums_list.append(i + 1)
- evi = self.evidences[i]
- evi_list.append(self.Evidence(evi.name, '<owner = {}>\n{}'.format(evi.pos, evi.desc), evi.image, evi.pos).to_string())
- elif client.pos in self.poses[self.evidences[i].pos]:
- nums_list.append(i + 1)
- evi_list.append(self.evidences[i].to_string())
- return nums_list, evi_list
-
- def del_evidence(self, client, id):
- if self.login(client):
- self.evidences.pop(id)
-
- def edit_evidence(self, client, id, arg):
- if self.login(client):
- if client.area.evidence_mod == 'HiddenCM' and self.correct_format(client, arg[1]):
- self.evidences[id] = self.Evidence(arg[0], arg[1][14:], arg[2], arg[1][9:12])
- return
- if client.area.evidence_mod == 'HiddenCM':
- client.send_host_message('You entered a wrong pos.')
- return
- self.evidences[id] = self.Evidence(arg[0], arg[1], arg[2], arg[3]) \ No newline at end of file
diff --git a/server/exceptions.py b/server/exceptions.py
deleted file mode 100644
index d3503e91..00000000
--- a/server/exceptions.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-class ClientError(Exception):
- pass
-
-
-class AreaError(Exception):
- pass
-
-
-class ArgumentError(Exception):
- pass
-
-
-class ServerError(Exception):
- pass
diff --git a/server/fantacrypt.py b/server/fantacrypt.py
deleted file mode 100644
index e31548e7..00000000
--- a/server/fantacrypt.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# fantacrypt was a mistake, just hardcoding some numbers is good enough
-
-import binascii
-
-CRYPT_CONST_1 = 53761
-CRYPT_CONST_2 = 32618
-CRYPT_KEY = 5
-
-
-def fanta_decrypt(data):
- data_bytes = [int(data[x:x + 2], 16) for x in range(0, len(data), 2)]
- key = CRYPT_KEY
- ret = ''
- for byte in data_bytes:
- val = byte ^ ((key & 0xffff) >> 8)
- ret += chr(val)
- key = ((byte + key) * CRYPT_CONST_1) + CRYPT_CONST_2
- return ret
-
-
-def fanta_encrypt(data):
- key = CRYPT_KEY
- ret = ''
- for char in data:
- val = ord(char) ^ ((key & 0xffff) >> 8)
- ret += binascii.hexlify(val.to_bytes(1, byteorder='big')).decode().upper()
- key = ((val + key) * CRYPT_CONST_1) + CRYPT_CONST_2
- return ret
diff --git a/server/logger.py b/server/logger.py
deleted file mode 100644
index fb1b8b36..00000000
--- a/server/logger.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import logging
-
-import time
-
-
-def setup_logger(debug):
- logging.Formatter.converter = time.gmtime
- debug_formatter = logging.Formatter('[%(asctime)s UTC]%(message)s')
- srv_formatter = logging.Formatter('[%(asctime)s UTC]%(message)s')
- mod_formatter = logging.Formatter('[%(asctime)s UTC]%(message)s')
-
- debug_log = logging.getLogger('debug')
- debug_log.setLevel(logging.DEBUG)
-
- debug_handler = logging.FileHandler('logs/debug.log', encoding='utf-8')
- debug_handler.setLevel(logging.DEBUG)
- debug_handler.setFormatter(debug_formatter)
- debug_log.addHandler(debug_handler)
-
- if not debug:
- debug_log.disabled = True
-
- server_log = logging.getLogger('server')
- server_log.setLevel(logging.INFO)
-
- server_handler = logging.FileHandler('logs/server.log', encoding='utf-8')
- server_handler.setLevel(logging.INFO)
- server_handler.setFormatter(srv_formatter)
- server_log.addHandler(server_handler)
-
- mod_log = logging.getLogger('mod')
- mod_log.setLevel(logging.INFO)
-
- mod_handler = logging.FileHandler('logs/mod.log', encoding='utf-8')
- mod_handler.setLevel(logging.INFO)
- mod_handler.setFormatter(mod_formatter)
- mod_log.addHandler(mod_handler)
-
-
-def log_debug(msg, client=None):
- msg = parse_client_info(client) + msg
- logging.getLogger('debug').debug(msg)
-
-
-def log_server(msg, client=None):
- msg = parse_client_info(client) + msg
- logging.getLogger('server').info(msg)
-
-
-def log_mod(msg, client=None):
- msg = parse_client_info(client) + msg
- logging.getLogger('mod').info(msg)
-
-
-def parse_client_info(client):
- if client is None:
- return ''
- info = client.get_ip()
- if client.is_mod:
- return '[{:<15}][{:<3}][{}][MOD]'.format(info, client.id, client.name)
- return '[{:<15}][{:<3}][{}]'.format(info, client.id, client.name)
diff --git a/server/masterserverclient.py b/server/masterserverclient.py
deleted file mode 100644
index 49af0435..00000000
--- a/server/masterserverclient.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-import asyncio
-import time
-from server import logger
-
-
-class MasterServerClient:
- def __init__(self, server):
- self.server = server
- self.reader = None
- self.writer = None
-
- async def connect(self):
- loop = asyncio.get_event_loop()
- while True:
- try:
- self.reader, self.writer = await asyncio.open_connection(self.server.config['masterserver_ip'],
- self.server.config['masterserver_port'],
- loop=loop)
- await self.handle_connection()
- except (ConnectionRefusedError, TimeoutError):
- pass
- except (ConnectionResetError, asyncio.IncompleteReadError):
- self.writer = None
- self.reader = None
- finally:
- logger.log_debug("Couldn't connect to the master server, retrying in 30 seconds.")
- print("Couldn't connect to the master server, retrying in 30 seconds.")
- await asyncio.sleep(30)
-
- async def handle_connection(self):
- logger.log_debug('Master server connected.')
- await self.send_server_info()
- fl = False
- lastping = time.time() - 20
- while True:
- self.reader.feed_data(b'END')
- full_data = await self.reader.readuntil(b'END')
- full_data = full_data[:-3]
- if len(full_data) > 0:
- data_list = list(full_data.split(b'#%'))[:-1]
- for data in data_list:
- raw_msg = data.decode()
- cmd, *args = raw_msg.split('#')
- if cmd != 'CHECK' and cmd != 'PONG':
- logger.log_debug('[MASTERSERVER][INC][RAW]{}'.format(raw_msg))
- elif cmd == 'CHECK':
- await self.send_raw_message('PING#%')
- elif cmd == 'PONG':
- fl = False
- elif cmd == 'NOSERV':
- await self.send_server_info()
- if time.time() - lastping > 5:
- if fl:
- return
- lastping = time.time()
- fl = True
- await self.send_raw_message('PING#%')
- await asyncio.sleep(1)
-
- async def send_server_info(self):
- cfg = self.server.config
- msg = 'SCC#{}#{}#{}#{}#%'.format(cfg['port'], cfg['masterserver_name'], cfg['masterserver_description'],
- self.server.software)
- await self.send_raw_message(msg)
-
- async def send_raw_message(self, msg):
- try:
- self.writer.write(msg.encode())
- await self.writer.drain()
- except ConnectionResetError:
- return
diff --git a/server/tsuserver.py b/server/tsuserver.py
deleted file mode 100644
index 5af8161d..00000000
--- a/server/tsuserver.py
+++ /dev/null
@@ -1,305 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2016 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import asyncio
-
-import yaml
-import json
-
-from server import logger
-from server.aoprotocol import AOProtocol
-from server.area_manager import AreaManager
-from server.ban_manager import BanManager
-from server.client_manager import ClientManager
-from server.districtclient import DistrictClient
-from server.exceptions import ServerError
-from server.masterserverclient import MasterServerClient
-
-class TsuServer3:
- def __init__(self):
- self.config = None
- self.allowed_iniswaps = None
- self.load_config()
- self.load_iniswaps()
- self.client_manager = ClientManager(self)
- self.area_manager = AreaManager(self)
- self.ban_manager = BanManager()
- self.software = 'tsuserver3'
- self.version = 'tsuserver3dev'
- self.release = 3
- self.major_version = 1
- self.minor_version = 1
- self.ipid_list = {}
- self.hdid_list = {}
- self.char_list = None
- self.char_pages_ao1 = None
- self.music_list = None
- self.music_list_ao2 = None
- self.music_pages_ao1 = None
- self.backgrounds = None
- self.load_characters()
- self.load_music()
- self.load_backgrounds()
- self.load_ids()
- self.district_client = None
- self.ms_client = None
- self.rp_mode = False
- logger.setup_logger(debug=self.config['debug'])
-
- def start(self):
- loop = asyncio.get_event_loop()
-
- bound_ip = '0.0.0.0'
- if self.config['local']:
- bound_ip = '127.0.0.1'
-
- ao_server_crt = loop.create_server(lambda: AOProtocol(self), bound_ip, self.config['port'])
- ao_server = loop.run_until_complete(ao_server_crt)
-
- if self.config['use_district']:
- self.district_client = DistrictClient(self)
- asyncio.ensure_future(self.district_client.connect(), loop=loop)
-
- if self.config['use_masterserver']:
- self.ms_client = MasterServerClient(self)
- asyncio.ensure_future(self.ms_client.connect(), loop=loop)
-
- logger.log_debug('Server started.')
-
- try:
- loop.run_forever()
- except KeyboardInterrupt:
- pass
-
- logger.log_debug('Server shutting down.')
-
- ao_server.close()
- loop.run_until_complete(ao_server.wait_closed())
- loop.close()
-
- def get_version_string(self):
- return str(self.release) + '.' + str(self.major_version) + '.' + str(self.minor_version)
-
- def new_client(self, transport):
- c = self.client_manager.new_client(transport)
- if self.rp_mode:
- c.in_rp = True
- c.server = self
- c.area = self.area_manager.default_area()
- c.area.new_client(c)
- return c
-
- def remove_client(self, client):
- client.area.remove_client(client)
- self.client_manager.remove_client(client)
-
- def get_player_count(self):
- return len(self.client_manager.clients)
-
- def load_config(self):
- with open('config/config.yaml', 'r', encoding = 'utf-8') as cfg:
- self.config = yaml.load(cfg)
- self.config['motd'] = self.config['motd'].replace('\\n', ' \n')
- if 'music_change_floodguard' not in self.config:
- self.config['music_change_floodguard'] = {'times_per_interval': 1, 'interval_length': 0, 'mute_length': 0}
- if 'wtce_floodguard' not in self.config:
- self.config['wtce_floodguard'] = {'times_per_interval': 1, 'interval_length': 0, 'mute_length': 0}
-
- def load_characters(self):
- with open('config/characters.yaml', 'r', encoding = 'utf-8') as chars:
- self.char_list = yaml.load(chars)
- self.build_char_pages_ao1()
-
- def load_music(self):
- with open('config/music.yaml', 'r', encoding = 'utf-8') as music:
- self.music_list = yaml.load(music)
- self.build_music_pages_ao1()
- self.build_music_list_ao2()
-
- def load_ids(self):
- self.ipid_list = {}
- self.hdid_list = {}
- #load ipids
- try:
- with open('storage/ip_ids.json', 'r', encoding = 'utf-8') as whole_list:
- self.ipid_list = json.loads(whole_list.read())
- except:
- logger.log_debug('Failed to load ip_ids.json from ./storage. If ip_ids.json is exist then remove it.')
- #load hdids
- try:
- with open('storage/hd_ids.json', 'r', encoding = 'utf-8') as whole_list:
- self.hdid_list = json.loads(whole_list.read())
- except:
- logger.log_debug('Failed to load hd_ids.json from ./storage. If hd_ids.json is exist then remove it.')
-
- def dump_ipids(self):
- with open('storage/ip_ids.json', 'w') as whole_list:
- json.dump(self.ipid_list, whole_list)
-
- def dump_hdids(self):
- with open('storage/hd_ids.json', 'w') as whole_list:
- json.dump(self.hdid_list, whole_list)
-
- def get_ipid(self, ip):
- if not (ip in self.ipid_list):
- self.ipid_list[ip] = len(self.ipid_list)
- self.dump_ipids()
- return self.ipid_list[ip]
-
- def load_backgrounds(self):
- with open('config/backgrounds.yaml', 'r', encoding = 'utf-8') as bgs:
- self.backgrounds = yaml.load(bgs)
-
- def load_iniswaps(self):
- try:
- with open('config/iniswaps.yaml', 'r', encoding = 'utf-8') as iniswaps:
- self.allowed_iniswaps = yaml.load(iniswaps)
- except:
- logger.log_debug('cannot find iniswaps.yaml')
-
-
- def build_char_pages_ao1(self):
- self.char_pages_ao1 = [self.char_list[x:x + 10] for x in range(0, len(self.char_list), 10)]
- for i in range(len(self.char_list)):
- self.char_pages_ao1[i // 10][i % 10] = '{}#{}&&0&&&0&'.format(i, self.char_list[i])
-
- def build_music_pages_ao1(self):
- self.music_pages_ao1 = []
- index = 0
- # add areas first
- for area in self.area_manager.areas:
- self.music_pages_ao1.append('{}#{}'.format(index, area.name))
- index += 1
- # then add music
- for item in self.music_list:
- self.music_pages_ao1.append('{}#{}'.format(index, item['category']))
- index += 1
- for song in item['songs']:
- self.music_pages_ao1.append('{}#{}'.format(index, song['name']))
- index += 1
- self.music_pages_ao1 = [self.music_pages_ao1[x:x + 10] for x in range(0, len(self.music_pages_ao1), 10)]
-
- def build_music_list_ao2(self):
- self.music_list_ao2 = []
- # add areas first
- for area in self.area_manager.areas:
- self.music_list_ao2.append(area.name)
- # then add music
- for item in self.music_list:
- self.music_list_ao2.append(item['category'])
- for song in item['songs']:
- self.music_list_ao2.append(song['name'])
-
- def is_valid_char_id(self, char_id):
- return len(self.char_list) > char_id >= 0
-
- def get_char_id_by_name(self, name):
- for i, ch in enumerate(self.char_list):
- if ch.lower() == name.lower():
- return i
- raise ServerError('Character not found.')
-
- def get_song_data(self, music):
- for item in self.music_list:
- if item['category'] == music:
- return item['category'], -1
- for song in item['songs']:
- if song['name'] == music:
- try:
- return song['name'], song['length']
- except KeyError:
- return song['name'], -1
- raise ServerError('Music not found.')
-
- def send_all_cmd_pred(self, cmd, *args, pred=lambda x: True):
- for client in self.client_manager.clients:
- if pred(client):
- client.send_command(cmd, *args)
-
- def broadcast_global(self, client, msg, as_mod=False):
- char_name = client.get_char_name()
- ooc_name = '{}[{}][{}]'.format('<dollar>G', client.area.abbreviation, char_name)
- if as_mod:
- ooc_name += '[M]'
- self.send_all_cmd_pred('CT', ooc_name, msg, pred=lambda x: not x.muted_global)
- if self.config['use_district']:
- self.district_client.send_raw_message(
- 'GLOBAL#{}#{}#{}#{}'.format(int(as_mod), client.area.id, char_name, msg))
-
- def send_modchat(self, client, msg):
- name = client.name
- ooc_name = '{}[{}][{}]'.format('<dollar>M', client.area.abbreviation, name)
- self.send_all_cmd_pred('CT', ooc_name, msg, pred=lambda x: x.is_mod)
- if self.config['use_district']:
- self.district_client.send_raw_message(
- 'MODCHAT#{}#{}#{}'.format(client.area.id, char_name, msg))
-
- def broadcast_need(self, client, msg):
- char_name = client.get_char_name()
- area_name = client.area.name
- area_id = client.area.abbreviation
- self.send_all_cmd_pred('CT', '{}'.format(self.config['hostname']),
- ['=== Advert ===\r\n{} in {} [{}] needs {}\r\n==============='
- .format(char_name, area_name, area_id, msg), '1'], pred=lambda x: not x.muted_adverts)
- if self.config['use_district']:
- self.district_client.send_raw_message('NEED#{}#{}#{}#{}'.format(char_name, area_name, area_id, msg))
-
- def send_arup(self, args):
- """ Updates the area properties on the Case Café Custom Client.
-
- Playercount:
- ARUP#0#<area1_p: int>#<area2_p: int>#...
- Status:
- ARUP#1##<area1_s: string>##<area2_s: string>#...
- CM:
- ARUP#2##<area1_cm: string>##<area2_cm: string>#...
- Lockedness:
- ARUP#3##<area1_l: string>##<area2_l: string>#...
-
- """
- if len(args) < 2:
- # An argument count smaller than 2 means we only got the identifier of ARUP.
- return
- if args[0] not in (0,1,2,3):
- return
-
- if args[0] == 0:
- for part_arg in args[1:]:
- try:
- sanitised = int(part_arg)
- except:
- return
- elif args[0] in (1, 2, 3):
- for part_arg in args[1:]:
- try:
- sanitised = str(part_arg)
- except:
- return
-
- self.send_all_cmd_pred('ARUP', *args, pred=lambda x: True)
-
- def refresh(self):
- with open('config/config.yaml', 'r') as cfg:
- self.config['motd'] = yaml.load(cfg)['motd'].replace('\\n', ' \n')
- with open('config/characters.yaml', 'r') as chars:
- self.char_list = yaml.load(chars)
- with open('config/music.yaml', 'r') as music:
- self.music_list = yaml.load(music)
- self.build_music_pages_ao1()
- self.build_music_list_ao2()
- with open('config/backgrounds.yaml', 'r') as bgs:
- self.backgrounds = yaml.load(bgs)
diff --git a/server/websocket.py b/server/websocket.py
deleted file mode 100644
index ba4258f3..00000000
--- a/server/websocket.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# tsuserver3, an Attorney Online server
-#
-# Copyright (C) 2017 argoneus <argoneuscze@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# Partly authored by Johan Hanssen Seferidis (MIT license):
-# https://github.com/Pithikos/python-websocket-server
-
-import asyncio
-import re
-import struct
-from base64 import b64encode
-from hashlib import sha1
-
-from server import logger
-
-
-class Bitmasks:
- FIN = 0x80
- OPCODE = 0x0f
- MASKED = 0x80
- PAYLOAD_LEN = 0x7f
- PAYLOAD_LEN_EXT16 = 0x7e
- PAYLOAD_LEN_EXT64 = 0x7f
-
-
-class Opcode:
- CONTINUATION = 0x0
- TEXT = 0x1
- BINARY = 0x2
- CLOSE_CONN = 0x8
- PING = 0x9
- PONG = 0xA
-
-
-class WebSocket:
- """
- State data for clients that are connected via a WebSocket that wraps
- over a conventional TCP connection.
- """
-
- def __init__(self, client, protocol):
- self.client = client
- self.transport = client.transport
- self.protocol = protocol
- self.keep_alive = True
- self.handshake_done = False
- self.valid = False
-
- def handle(self, data):
- if not self.handshake_done:
- return self.handshake(data)
- return self.parse(data)
-
- def parse(self, data):
- b1, b2 = 0, 0
- if len(data) >= 2:
- b1, b2 = data[0], data[1]
-
- fin = b1 & Bitmasks.FIN
- opcode = b1 & Bitmasks.OPCODE
- masked = b2 & Bitmasks.MASKED
- payload_length = b2 & Bitmasks.PAYLOAD_LEN
-
- if not b1:
- # Connection closed
- self.keep_alive = 0
- return
- if opcode == Opcode.CLOSE_CONN:
- # Connection close requested
- self.keep_alive = 0
- return
- if not masked:
- # Client was not masked (spec violation)
- logger.log_debug("ws: client was not masked.", self.client)
- self.keep_alive = 0
- print(data)
- return
- if opcode == Opcode.CONTINUATION:
- # No continuation frames supported
- logger.log_debug("ws: client tried to send continuation frame.", self.client)
- return
- elif opcode == Opcode.BINARY:
- # No binary frames supported
- logger.log_debug("ws: client tried to send binary frame.", self.client)
- return
- elif opcode == Opcode.TEXT:
- def opcode_handler(s, msg):
- return msg
- elif opcode == Opcode.PING:
- opcode_handler = self.send_pong
- elif opcode == Opcode.PONG:
- opcode_handler = lambda s, msg: None
- else:
- # Unknown opcode
- logger.log_debug("ws: unknown opcode!", self.client)
- self.keep_alive = 0
- return
-
- mask_offset = 2
- if payload_length == 126:
- payload_length = struct.unpack(">H", data[2:4])[0]
- mask_offset = 4
- elif payload_length == 127:
- payload_length = struct.unpack(">Q", data[2:10])[0]
- mask_offset = 10
-
- masks = data[mask_offset:mask_offset + 4]
- decoded = ""
- for char in data[mask_offset + 4:payload_length + mask_offset + 4]:
- char ^= masks[len(decoded) % 4]
- decoded += chr(char)
-
- return opcode_handler(self, decoded)
-
- def send_message(self, message):
- self.send_text(message)
-
- def send_pong(self, message):
- self.send_text(message, Opcode.PONG)
-
- def send_text(self, message, opcode=Opcode.TEXT):
- """
- Important: Fragmented (continuation) messages are not supported since
- their usage cases are limited - when we don't know the payload length.
- """
-
- # Validate message
- if isinstance(message, bytes):
- message = message.decode("utf-8")
- elif isinstance(message, str):
- pass
- else:
- raise TypeError("Message must be either str or bytes")
-
- header = bytearray()
- payload = message.encode("utf-8")
- payload_length = len(payload)
-
- # Normal payload
- if payload_length <= 125:
- header.append(Bitmasks.FIN | opcode)
- header.append(payload_length)
-
- # Extended payload
- elif payload_length >= 126 and payload_length <= 65535:
- header.append(Bitmasks.FIN | opcode)
- header.append(Bitmasks.PAYLOAD_LEN_EXT16)
- header.extend(struct.pack(">H", payload_length))
-
- # Huge extended payload
- elif payload_length < (1 << 64):
- header.append(Bitmasks.FIN | opcode)
- header.append(Bitmasks.PAYLOAD_LEN_EXT64)
- header.extend(struct.pack(">Q", payload_length))
-
- else:
- raise Exception("Message is too big")
-
- self.transport.write(header + payload)
-
- def handshake(self, data):
- try:
- message = data[0:1024].decode().strip()
- except UnicodeDecodeError:
- return False
-
- upgrade = re.search('\nupgrade[\s]*:[\s]*websocket', message.lower())
- if not upgrade:
- self.keep_alive = False
- return False
-
- key = re.search('\n[sS]ec-[wW]eb[sS]ocket-[kK]ey[\s]*:[\s]*(.*)\r\n', message)
- if key:
- key = key.group(1)
- else:
- logger.log_debug("Client tried to connect but was missing a key", self.client)
- self.keep_alive = False
- return False
-
- response = self.make_handshake_response(key)
- print(response.encode())
- self.transport.write(response.encode())
- self.handshake_done = True
- self.valid = True
- return True
-
- def make_handshake_response(self, key):
- return \
- 'HTTP/1.1 101 Switching Protocols\r\n'\
- 'Upgrade: websocket\r\n' \
- 'Connection: Upgrade\r\n' \
- 'Sec-WebSocket-Accept: %s\r\n' \
- '\r\n' % self.calculate_response_key(key)
-
- def calculate_response_key(self, key):
- GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
- hash = sha1(key.encode() + GUID.encode())
- response_key = b64encode(hash.digest()).strip()
- return response_key.decode('ASCII')
-
- def finish(self):
- self.protocol.connection_lost(self)