From 069cd628658703e2a41dd785b8d81e07738a766a Mon Sep 17 00:00:00 2001 From: James Lu Date: Thu, 17 Sep 2015 19:01:54 -0700 Subject: [PATCH] core: allow marking spawned clients as manipulatable or protected This flag determines whether the client should be manipulated by commands like bots.py's MODE/QUIT/JOIN commands, or protected from them (services). --- classes.py | 11 +++++++++-- protocols/inspircd.py | 5 +++-- protocols/ts6.py | 5 +++-- utils.py | 9 +++++++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/classes.py b/classes.py index 735e80f..0834a4f 100644 --- a/classes.py +++ b/classes.py @@ -274,7 +274,9 @@ class Irc(): host = self.serverdata["hostname"] log.info('(%s) Connected! Spawning main client %s.', self.name, nick) olduserobj = self.pseudoclient - self.pseudoclient = self.proto.spawnClient(nick, ident, host, modes={("+o", None)}) + self.pseudoclient = self.proto.spawnClient(nick, ident, host, + modes={("+o", None)}, + manipulatable=True) for chan in self.serverdata['channels']: self.proto.joinClient(self.pseudoclient.uid, chan) # PyLink internal hook called when spawnMain is called and the @@ -284,7 +286,7 @@ class Irc(): class IrcUser(): def __init__(self, nick, ts, uid, ident='null', host='null', realname='PyLink dummy client', realhost='null', - ip='0.0.0.0'): + ip='0.0.0.0', manipulatable=False): self.nick = nick self.ts = ts self.uid = uid @@ -299,6 +301,11 @@ class IrcUser(): self.channels = set() self.away = '' + # Whether the client should be marked as manipulatable + # (i.e. we are allowed to play with it using bots.py's commands). + # For internal services clients, this should always be False. + self.manipulatable = manipulatable + def __repr__(self): return repr(self.__dict__) diff --git a/protocols/inspircd.py b/protocols/inspircd.py index c64055c..488372e 100644 --- a/protocols/inspircd.py +++ b/protocols/inspircd.py @@ -31,7 +31,8 @@ class InspIRCdProtocol(TS6BaseProtocol): self.allow_forceset_usermodes = True def spawnClient(self, nick, ident='null', host='null', realhost=None, modes=set(), - server=None, ip='0.0.0.0', realname=None, ts=None, opertype=None): + server=None, ip='0.0.0.0', realname=None, ts=None, opertype=None, + manipulatable=False): """Spawns a client with nick on the given IRC connection. Note: No nick collision / valid nickname checks are done here; it is @@ -47,7 +48,7 @@ class InspIRCdProtocol(TS6BaseProtocol): realhost = realhost or host raw_modes = utils.joinModes(modes) u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname, - realhost=realhost, ip=ip) + realhost=realhost, ip=ip, manipulatable=manipulatable) utils.applyModes(self.irc, uid, modes) self.irc.servers[server].users.add(uid) self._send(server, "UID {uid} {ts} {nick} {realhost} {host} {ident} {ip}" diff --git a/protocols/ts6.py b/protocols/ts6.py index 6cf150f..dc010b4 100644 --- a/protocols/ts6.py +++ b/protocols/ts6.py @@ -21,7 +21,8 @@ class TS6Protocol(TS6BaseProtocol): self.uidgen = {} def spawnClient(self, nick, ident='null', host='null', realhost=None, modes=set(), - server=None, ip='0.0.0.0', realname=None, ts=None, opertype=None): + server=None, ip='0.0.0.0', realname=None, ts=None, opertype=None, + manipulatable=False): """Spawns a client with nick on the given IRC connection. Note: No nick collision / valid nickname checks are done here; it is @@ -40,7 +41,7 @@ class TS6Protocol(TS6BaseProtocol): realhost = realhost or host raw_modes = utils.joinModes(modes) u = self.irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname, - realhost=realhost, ip=ip) + realhost=realhost, ip=ip, manipulatable=manipulatable) utils.applyModes(self.irc, uid, modes) self.irc.servers[server].users.add(uid) self._send(server, "EUID {nick} 1 {ts} {modes} {ident} {host} {ip} {uid} " diff --git a/utils.py b/utils.py index 5a2349b..06b1904 100644 --- a/utils.py +++ b/utils.py @@ -462,6 +462,15 @@ def checkAuthenticated(irc, uid, allowAuthed=True, allowOper=True): raise NotAuthenticatedError("You are not authenticated!") return True +def isManipulatableClient(irc, uid): + """ + Returns whether the given user is marked as an internal, manipulatable + client. Usually, automatically spawned services clients should have this + set True to prevent interactions with opers (like mode changes) from + causing desyncs. + """ + return isInternalClient(irc, uid) and irc.users[uid].manipulatable + def getHostmask(irc, user): """Gets the hostmask of the given user, if present.""" userobj = irc.users.get(user)