def sendMessage(sender="", target="", message="", token=None, toIRC=True): """ Send a message to osu!bancho and IRC server :param sender: sender username. Optional. token can be used instead :param target: receiver channel (if starts with #) or username :param message: text of the message :param token: sender token object. Optional. sender can be used instead :param toIRC: if True, send the message to IRC. If False, send it to Bancho only. Default: True :return: 0 if joined or other IRC code in case of error. Needed only on IRC-side """ reencode = lambda s: s.encode('latin-1').decode('utf-8') try: #tokenString = "" # Get token object if not passed if token is None: token = glob.tokens.getTokenFromUsername(sender) if token is None: raise exceptions.userNotFoundException() else: # token object alredy passed, get its string and its username (sender) sender = token.username #tokenString = token.token # Make sure this is not a tournament client # if token.tournament: # raise exceptions.userTournamentException() # Make sure the user is not in restricted mode if token.restricted: raise exceptions.userRestrictedException() # Make sure the user is not silenced if token.isSilenced(): raise exceptions.userSilencedException() if target in chatChannels.RESERVED_CHANNELS: sendMessage(glob.BOT_NAME, token.username, "\x01ACTION gaplok kamu\x01") token.enqueue(serverPackets.notification("You have been gaplok'd")) return 403 # Bancho style. isAPI = sender == glob.BOT_NAME and message.startswith( "\x02YOHANE ") and message.endswith("\x02") isSPub = target.startswith( f"{chatChannels.SPECTATOR_PREFIX}_") or target.startswith( f"{chatChannels.MULTIPLAYER_PREFIX}_") or target in ( chatChannels.SPECTATOR_MASK, chatChannels.MULTIPLAYER_MASK) forBot = target.lower() == glob.BOT_NAME.lower() botCommand = (target[0] == '#' and message[0] == '!') or forBot if isAPI: message = message[8:-1] if botCommand and not isAPI: redirectBot = not (token.admin or isSPub or target.lower() == chatChannels.SPECIAL_CHANNEL) if target[0] == '#' or forBot: pass if redirectBot: target = glob.BOT_NAME log.info( f'Redirect {redirectBot} ({token.admin}/{isSPub}) -> {target}({forBot}) -> {message}' ) if message.lower().split()[0] in ('!help', '!report'): target = glob.BOT_NAME # Determine internal name if needed # (toclient is used clientwise for #multiplayer and #spectator channels) target, toClient = channelMasking(token, target, userID=token.userID) if target is None and toClient is None: return 0 isChannel = target.startswith("#") # Make sure the message is valid if not message.strip(): raise exceptions.invalidArgumentsException() # Truncate message if > 2048 characters message = message[:2048] + "..." if len(message) > 2048 else message # Check for word filters message = glob.chatFilters.filterMessage(message) # Build packet bytes packet = serverPackets.sendMessage(token.username, toClient, message) # Send the message to IRC if glob.irc and toIRC: messageSplitInLines = reencode(message).split("\n") for line in messageSplitInLines: if line == messageSplitInLines[:1] and line == "": continue glob.ircServer.banchoMessage(sender, target, line) # Spam protection (ignore the bot) if token.userID > 1 and not token.admin: token.spamProtection() # File and discord logs (public chat only) eligibleLogging = target.startswith("#") and not ( message.startswith("\x01ACTION is playing") and target.startswith(f"{chatChannels.SPECTATOR_PREFIX}_")) # this one is to mark "!" usage, as those are thrown directly to the bot. eligibleLogging = eligibleLogging or (target == glob.BOT_NAME and not forBot) if eligibleLogging: log.chat("{sender} @ {target}: {message}".format( sender=token.username, target=target, message=reencode(message))) glob.schiavo.sendChatlog( "**{sender} @ {target}:** {message}".format( sender=token.username, target=target, message=reencode(message))) # Send the message if isChannel: # CHANNEL # Make sure the channel exists if target not in glob.channels.channels: raise exceptions.channelUnknownException() # Make sure the channel is not in moderated mode if glob.channels.channels[target].moderated and not token.admin: raise exceptions.channelModeratedException() # Make sure we are in the channel if target not in token.joinedChannels: # I'm too lazy to put and test the correct IRC error code here... # but IRC is not strict at all so who cares raise exceptions.channelNoPermissionsException() # Make sure we have write permissions if not (token.admin or glob.channels.channels[target].publicWrite): raise exceptions.channelNoPermissionsException() # Add message in buffer token.addMessageInBuffer(target, message) # Everything seems fine, build recipients list and send packet glob.streams.broadcast("chat/{}".format(target), packet, but=[token.token]) else: # USER # Make sure recipient user is connected recipientToken = glob.tokens.getTokenFromUsername(target) if recipientToken is None: raise exceptions.userNotFoundException() # Make sure the recipient is not a tournament client if recipientToken.tournament: raise exceptions.userTournamentException() if recipientToken.ignoreDM: targetFriends = userUtils.getFriendList(recipientToken.userID) if sender != glob.BOT_NAME and token.userID not in targetFriends and not token.admin: packet = serverPackets.userDeniedMessage( token.username, toClient, message) token.enqueue(packet) raise exceptions.userBlockedPrivateException() # Make sure the recipient is not restricted or we are the bot if recipientToken.restricted and sender.lower( ) != glob.BOT_NAME.lower(): raise exceptions.userRestrictedException() # TODO: Make sure the recipient has not disabled PMs for non-friends or he's our friend # Away check if recipientToken.awayCheck(token.userID): sendMessage( target, sender, "\x01ACTION is away: {}\x01".format( recipientToken.awayMessage)) # Check message templates (mods/admins only) if message in messageTemplates.templates and token.admin: sendMessage(sender, target, messageTemplates.templates[message]) # Everything seems fine, send packet recipientToken.enqueue(packet) # Bot must not react to their own message. if sender == glob.BOT_NAME and not isAPI: return 0 # Some bot message if (isChannel or target == glob.BOT_NAME): if botCommand or isAPI: msgOffset = 0 if forBot else 1 da10Message = fokabot.fokabotCommands(token, token.username, target, message[msgOffset:]) else: da10Message = fokabot.fokabotResponse(token, token.username, target, message) if da10Message: sendMessage(glob.BOT_NAME, target if isChannel else sender, da10Message) return 0 except exceptions.userSilencedException: token.enqueue( serverPackets.silenceEndTime(token.getSilenceSecondsLeft())) log.warning("{} tried to send a message during silence".format( token.username)) return 404 except exceptions.channelModeratedException: log.warning( "{} tried to send a message to a channel that is in moderated mode ({})" .format(token.username, target)) return 404 except exceptions.channelUnknownException: log.warning( "{} tried to send a message to an unknown channel ({})".format( token.username, target)) return 403 except exceptions.channelNoPermissionsException: log.warning( "{} tried to send a message to channel {}, but they have no write permissions" .format(token.username, target)) return 404 except exceptions.userRestrictedException: log.warning( "{} tried to send a message {}, but the recipient is in restricted mode" .format(token.username, target)) return 404 except exceptions.userTournamentException: log.warning( "{} tried to send a message {}, but the recipient is a tournament client" .format(token.username, target)) return 404 except exceptions.userNotFoundException: log.warning("User not connected to IRC/Bancho") return 401 except exceptions.userBlockedPrivateException: return 404 except exceptions.invalidArgumentsException: log.warning("{} tried to send an invalid message to {}".format( token.username, target)) return 404
def sendMessage(fro="", to="", message="", token=None, toIRC=True): """ Send a message to osu!bancho and IRC server :param fro: sender username. Optional. token can be used instead :param to: receiver channel (if starts with #) or username :param message: text of the message :param token: sender token object. Optional. fro can be used instead :param toIRC: if True, send the message to IRC. If False, send it to Bancho only. Default: True :return: 0 if joined or other IRC code in case of error. Needed only on IRC-side """ try: #tokenString = "" # Get token object if not passed if token is None: token = glob.tokens.getTokenFromUsername(fro) if token is None: raise exceptions.userNotFoundException() else: # token object alredy passed, get its string and its username (fro) fro = token.username #tokenString = token.token # Make sure this is not a tournament client # if token.tournament: # raise exceptions.userTournamentException() # Make sure the user is not in restricted mode if token.restricted: raise exceptions.userRestrictedException() # Make sure the user is not silenced if token.isSilenced(): raise exceptions.userSilencedException() # Redirect !report to the bot if message.startswith("!report"): to = glob.BOT_NAME # Determine internal name if needed # (toclient is used clientwise for #multiplayer and #spectator channels) toClient = to if to == "#spectator": if token.spectating is None: s = token.userID else: s = token.spectatingUserID to = "#spect_{}".format(s) elif to == "#multiplayer": to = "#multi_{}".format(token.matchID) elif to.startswith("#spect_"): toClient = "#spectator" elif to.startswith("#multi_"): toClient = "#multiplayer" # Make sure the message is valid if not message.strip(): raise exceptions.invalidArgumentsException() # Truncate message if > 2048 characters message = message[:2048] + "..." if len(message) > 2048 else message # Check for word filters message = glob.chatFilters.filterMessage(message) # Build packet bytes packet = serverPackets.sendMessage(token.username, toClient, message) # Send the message isChannel = to.startswith("#") if isChannel: # CHANNEL # Make sure the channel exists if to not in glob.channels.channels: raise exceptions.channelUnknownException() # Make sure the channel is not in moderated mode if glob.channels.channels[to].moderated and not token.admin: raise exceptions.channelModeratedException() # Make sure we are in the channel if to not in token.joinedChannels: # I'm too lazy to put and test the correct IRC error code here... # but IRC is not strict at all so who cares raise exceptions.channelNoPermissionsException() # Make sure we have write permissions if not glob.channels.channels[to].publicWrite and not token.admin: raise exceptions.channelNoPermissionsException() # Add message in buffer token.addMessageInBuffer(to, message) # Everything seems fine, build recipients list and send packet glob.streams.broadcast("chat/{}".format(to), packet, but=[token.token]) else: # USER # Make sure recipient user is connected recipientToken = glob.tokens.getTokenFromUsername(to) if recipientToken is None: raise exceptions.userNotFoundException() # Make sure the recipient is not a tournament client #if recipientToken.tournament: # raise exceptions.userTournamentException() # Make sure the recipient is not restricted or we are the bot if recipientToken.restricted and fro.lower( ) != glob.BOT_NAME.lower(): raise exceptions.userRestrictedException() # TODO: Make sure the recipient has not disabled PMs for non-friends or he's our friend # Away check if recipientToken.awayCheck(token.userID): sendMessage( to, fro, "\x01ACTION is away: {}\x01".format( recipientToken.awayMessage)) # Everything seems fine, send packet recipientToken.enqueue(packet) # Send the message to IRC if glob.irc and toIRC: messageSplitInLines = message.encode("latin-1").decode( "utf-8").split("\n") for line in messageSplitInLines: if line == messageSplitInLines[:1] and line == "": continue glob.ircServer.banchoMessage(fro, to, line) # Spam protection (ignore the bot) if token.userID > 999: token.spamProtection() # Some bot message if isChannel or to.lower() == glob.BOT_NAME.lower(): fokaMessage = fokabot.fokabotResponse(token.username, to, message) if fokaMessage: sendMessage(glob.BOT_NAME, to if isChannel else fro, fokaMessage) # File and discord logs (public chat only) if to.startswith("#") and not ( message.startswith("\x01ACTION is playing") and to.startswith("#spect_")): log.chat("{fro} @ {to}: {message}".format( fro=token.username, to=to, message=message.encode("latin-1").decode("utf-8"))) glob.schiavo.sendChatlog("**{fro} @ {to}:** {message}".format( fro=token.username, to=to, message=message.encode("latin-1").decode("utf-8"))) return 0 except exceptions.userSilencedException: token.enqueue( serverPackets.silenceEndTime(token.getSilenceSecondsLeft())) log.warning("{} tried to send a message during silence".format( token.username)) return 404 except exceptions.channelModeratedException: log.warning( "{} tried to send a message to a channel that is in moderated mode ({})" .format(token.username, to)) return 404 except exceptions.channelUnknownException: log.warning( "{} tried to send a message to an unknown channel ({})".format( token.username, to)) return 403 except exceptions.channelNoPermissionsException: log.warning( "{} tried to send a message to channel {}, but they have no write permissions" .format(token.username, to)) return 404 except exceptions.userRestrictedException: log.warning( "{} tried to send a message {}, but the recipient is in restricted mode" .format(token.username, to)) return 404 except exceptions.userTournamentException: log.warning( "{} tried to send a message {}, but the recipient is a tournament client" .format(token.username, to)) return 404 except exceptions.userNotFoundException: log.warning("User not connected to IRC/Bancho") return 401 except exceptions.invalidArgumentsException: log.warning("{} tried to send an invalid message to {}".format( token.username, to)) return 404
def sendMessage(fro="", to="", message="", token=None, toIRC=True): """ Send a message to osu!bancho and IRC server :param fro: sender username. Optional. token can be used instead :param to: receiver channel (if starts with #) or username :param message: text of the message :param token: sender token object. Optional. fro can be used instead :param toIRC: if True, send the message to IRC. If False, send it to Bancho only. Default: True :return: 0 if joined or other IRC code in case of error. Needed only on IRC-side """ try: #tokenString = "" # Get token object if not passed if token is None: token = glob.tokens.getTokenFromUsername(fro) if token is None: raise exceptions.userNotFoundException() else: # token object alredy passed, get its string and its username (fro) fro = token.username #tokenString = token.token # Make sure this is not a tournament client # if token.tournament: # raise exceptions.userTournamentException() # Make sure the user is not in restricted mode if token.restricted: raise exceptions.userRestrictedException() # Make sure the user is not silenced if token.isSilenced(): raise exceptions.userSilencedException() # Redirect !report to the bot if message.startswith("!report"): to = glob.BOT_NAME #here is a filter for REALLY bad words. while we will allow things such as f**k, we dont want the community to be really toxic and unwelcoming #TODO: unhardcode this MessageList = message.split( " ") #makes it easier to analyse and filter ReallyBadWords = [ #also realistik was here "nazi", "testword1", #so i can test without saying a really bad word! "nigger", #ah the classic "n***a", "coon", ## GERMAN ## "hurensohn", ## RUSSIAN ## "хуесос", "пидорас", "пидр" ] # we EXTERMINATE THE BAD BAD WORDS!!!! FinalMessage = "" for Word in MessageList: #ik there is a better way of doing this but this is the only way i could come up with that ignored caps for BadWord in ReallyBadWords: if BadWord in Word: Word = "#########" #TODO: make the amount of hashes be the lenght of the word FinalMessage += f"{Word} " message = FinalMessage[:-1] #removes the last space # Determine internal name if needed # (toclient is used clientwise for #multiplayer and #spectator channels) toClient = to if to == "#spectator": if token.spectating is None: s = token.userID else: s = token.spectatingUserID to = "#spect_{}".format(s) elif to == "#multiplayer": to = "#multi_{}".format(token.matchID) elif to.startswith("#spect_"): toClient = "#spectator" elif to.startswith("#multi_"): toClient = "#multiplayer" # Make sure the message is valid if not message.strip(): raise exceptions.invalidArgumentsException() # Truncate message if > 2048 characters message = message[:2048] + "..." if len(message) > 2048 else message # Check for word filters message = glob.chatFilters.filterMessage(message) # Build packet bytes packet = serverPackets.sendMessage(token.username, toClient, message) # Send the message isChannel = to.startswith("#") if isChannel: # CHANNEL # Make sure the channel exists if to not in glob.channels.channels: raise exceptions.channelUnknownException() # Make sure the channel is not in moderated mode if glob.channels.channels[to].moderated and not token.admin: raise exceptions.channelModeratedException() # Make sure we are in the channel if to not in token.joinedChannels: # I'm too lazy to put and test the correct IRC error code here... # but IRC is not strict at all so who cares raise exceptions.channelNoPermissionsException() # Make sure we have write permissions if not glob.channels.channels[to].publicWrite and not token.admin: raise exceptions.channelNoPermissionsException() # Add message in buffer token.addMessageInBuffer(to, message) # Everything seems fine, build recipients list and send packet glob.streams.broadcast("chat/{}".format(to), packet, but=[token.token]) else: # USER # Make sure recipient user is connected recipientToken = glob.tokens.getTokenFromUsername(to) if recipientToken is None: raise exceptions.userNotFoundException() # Make sure the recipient is not a tournament client #if recipientToken.tournament: # raise exceptions.userTournamentException() # Make sure the recipient is not restricted or we are your bot if recipientToken.restricted and fro.lower( ) != glob.BOT_NAME.lower: raise exceptions.userRestrictedException() # TODO: Make sure the recipient has not disabled PMs for non-friends or he's our friend # Away check if recipientToken.awayCheck(token.userID): sendMessage( to, fro, "\x01ACTION is away: {}\x01".format( recipientToken.awayMessage)) # Check message templates (mods/admins only) if message in messageTemplates.templates and token.admin: sendMessage(fro, to, messageTemplates.templates[message]) # Everything seems fine, send packet recipientToken.enqueue(packet) # Send the message to IRC if glob.irc and toIRC: messageSplitInLines = message.encode("latin-1").decode( "utf-8").split("\n") for line in messageSplitInLines: if line == messageSplitInLines[:1] and line == "": continue glob.ircServer.banchoMessage(fro, to, line) # Spam protection (ignore your bot) if token.userID > 999: token.spamProtection() # bot message if isChannel or to.lower() == glob.BOT_NAME.lower: fokaMessage = fokabot.fokabotResponse(token.username, to, message) if fokaMessage: sendMessage(glob.BOT_NAME, to if isChannel else fro, fokaMessage) # File and discord logs (public chat only) if to.startswith("#") and not ( message.startswith("\x01ACTION is playing") and to.startswith("#spect_")): log.chat("{fro} @ {to}: {message}".format( fro=token.username, to=to, message=message.encode("latin-1").decode("utf-8"))) glob.schiavo.sendChatlog("**{fro} @ {to}:** {message}".format( fro=token.username, to=to, message=message.encode("latin-1").decode("utf-8"))) return 0 except exceptions.userSilencedException: token.enqueue( serverPackets.silenceEndTime(token.getSilenceSecondsLeft())) log.warning("{} tried to send a message during silence".format( token.username)) return 404 except exceptions.channelModeratedException: log.warning( "{} tried to send a message to a channel that is in moderated mode ({})" .format(token.username, to)) return 404 except exceptions.channelUnknownException: log.warning( "{} tried to send a message to an unknown channel ({})".format( token.username, to)) return 403 except exceptions.channelNoPermissionsException: log.warning( "{} tried to send a message to channel {}, but they have no write permissions" .format(token.username, to)) return 404 except exceptions.userRestrictedException: log.warning( "{} tried to send a message {}, but the recipient is in restricted mode" .format(token.username, to)) return 404 except exceptions.userTournamentException: log.warning( "{} tried to send a message {}, but the recipient is a tournament client" .format(token.username, to)) return 404 except exceptions.userNotFoundException: log.warning("User not connected to IRC/Bancho") return 401 except exceptions.invalidArgumentsException: log.warning("{} tried to send an invalid message to {}".format( token.username, to)) return 404