Exemple #1
0
def report(fro, chan, message):
    msg = ""
    try:
        # TODO: Rate limit
        # Get username, report reason and report info
        target, reason, additionalInfo = message[0], message[1], message[2]
        target = chat.fixUsernameForBancho(target)

        # Make sure the target is not foka
        if target == glob.BOT_NAME:
            raise exceptions.invalidUserException()

        # Make sure the user exists
        targetID = userUtils.getID(target)
        if targetID == 0:
            raise exceptions.userNotFoundException()

        # Make sure that the user has specified additional info if report reason is 'Other'
        if reason.lower() == "other" and not additionalInfo:
            raise exceptions.missingReportInfoException()

        # Get the token if possible
        chatlog = ""
        token = glob.tokens.getTokenFromUsername(userUtils.safeUsername(target), safe=True)
        if token is not None:
            chatlog = token.getMessagesBufferString()

        # Everything is fine, submit report
        glob.db.execute(
            "INSERT INTO reports (id, from_uid, to_uid, reason, chatlog, time, assigned) VALUES (NULL, %s, %s, %s, %s, %s, 0)",
            [userUtils.getID(fro), targetID, "{reason} - ingame {info}".format(reason=reason, info="({})".format(
                additionalInfo) if additionalInfo is not None else ""), chatlog, int(time.time())])
        msg = "You've reported {target} for {reason}{info}. A Community Manager will check your report as soon as possible. Every !report message you may see in chat wasn't sent to anyone, so nobody in chat, but admins, know about your report. Thank you for reporting!".format(
            target=target, reason=reason, info="" if additionalInfo is None else " (" + additionalInfo + ")")
        adminMsg = "{user} has reported {target} for {reason} ({info})".format(user=fro, target=target, reason=reason,
                                                                               info=additionalInfo)

        # Log report in #admin and on discord
        chat.sendMessage(glob.BOT_NAME, "#admin", adminMsg)
        log.warning(adminMsg, discord="cm")
    except exceptions.invalidUserException:
        msg = "Hello, {} here! You can't report me. I won't forget what you've tried to do. Watch out.".format(
            glob.BOT_NAME)
    except exceptions.invalidArgumentsException:
        msg = "Invalid report command syntax. To report an user, click on it and select 'Report user'."
    except exceptions.userNotFoundException:
        msg = "The user you've tried to report doesn't exist."
    except exceptions.missingReportInfoException:
        msg = "Please specify the reason of your report."
    except:
        raise
    finally:
        if msg != "":
            token = glob.tokens.getTokenFromUsername(fro)
            if token is not None:
                if token.irc:
                    chat.sendMessage(glob.BOT_NAME, fro, msg)
                else:
                    token.enqueue(serverPackets.notification(msg))
    return False
Exemple #2
0
 def mpKick():
     if len(message) < 2:
         raise exceptions.invalidArgumentsException(
             "Wrong syntax: !mp kick <username>")
     username = message[1]
     userID = userUtils.getIDSafe(username)
     if userID is None:
         raise exceptions.userNotFoundException("No such user")
     _match = glob.matches.matches[getMatchIDFromChannel(chan)]
     slotID = _match.getUserSlotID(userID)
     if slotID is None:
         raise exceptions.userNotFoundException(
             "The specified user is not in this match")
     for i in range(0, 2):
         _match.toggleSlotLocked(slotID)
     return "{} has been kicked from the match.".format(username)
Exemple #3
0
 def mp_invite():
     userID = userUtils.getID(fro)
     if not can_user_touch_lobby(get_match_id_from_channel(chan), userID,
                                 True):
         return False
     if len(message) < 2:
         raise exceptions.invalidArgumentsException(
             "Wrong syntax: !mp invite <username>")
     username = message[1].strip()
     if not username:
         raise exceptions.invalidArgumentsException(
             "Please provide a username")
     userID = userUtils.getIDSafe(username)
     if userID is None:
         raise exceptions.userNotFoundException("No such user")
     token = glob.tokens.getTokenFromUserID(userID, ignoreIRC=True)
     if token is None:
         raise exceptions.invalidUserException(
             "That user is not connected to bancho right now.")
     _match = glob.matches.matches[get_match_id_from_channel(chan)]
     _match.invite(999, userID)
     token.enqueue(
         serverPackets.notification(
             "Please accept the invite you've just received from {} to "
             "enter your tourney match.".format(glob.BOT_NAME)))
     return "An invite to this match has been sent to {}".format(username)
Exemple #4
0
	def mpHost():
		if len(message) < 2:
			raise exceptions.invalidArgumentsException("Wrong syntax: !mp host <username>")
		username = message[1].strip()
		if not username:
			raise exceptions.invalidArgumentsException("Please provide a username")
		userID = userUtils.getIDSafe(username)
		if userID is None:
			raise exceptions.userNotFoundException("No such user")
		_match = glob.matches.matches[getMatchIDFromChannel(chan)]
		success = _match.setHost(userID)
		return "{} is now the host".format(username) if success else "Couldn't give host to {}".format(username)
Exemple #5
0
 def lookupUser(userStr):
     match = re.match(r'^#([1-9][0-9]*)$', userStr)
     if match:
         log.info(f"Special case {match.group(1)}")
         userID = int(match.group(1))
     else:
         userID = lookupUserID(userStr)
     if userID is None:
         raise exceptions.userNotFoundException('No such user.')
     if userID < 2:
         raise exceptions.invalidArgumentsException("\x01ACTION gaplok")
     return userID
Exemple #6
0
 def mp_kick():
     userID = userUtils.getID(fro)
     if not can_user_touch_lobby(get_match_id_from_channel(chan), userID,
                                 False, False):
         return False
     if len(message) < 2:
         raise exceptions.invalidArgumentsException(
             "Wrong syntax: !mp kick <username>")
     username = message[1].strip()
     if not username:
         raise exceptions.invalidArgumentsException(
             "Please provide a username")
     userID = userUtils.getIDSafe(username)
     if userID is None:
         raise exceptions.userNotFoundException("No such user")
     _match = glob.matches.matches[get_match_id_from_channel(chan)]
     slotID = _match.getUserSlotID(userID)
     if slotID is None:
         raise exceptions.userNotFoundException(
             "The specified user is not in this match")
     for i in range(0, 2):
         _match.toggleSlotLocked(slotID)
     return "{} has been kicked from the match.".format(username)
Exemple #7
0
	def mpMove():
		if len(message) < 3 or not message[2].isdigit() or int(message[2]) < 0 or int(message[2]) > 16:
			raise exceptions.invalidArgumentsException("Wrong syntax: !mp move <username> <slot>")
		username = message[1]
		newSlotID = int(message[2])
		userID = userUtils.getIDSafe(username)
		if userID is None:
			raise exceptions.userNotFoundException("No such user")
		_match = glob.matches.matches[getMatchIDFromChannel(chan)]
		success = _match.userChangeSlot(userID, newSlotID)
		if success:
			result = "Player {} moved to slot {}".format(username, newSlotID)
		else:
			result = "You can't use that slot: it's either already occupied by someone else or locked"
		return result
Exemple #8
0
	def mpTeam():
		if len(message) < 3:
			raise exceptions.invalidArgumentsException("Wrong syntax: !mp team <username> <colour>")
		username = message[1].strip()
		if not username:
			raise exceptions.invalidArgumentsException("Please provide a username")
		colour = message[2].lower().strip()
		if colour not in ["red", "blue"]:
			raise exceptions.invalidArgumentsException("Team colour must be red or blue")
		userID = userUtils.getIDSafe(username)
		if userID is None:
			raise exceptions.userNotFoundException("No such user")
		_match = glob.matches.matches[getMatchIDFromChannel(chan)]
		_match.changeTeam(userID, matchTeams.BLUE if colour == "blue" else matchTeams.RED)
		return "{} is now in {} team".format(username, colour)
Exemple #9
0
 def mpInvite():
     if len(message) < 2:
         raise exceptions.invalidArgumentsException(
             "Wrong syntax: !mp invite <username>")
     username = message[1]
     userID = userUtils.getIDSafe(username)
     if userID is None:
         raise exceptions.userNotFoundException("No such user")
     token = glob.tokens.getTokenFromUserID(userID, ignoreIRC=True)
     if token is None:
         raise exceptions.invalidUserException(
             "That user is not connected to bancho right now.")
     _match = glob.matches.matches[getMatchIDFromChannel(chan)]
     _match.invite(999, userID)
     token.enqueue(
         serverPackets.notification(
             "Please accept the invite you've just received from FokaBot to "
             "enter your tourney match."))
     return "An invite to this match has been sent to {}".format(username)
Exemple #10
0
 def kick(response, token, sender, channel, message):
     if len(message) < 1:
         raise exceptions.invalidArgumentsException(
             "Wrong syntax: !mp kick <username>")
     ensureMatchIdle(channel)
     username = message[0].strip()
     if not username:
         raise exceptions.invalidArgumentsException(
             "Please provide a username")
     userID = lookupUser(username)
     _match = getCurrentMatch(channel)
     slotID = _match.getUserSlotID(userID)
     if slotID is None:
         raise exceptions.userNotFoundException(
             "The specified user is not in this match")
     for i in range(2):
         _match.toggleSlotLocked(slotID)
     response.setContent(
         token, "{} has been kicked from the match.".format(username))
Exemple #11
0
def partChannel(userID=0,
                channel="",
                token=None,
                toIRC=True,
                kick=False,
                force=False):
    """
	Part a channel

	:param userID: user ID of the user that parts the channel. Optional. token can be used instead.
	:param token: user token object of user that parts the channel. Optional. userID can be used instead.
	:param channel: channel name
	:param toIRC: if True, send this channel join event to IRC. Must be true if joining from bancho. Optional. Default: True
	:param kick: if True, channel tab will be closed on client. Used when leaving lobby. Optional. Default: False
	:param force: whether to allow game clients to part #spect_ and #multi_ channels
	:return: 0 if joined or other IRC code in case of error. Needed only on IRC-side
	"""
    try:
        # Make sure the client is not drunk and sends partChannel when closing a PM tab
        if not channel.startswith("#"):
            return

        # Get token if not defined
        if token is None:
            token = glob.tokens.getTokenFromUserID(userID)
            # Make sure the token exists
            if token is None:
                raise exceptions.userNotFoundException()
        else:
            token = token

        # Determine internal/client name if needed
        # (toclient is used clientwise for #multiplayer and #spectator channels)
        channelClient = channel
        if channel == "#spectator":
            if token.spectating is None:
                s = userID
            else:
                s = token.spectatingUserID
            channel = "#spect_{}".format(s)
        elif channel == "#multiplayer":
            channel = "#multi_{}".format(token.matchID)
        elif channel.startswith("#spect_"):
            channelClient = "#spectator"
        elif channel.startswith("#multi_"):
            channelClient = "#multiplayer"

        # Make sure the channel exists
        if channel not in glob.channels.channels:
            raise exceptions.channelUnknownException()

        # Make sure a game client is not trying to join a #multi_ or #spect_ channel manually
        channelObject = glob.channels.channels[channel]
        if channelObject.isSpecial and not token.irc and not force:
            raise exceptions.channelUnknownException()

        # Make sure the user is in the channel
        if channel not in token.joinedChannels:
            raise exceptions.userNotInChannelException()

        # Part channel (token-side and channel-side)
        token.partChannel(channelObject)

        # Delete temporary channel if everyone left
        if "chat/{}".format(channelObject.name) in glob.streams.streams:
            if channelObject.temp and len(glob.streams.streams[
                    "chat/{}".format(channelObject.name)].clients) - 1 == 0:
                glob.channels.removeChannel(channelObject.name)

        # Force close tab if needed
        # NOTE: Maybe always needed, will check later
        if kick:
            token.enqueue(serverPackets.channelKicked(channelClient))

        # IRC part
        if glob.irc and toIRC:
            glob.ircServer.banchoPartChannel(token.username, channel)

        # Console output
        log.info("{} parted channel {} ({})".format(token.username, channel,
                                                    channelClient))

        # Return IRC code
        return 0
    except exceptions.channelUnknownException:
        log.warning("{} attempted to part an unknown channel ({})".format(
            token.username, channel))
        return 403
    except exceptions.userNotInChannelException:
        log.warning(
            "{} attempted to part {}, but he's not in that channel".format(
                token.username, channel))
        return 442
    except exceptions.userNotFoundException:
        log.warning("User not connected to IRC/Bancho")
        return 442  # idk
Exemple #12
0
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
Exemple #13
0
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
Exemple #14
0
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