예제 #1
0
def on_privmsg(cli, rawnick, chan, msg, *, notice=False):
    if notice and "!" not in rawnick or not rawnick:  # server notice; we don't care about those
        return

    if not users.equals(
            chan, users.Bot.nick
    ) and botconfig.IGNORE_HIDDEN_COMMANDS and not chan.startswith(
            tuple(hooks.Features["CHANTYPES"])):
        return

    if (notice and ((not users.equals(chan, users.Bot.nick)
                     and not botconfig.ALLOW_NOTICE_COMMANDS) or
                    (users.equals(chan, users.Bot.nick)
                     and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
        return  # not allowed in settings

    for fn in decorators.COMMANDS[""]:
        fn.caller(cli, rawnick, chan, msg)

    phase = var.PHASE
    for x in list(decorators.COMMANDS.keys()):
        if not users.equals(chan,
                            users.Bot.nick) and not msg.lower().startswith(
                                botconfig.CMD_CHAR):
            break  # channel message but no prefix; ignore
        if msg.lower().startswith(botconfig.CMD_CHAR + x):
            h = msg[len(x) + len(botconfig.CMD_CHAR):]
        elif not x or msg.lower().startswith(x):
            h = msg[len(x):]
        else:
            continue
        if not h or h[0] == " ":
            for fn in decorators.COMMANDS.get(x, []):
                if phase == var.PHASE:
                    fn.caller(cli, rawnick, chan, h.lstrip())
예제 #2
0
def on_privmsg(cli, rawnick, chan, msg, *, notice=False):
    if notice and "!" not in rawnick or not rawnick:  # server notice; we don't care about those
        return

    _ignore_locals_ = False
    if var.USER_DATA_LEVEL == 0 or var.CHANNEL_DATA_LEVEL == 0:
        _ignore_locals_ = True  # don't expose in tb if we're trying to anonymize stuff

    user = users.get(rawnick, allow_none=True)

    ch = chan.lstrip("".join(Features["PREFIX"]))

    if users.equals(chan, users.Bot.nick):  # PM
        target = users.Bot
    else:
        target = channels.get(ch, allow_none=True)

    if user is None or target is None:
        return

    wrapper = MessageDispatcher(user, target)

    if wrapper.public and botconfig.IGNORE_HIDDEN_COMMANDS and not chan.startswith(
            tuple(Features["CHANTYPES"])):
        return

    if (notice and
        ((wrapper.public and not botconfig.ALLOW_NOTICE_COMMANDS) or
         (wrapper.private and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
        return  # not allowed in settings

    for fn in decorators.COMMANDS[""]:
        fn.caller(var, wrapper, msg)

    parts = msg.split(sep=" ", maxsplit=1)
    key = parts[0].lower()
    if len(parts) > 1:
        message = parts[1].strip()
    else:
        message = ""

    if wrapper.public and not key.startswith(botconfig.CMD_CHAR):
        return  # channel message but no prefix; ignore
    parse_and_dispatch(var, wrapper, key, message)
예제 #3
0
def on_privmsg(cli, rawnick, chan, msg, *, notice=False, force_role=None):
    if notice and "!" not in rawnick or not rawnick: # server notice; we don't care about those
        return

    user = users._get(rawnick, allow_none=True) # FIXME

    if users.equals(chan, users.Bot.nick): # PM
        target = users.Bot
    else:
        target = channels.get(chan, allow_none=True)

    if user is None or target is None:
        return

    wrapper = MessageDispatcher(user, target)

    if wrapper.public and botconfig.IGNORE_HIDDEN_COMMANDS and not chan.startswith(tuple(hooks.Features["CHANTYPES"])):
        return

    if (notice and ((wrapper.public and not botconfig.ALLOW_NOTICE_COMMANDS) or
                    (wrapper.private and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
        return  # not allowed in settings

    if force_role is None: # if force_role isn't None, that indicates recursion; don't fire these off twice
        for fn in decorators.COMMANDS[""]:
            fn.caller(cli, rawnick, chan, msg)

    parts = msg.split(sep=" ", maxsplit=1)
    key = parts[0].lower()
    if len(parts) > 1:
        message = parts[1].lstrip()
    else:
        message = ""

    if wrapper.public and not key.startswith(botconfig.CMD_CHAR):
        return # channel message but no prefix; ignore

    if key.startswith(botconfig.CMD_CHAR):
        key = key[len(botconfig.CMD_CHAR):]

    if not key: # empty key ("") already handled above
        return

    # Don't change this into decorators.COMMANDS[key] even though it's a defaultdict,
    # as we don't want to insert bogus command keys into the dict.
    cmds = []
    phase = var.PHASE
    if user in get_participants():
        roles = get_all_roles(user)
        # A user can be a participant but not have a role, for example, dead vengeful ghost
        has_roles = len(roles) != 0
        if force_role is not None:
            roles &= {force_role} # only fire off role commands for the forced role

        common_roles = set(roles) # roles shared by every eligible role command
        have_role_cmd = False
        for fn in decorators.COMMANDS.get(key, []):
            if not fn.roles:
                cmds.append(fn)
                continue
            if roles.intersection(fn.roles):
                have_role_cmd = True
                cmds.append(fn)
                common_roles.intersection_update(fn.roles)

        if force_role is not None and not have_role_cmd:
            # Trying to force a non-role command with a role.
            # We allow non-role commands to execute if a role is forced if a role
            # command is also executed, as this would allow (for example) a bot admin
            # to add extra effects to all "kill" commands without needing to continually
            # update the list of roles which can use "kill". However, we don't want to
            # allow things like "wolf pstats" because that just doesn't make sense.
            return

        if has_roles and not common_roles:
            # getting here means that at least one of the role_cmds is disjoint
            # from the others. For example, augur see vs seer see when a bare see
            # is executed. In this event, display a helpful error message instructing
            # the user to resolve the ambiguity.
            common_roles = set(roles)
            info = [0,0]
            for fn in cmds:
                fn_roles = roles.intersection(fn.roles)
                if not fn_roles:
                    continue
                for role1 in common_roles:
                    info[0] = role1
                    break
                for role2 in fn_roles:
                    info[1] = role2
                    break
                common_roles &= fn_roles
                if not common_roles:
                    break
            wrapper.pm(messages["ambiguous_command"].format(key, info[0], info[1]))
            return
    elif force_role is None:
        cmds = decorators.COMMANDS.get(key, [])

    for fn in cmds:
        if phase == var.PHASE:
            # FIXME: pass in var, wrapper, message instead of cli, rawnick, chan, message
            fn.caller(cli, rawnick, chan, message)
예제 #4
0
    def caller(self, cli, rawnick, chan, rest):
        _ignore_locals_ = True
        if users.equals(chan, users.Bot.nick):
            chan = users.parse_rawnick_as_dict(rawnick)["nick"]

        largs = [cli, rawnick, chan, rest]

        cli, rawnick, chan, rest = largs
        nick, mode, ident, host = parse_nick(rawnick)

        if ident is None:
            ident = ""

        if host is None:
            host = ""

        if not self.raw_nick:
            largs[1] = nick

        if not self.pm and chan == nick:
            return # PM command, not allowed

        if not self.chan and chan != nick:
            return # channel command, not allowed

        if chan.startswith("#") and chan != botconfig.CHANNEL and not (self.flag or self.owner_only):
            if "" in self.cmds:
                return # don't have empty commands triggering in other channels
            for command in self.cmds:
                if command in botconfig.ALLOWED_ALT_CHANNELS_COMMANDS:
                    break
            else:
                return

        if nick not in var.USERS and not is_fake_nick(nick):
            return

        if nick in var.USERS and var.USERS[nick]["account"] != "*":
            acc = irc_lower(var.USERS[nick]["account"])
        else:
            acc = None
        ident = irc_lower(ident)
        host = host.lower()
        hostmask = nick + "!" + ident + "@" + host

        if "" in self.cmds:
            self.func(*largs)
            return

        if self.phases and var.PHASE not in self.phases:
            return

        if self.playing and (nick not in list_players() or users._get(nick) in var.DISCONNECTED):
            return

        for role in self.roles:
            if users._get(nick) in var.ROLES[role]:
                break
        else:
            if (self.nicks is not None and nick not in self.nicks) or self.roles:
                return

        if self.silenced and nick in var.SILENCED:
            if chan == nick:
                pm(cli, nick, messages["silenced"])
            else:
                cli.notice(nick, messages["silenced"])
            return

        if self.roles or (self.nicks is not None and nick in self.nicks):
            self.func(*largs) # don't check restrictions for role commands
            # Role commands might end the night if it's nighttime
            if var.PHASE == "night":
                from src.wolfgame import chk_nightdone
                chk_nightdone()
            return

        forced_owner_only = False
        if hasattr(botconfig, "OWNERS_ONLY_COMMANDS"):
            for command in self.cmds:
                if command in botconfig.OWNERS_ONLY_COMMANDS:
                    forced_owner_only = True
                    break

        owner = is_owner(nick, ident, host)
        if self.owner_only or forced_owner_only:
            if owner:
                adminlog(chan, rawnick, self.name, rest)
                self.func(*largs)
                return

            if chan == nick:
                pm(cli, nick, messages["not_owner"])
            else:
                cli.notice(nick, messages["not_owner"])
            return

        flags = var.FLAGS[hostmask] + var.FLAGS_ACCS[acc]
        admin = is_admin(nick, ident, host)
        if self.flag and (admin or owner):
            adminlog(chan, rawnick, self.name, rest)
            self.func(*largs)
            return

        denied_cmds = var.DENY[hostmask] | var.DENY_ACCS[acc]
        for command in self.cmds:
            if command in denied_cmds:
                if chan == nick:
                    pm(cli, nick, messages["invalid_permissions"])
                else:
                    cli.notice(nick, messages["invalid_permissions"])
                return

        if self.flag:
            if self.flag in flags:
                adminlog(chan, rawnick, self.name, rest)
                self.func(*largs)
                return
            elif chan == nick:
                pm(cli, nick, messages["not_an_admin"])
            else:
                cli.notice(nick, messages["not_an_admin"])
            return

        self.func(*largs)
예제 #5
0
    def caller(self, cli, rawnick, chan, rest):
        _ignore_locals_ = True
        user = users._get(rawnick, allow_none=True) # FIXME

        if users.equals(chan, users.Bot.nick): # PM
            target = users.Bot
        else:
            target = channels.get(chan, allow_none=True)

        if user is None or target is None:
            return

        dispatcher = MessageDispatcher(user, target)

        if (not self.pm and dispatcher.private) or (not self.chan and dispatcher.public):
            return # channel or PM command that we don't allow

        if dispatcher.public and target is not channels.Main and not (self.flag or self.owner_only):
            if "" in self.commands or not self.alt_allowed:
                return # commands not allowed in alt channels

        if "" in self.commands:
            self.func(var, dispatcher, rest)
            return

        if self.phases and var.PHASE not in self.phases:
            return

        if self.playing and (user not in get_players() or user in var.DISCONNECTED):
            return

        for role in self.roles:
            if user in var.ROLES[role]:
                break
        else:
            if (self.users is not None and user not in self.users) or self.roles:
                return

        if self.silenced and user.nick in var.SILENCED: # FIXME: Need to change this once var.SILENCED holds User instances
            dispatcher.pm(messages["silenced"])
            return

        if self.roles or (self.users is not None and user in self.users):
            self.func(var, dispatcher, rest) # don't check restrictions for role commands
            # Role commands might end the night if it's nighttime
            if var.PHASE == "night":
                from src.wolfgame import chk_nightdone
                chk_nightdone()
            return

        if self.owner_only:
            if user.is_owner():
                adminlog(chan, rawnick, self.name, rest)
                self.func(var, dispatcher, rest)
                return

            dispatcher.pm(messages["not_owner"])
            return

        temp = user.lower()

        flags = var.FLAGS[temp.rawnick] + var.FLAGS_ACCS[temp.account] # TODO: add flags handling to User

        if self.flag and (user.is_admin() or user.is_owner()):
            adminlog(chan, rawnick, self.name, rest)
            return self.func(var, dispatcher, rest)

        denied_commands = var.DENY[temp.rawnick] | var.DENY_ACCS[temp.account] # TODO: add denied commands handling to User

        if self.commands & denied_commands:
            dispatcher.pm(messages["invalid_permissions"])
            return

        if self.flag:
            if self.flag in flags:
                adminlog(chan, rawnick, self.name, rest)
                self.func(var, dispatcher, rest)
                return

            dispatcher.pm(messages["not_an_admin"])
            return

        self.func(var, dispatcher, rest)
예제 #6
0
파일: handler.py 프로젝트: lykoss/lykos
def on_privmsg(cli, rawnick, chan, msg, *, notice=False, force_role=None):
    if notice and "!" not in rawnick or not rawnick: # server notice; we don't care about those
        return

    user = users._get(rawnick, allow_none=True) # FIXME

    ch = chan.lstrip("".join(hooks.Features["PREFIX"]))

    if users.equals(chan, users.Bot.nick): # PM
        target = users.Bot
    else:
        target = channels.get(ch, allow_none=True)

    if user is None or target is None:
        return

    wrapper = MessageDispatcher(user, target)

    if wrapper.public and botconfig.IGNORE_HIDDEN_COMMANDS and not chan.startswith(tuple(hooks.Features["CHANTYPES"])):
        return

    if (notice and ((wrapper.public and not botconfig.ALLOW_NOTICE_COMMANDS) or
                    (wrapper.private and not botconfig.ALLOW_PRIVATE_NOTICE_COMMANDS))):
        return  # not allowed in settings

    if force_role is None: # if force_role isn't None, that indicates recursion; don't fire these off twice
        for fn in decorators.COMMANDS[""]:
            fn.caller(cli, rawnick, ch, msg)

    parts = msg.split(sep=" ", maxsplit=1)
    key = parts[0].lower()
    if len(parts) > 1:
        message = parts[1].lstrip()
    else:
        message = ""

    if wrapper.public and not key.startswith(botconfig.CMD_CHAR):
        return # channel message but no prefix; ignore

    if key.startswith(botconfig.CMD_CHAR):
        key = key[len(botconfig.CMD_CHAR):]

    if not key: # empty key ("") already handled above
        return

    # Don't change this into decorators.COMMANDS[key] even though it's a defaultdict,
    # as we don't want to insert bogus command keys into the dict.
    cmds = []
    phase = var.PHASE
    if user in get_participants():
        roles = get_all_roles(user)
        # A user can be a participant but not have a role, for example, dead vengeful ghost
        has_roles = len(roles) != 0
        if force_role is not None:
            roles &= {force_role} # only fire off role commands for the forced role

        common_roles = set(roles) # roles shared by every eligible role command
        have_role_cmd = False
        for fn in decorators.COMMANDS.get(key, []):
            if not fn.roles:
                cmds.append(fn)
                continue
            if roles.intersection(fn.roles):
                have_role_cmd = True
                cmds.append(fn)
                common_roles.intersection_update(fn.roles)

        if force_role is not None and not have_role_cmd:
            # Trying to force a non-role command with a role.
            # We allow non-role commands to execute if a role is forced if a role
            # command is also executed, as this would allow (for example) a bot admin
            # to add extra effects to all "kill" commands without needing to continually
            # update the list of roles which can use "kill". However, we don't want to
            # allow things like "wolf pstats" because that just doesn't make sense.
            return

        if has_roles and not common_roles:
            # getting here means that at least one of the role_cmds is disjoint
            # from the others. For example, augur see vs seer see when a bare see
            # is executed. In this event, display a helpful error message instructing
            # the user to resolve the ambiguity.
            common_roles = set(roles)
            info = [0,0]
            for fn in cmds:
                fn_roles = roles.intersection(fn.roles)
                if not fn_roles:
                    continue
                for role1 in common_roles:
                    info[0] = role1
                    break
                for role2 in fn_roles:
                    info[1] = role2
                    break
                common_roles &= fn_roles
                if not common_roles:
                    break
            wrapper.pm(messages["ambiguous_command"].format(key, info[0], info[1]))
            return
    elif force_role is None:
        cmds = decorators.COMMANDS.get(key, [])

    for fn in cmds:
        if phase == var.PHASE:
            # FIXME: pass in var, wrapper, message instead of cli, rawnick, chan, message
            fn.caller(cli, rawnick, ch, message)