diff --git a/classes.py b/classes.py index e916fc3..5e84844 100644 --- a/classes.py +++ b/classes.py @@ -920,8 +920,28 @@ class Irc(): # Get the corresponding casemapping value used by ircmatch. casemapping = getattr(ircmatch, self.proto.casemapping) + # Try to convert target into a UID. If this fails, it's probably a hostname. + target = self.nickToUid(target) or target + # Prepare a list of hosts to check against. if target in self.users: + if glob.startswith('$'): + # Exttargets start with $. Skip regular ban matching and find the matching ban handler. + glob = glob.lstrip('$') + exttargetname = glob.split(':', 1)[0] + handler = world.exttarget_handlers.get(exttargetname) + + if handler: + # Handler exists. Return what it finds. + result = handler(self, glob, target) + log.debug('(%s) Got %s from exttarget %s in matchHost() glob $%s for target %s', + self.name, result, exttargetname, glob, target) + return result + else: + log.debug('(%s) Unknown exttarget %s in matchHost() glob $%s', self.name, + exttargetname, glob) + return False + hosts = {self.getHostmask(target)} if ip: diff --git a/coremods/__init__.py b/coremods/__init__.py index a54a65d..4652b7c 100644 --- a/coremods/__init__.py +++ b/coremods/__init__.py @@ -1,2 +1,2 @@ # Service support has to be imported first, so that utils.add_cmd works -from . import service_support, control, handlers, corecommands +from . import service_support, control, handlers, corecommands, exttargets diff --git a/coremods/exttargets.py b/coremods/exttargets.py new file mode 100644 index 0000000..3ee23a0 --- /dev/null +++ b/coremods/exttargets.py @@ -0,0 +1,57 @@ +""" +exttargets.py - Implements extended targets like $account:xyz, $oper, etc. +""" + +from pylinkirc import world +from pylinkirc.log import log + +def bind(func): + """ + Binds an exttarget with the given name. + """ + world.exttarget_handlers[func.__name__] = func + return func + +@bind +def account(irc, host, uid): + """ + $account exttarget handler. The following forms are supported, with groups separated by a + literal colon. All account and network name matching is currently case sensitive: + + $account -> Returns True (a match) if the target is registered. + $account:accountname -> Returns True if the target's account name matches the one given, and the + target is connected to the local network.. + $account:accountname:netname -> Returns True if both the target's account name and origin + network name match the ones given. + $account:*:netname -> Matches all logged in users on the given network. + """ + userobj = irc.users[uid] + homenet = irc.name + if hasattr(userobj, 'remote'): + # User is a PyLink Relay pseudoclient. Use their real services account on their + # origin network. + homenet, realuid = userobj.remote + log.debug('(%s) exttargets.account: Changing UID of relay client %s to %s/%s', irc.name, + uid, homenet, realuid) + try: + userobj = world.networkobjects[homenet].users[realuid] + except KeyError: # User lookup failed. Bail and return False. + log.exception('(%s) exttargets.account: KeyError finding %s/%s:', irc.name, + homenet, realuid) + return False + + slogin = userobj.services_account + + # Split the given exttarget host into parts, so we know how many to look for. + groups = host.split(':') + log.debug('(%s) exttargets.account: groups to match: %s', irc.name, groups) + + if len(groups) == 1: + # First scenario. Return True if user is logged in. + return bool(slogin) + elif len(groups) == 2: + # Second scenario. Return True if the user's account matches the one given. + return slogin == groups[1] and homenet == irc.name + else: + # Third or fourth scenario. If there are more than 3 groups, the rest are ignored. + return (groups[1] in ('*', slogin)) and (homenet == groups[2]) diff --git a/world.py b/world.py index 9cce45e..85b05aa 100644 --- a/world.py +++ b/world.py @@ -16,6 +16,9 @@ networkobjects = {} plugins = {} services = {} +# Registered extarget handlers. This maps exttarget names (strings) to handling functions. +exttarget_handlers = {} + started = threading.Event() source = "https://github.com/GLolol/PyLink" # CHANGE THIS IF YOU'RE FORKING!!