From 8c0f19422fcff4e2d4fdfd28df81b84485bb5962 Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 25 Aug 2017 13:53:45 -0700 Subject: [PATCH] core: Add irc argument to User and Server classes Also, add a __deepcopy__ override to channel because we cannot clone IRCNetwork objects (locks cannot be pickled). --- classes.py | 31 +++++++++++++++++++++++-------- protocols/clientbot.py | 6 +++--- protocols/hybrid.py | 4 ++-- protocols/inspircd.py | 10 +++++----- protocols/ngircd.py | 8 ++++---- protocols/p10.py | 8 ++++---- protocols/ratbox.py | 2 +- protocols/ts6.py | 6 +++--- protocols/ts6_common.py | 6 +++--- protocols/unreal.py | 6 +++--- 10 files changed, 51 insertions(+), 36 deletions(-) diff --git a/classes.py b/classes.py index 7bbc66f..bf0345a 100644 --- a/classes.py +++ b/classes.py @@ -12,7 +12,7 @@ import time import socket import ssl import hashlib -from copy import deepcopy +from copy import copy, deepcopy import inspect import ipaddress import queue @@ -41,7 +41,7 @@ class ChannelState(structures.IRCCaseInsensitiveDict): if key not in self._data: log.debug('(%s) ChannelState: creating new channel %s in memory', self._irc.name, key) - self._data[key] = newchan = Channel(key) + self._data[key] = newchan = Channel(self._irc, key) return newchan return self._data[key] @@ -1336,7 +1336,7 @@ class IRCNetwork(PyLinkNetworkCoreWithUtils): log.info('(%s) Enumerating our own SID %s', self.name, self.sid) host = self.hostname() - self.servers[self.sid] = Server(None, host, internal=True, + self.servers[self.sid] = Server(self, None, host, internal=True, desc=self.serverdata.get('serverdesc') or conf.conf['pylink']['serverdesc']) @@ -1515,7 +1515,7 @@ class User(): self.realname = realname self.modes = set() # Tracks user modes self.server = server - self.irc = irc + self._irc = irc # Tracks PyLink identification status self.account = '' @@ -1527,7 +1527,7 @@ class User(): self.services_account = '' # Tracks channels the user is in - self.channels = structures.IRCCaseInsensitiveSet(self.irc) + self.channels = structures.IRCCaseInsensitiveSet(self._irc) # Tracks away message status self.away = '' @@ -1554,21 +1554,23 @@ class Server(): internal: Whether the server is an internal PyLink server. """ - def __init__(self, uplink, name, internal=False, desc="(None given)"): + def __init__(self, irc, uplink, name, internal=False, desc="(None given)"): self.uplink = uplink self.users = set() self.internal = internal self.name = name.lower() self.desc = desc + self._irc = irc def __repr__(self): return 'Server(%s)' % self.name + IrcServer = Server class Channel(utils.DeprecatedAttributesObject, utils.CamelCaseToSnakeCase): """PyLink IRC channel class.""" - def __init__(self, name=None): + def __init__(self, irc, name=None): # Initialize variables, such as the topic, user list, TS, who's opped, etc. self.users = set() self.modes = set() @@ -1576,6 +1578,7 @@ class Channel(utils.DeprecatedAttributesObject, utils.CamelCaseToSnakeCase): self.ts = int(time.time()) self.prefixmodes = {'op': set(), 'halfop': set(), 'voice': set(), 'owner': set(), 'admin': set()} + self._irc = irc # Determines whether a topic has been set here or not. Protocol modules # should set this. @@ -1596,8 +1599,20 @@ class Channel(utils.DeprecatedAttributesObject, utils.CamelCaseToSnakeCase): self.users.discard(target) removeuser = remove_user - def deepcopy(self): + def __deepcopy__(self, memo): """Returns a deep copy of the channel object.""" + # XXX: we can't pickle IRCNetwork, so just return a reference of it. + channel_copy = copy(self) + # For everything else, create a copy. + for attr, val in self.__dict__.items(): + if not isinstance(val, PyLinkNetworkCore): + setattr(channel_copy, attr, deepcopy(val)) + + memo[id(self)] = channel_copy + + return channel_copy + + def deepcopy(self): return deepcopy(self) def is_voice(self, uid): diff --git a/protocols/clientbot.py b/protocols/clientbot.py index 15678a5..9081cb4 100644 --- a/protocols/clientbot.py +++ b/protocols/clientbot.py @@ -103,7 +103,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): f('NICK %s' % nick) f('USER %s 8 * :%s' % (ident, realname)) - self.pseudoclient = User(self, nick, int(time.time()), self.uidgen.next_uid(prefix='@ClientbotInternal'), self.sid, + self.pseudoclient = User(self, nick, int(time.time()), self.uidgen.next_uid(prefix='@ClientbotInternal'), self.sid, ident=ident, realname=realname, host=self.hostname()) self.users[self.pseudoclient.uid] = self.pseudoclient @@ -121,7 +121,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): ts = ts or int(time.time()) log.debug('(%s) spawn_client stub called, saving nick %s as PUID %s', self.name, nick, uid) - u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, + u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, manipulatable=manipulatable, realhost=realhost, ip=ip) self.servers[server].users.add(uid) @@ -141,7 +141,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): # For others servers, just use the server name as the SID. sid = name - self.servers[sid] = Server(uplink, name, internal=internal) + self.servers[sid] = Server(self, uplink, name, internal=internal) return sid def away(self, source, text): diff --git a/protocols/hybrid.py b/protocols/hybrid.py index 34a4930..f5672ae 100644 --- a/protocols/hybrid.py +++ b/protocols/hybrid.py @@ -113,7 +113,7 @@ class HybridProtocol(TS6Protocol): realname = realname or conf.conf['bot']['realname'] realhost = realhost or host raw_modes = self.join_modes(modes) - u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, + u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, realhost=realhost, ip=ip, manipulatable=manipulatable) self.apply_modes(uid, modes) self.servers[server].users.add(uid) @@ -199,7 +199,7 @@ class HybridProtocol(TS6Protocol): 'host=%s realname=%s ip=%s', self.name, nick, ts, uid, ident, host, realname, ip) - self.users[uid] = User(self, nick, ts, uid, numeric, ident, host, realname, host, ip) + self.users[uid] = User(self, nick, ts, uid, numeric, ident, host, realname, host, ip) parsedmodes = self.parse_modes(uid, [modes]) log.debug('(%s) handle_uid: Applying modes %s for %s', self.name, parsedmodes, uid) diff --git a/protocols/inspircd.py b/protocols/inspircd.py index c94458d..7eb2cb9 100644 --- a/protocols/inspircd.py +++ b/protocols/inspircd.py @@ -56,7 +56,7 @@ class InspIRCdProtocol(TS6BaseProtocol): realname = realname or conf.conf['bot']['realname'] realhost = realhost or host raw_modes = self.join_modes(modes) - u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, + u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype) self.apply_modes(uid, modes) @@ -356,7 +356,7 @@ class InspIRCdProtocol(TS6BaseProtocol): if not utils.isServerName(name): raise ValueError('Invalid server name %r' % name) self._send_with_prefix(uplink, 'SERVER %s * 1 %s :%s' % (name, sid, desc)) - self.servers[sid] = Server(uplink, name, internal=True, desc=desc) + self.servers[sid] = Server(self, uplink, name, internal=True, desc=desc) def endburstf(): # Delay ENDBURST by X seconds if requested. @@ -587,7 +587,7 @@ class InspIRCdProtocol(TS6BaseProtocol): uid, ts, nick, realhost, host, ident, ip = args[0:7] self._check_nick_collision(nick) realname = args[-1] - self.users[uid] = userobj = User(self, nick, ts, uid, numeric, ident, host, realname, realhost, ip) + self.users[uid] = userobj = User(self, nick, ts, uid, numeric, ident, host, realname, realhost, ip) parsedmodes = self.parse_modes(uid, [args[8], args[9]]) self.apply_modes(uid, parsedmodes) @@ -611,7 +611,7 @@ class InspIRCdProtocol(TS6BaseProtocol): raise ProtocolError('recvpass from uplink server %s does not match configuration!' % servername) sdesc = args[-1] - self.servers[numeric] = Server(None, servername, desc=sdesc) + self.servers[numeric] = Server(self, None, servername, desc=sdesc) self.uplink = numeric return @@ -620,7 +620,7 @@ class InspIRCdProtocol(TS6BaseProtocol): servername = args[0].lower() sid = args[3] sdesc = args[-1] - self.servers[sid] = Server(numeric, servername, desc=sdesc) + self.servers[sid] = Server(self, numeric, servername, desc=sdesc) return {'name': servername, 'sid': args[3], 'text': sdesc} diff --git a/protocols/ngircd.py b/protocols/ngircd.py index cf0dbab..8bde606 100644 --- a/protocols/ngircd.py +++ b/protocols/ngircd.py @@ -87,7 +87,7 @@ class NgIRCdProtocol(IRCS2SProtocol): realname = realname or conf.conf['bot']['realname'] uid = self._uidgen.next_uid(prefix=nick) - userobj = self.users[uid] = User(self, nick, ts or int(time.time()), uid, server, ident=ident, host=host, realname=realname, + userobj = self.users[uid] = User(self, nick, ts or int(time.time()), uid, server, ident=ident, host=host, realname=realname, manipulatable=manipulatable, opertype=opertype, realhost=host) self.apply_modes(uid, modes) @@ -130,7 +130,7 @@ class NgIRCdProtocol(IRCS2SProtocol): # a number, we can simply use the counter in our PSID generator for this. server_token = sid.rsplit('@')[-1] self._send_with_prefix(uplink, 'SERVER %s 1 %s :%s' % (name, server_token, desc)) - self.servers[sid] = Server(uplink, name, internal=True, desc=desc) + self.servers[sid] = Server(self, uplink, name, internal=True, desc=desc) return sid def away(self, source, text): @@ -445,7 +445,7 @@ class NgIRCdProtocol(IRCS2SProtocol): realname = args[-1] ts = int(time.time()) - self.users[uid] = User(self, nick, ts, uid, source, ident=ident, host=host, realname=realname, realhost=host) + self.users[uid] = User(self, nick, ts, uid, source, ident=ident, host=host, realname=realname, realhost=host) parsedmodes = self.parse_modes(uid, [args[5]]) self.apply_modes(uid, parsedmodes) @@ -524,7 +524,7 @@ class NgIRCdProtocol(IRCS2SProtocol): serverdesc = args[-1] # The uplink should be set to None for the uplink; otherwise, set it equal to the sender server. - self.servers[servername] = Server(source if source != servername else None, servername, desc=serverdesc) + self.servers[servername] = Server(self, source if source != servername else None, servername, desc=serverdesc) if self.uplink is None: self.uplink = servername diff --git a/protocols/p10.py b/protocols/p10.py index 35bcc72..22629a7 100644 --- a/protocols/p10.py +++ b/protocols/p10.py @@ -279,7 +279,7 @@ class P10Protocol(IRCS2SProtocol): raw_modes = self.join_modes(modes) # Initialize an User instance - u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, + u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype) # Fill in modes and add it to our users index @@ -674,7 +674,7 @@ class P10Protocol(IRCS2SProtocol): self._send_with_prefix(uplink, 'SERVER %s 1 %s %s P10 %s]]] +h6 :%s' % \ (name, self.start_ts, int(time.time()), sid, desc)) - self.servers[sid] = Server(uplink, name, internal=True, desc=desc) + self.servers[sid] = Server(self, uplink, name, internal=True, desc=desc) return sid def squit(self, source, target, text='No reason given'): @@ -832,7 +832,7 @@ class P10Protocol(IRCS2SProtocol): servername = args[0].lower() sid = args[5][:2] sdesc = args[-1] - self.servers[sid] = Server(source, servername, desc=sdesc) + self.servers[sid] = Server(self, source, servername, desc=sdesc) if self.uplink is None: # If we haven't already found our uplink, this is probably it. @@ -858,7 +858,7 @@ class P10Protocol(IRCS2SProtocol): 'host=%s realname=%s realhost=%s ip=%s', self.name, nick, ts, uid, ident, host, realname, realhost, ip) - uobj = self.users[uid] = User(self, nick, ts, uid, source, ident, host, realname, realhost, ip) + uobj = self.users[uid] = User(self, nick, ts, uid, source, ident, host, realname, realhost, ip) self.servers[source].users.add(uid) # https://github.com/evilnet/nefarious2/blob/master/doc/p10.txt#L708 diff --git a/protocols/ratbox.py b/protocols/ratbox.py index 8271d2d..fb171eb 100644 --- a/protocols/ratbox.py +++ b/protocols/ratbox.py @@ -72,7 +72,7 @@ class RatboxProtocol(TS6Protocol): orig_realhost = realhost realhost = realhost or host - u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, + u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, realhost=realhost, ip=ip, manipulatable=manipulatable) self.apply_modes(uid, modes) self.servers[server].users.add(uid) diff --git a/protocols/ts6.py b/protocols/ts6.py index 7120ea9..75221d5 100644 --- a/protocols/ts6.py +++ b/protocols/ts6.py @@ -55,7 +55,7 @@ class TS6Protocol(TS6BaseProtocol): realname = realname or conf.conf['bot']['realname'] realhost = realhost or host raw_modes = self.join_modes(modes) - u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, + u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype) self.apply_modes(uid, modes) @@ -400,7 +400,7 @@ class TS6Protocol(TS6BaseProtocol): # Server name and SID are sent in different messages, so we fill this # with dummy information until we get the actual sid. - self.servers[numeric] = Server(None, '') + self.servers[numeric] = Server(self, None, '') self.uplink = numeric def handle_capab(self, numeric, command, args): @@ -548,7 +548,7 @@ class TS6Protocol(TS6BaseProtocol): if ip == '0': # IP was invalid; something used for services. ip = '0.0.0.0' - self.users[uid] = User(self, nick, ts, uid, numeric, ident, host, realname, realhost, ip) + self.users[uid] = User(self, nick, ts, uid, numeric, ident, host, realname, realhost, ip) parsedmodes = self.parse_modes(uid, [modes]) log.debug('Applying modes %s for %s', parsedmodes, uid) diff --git a/protocols/ts6_common.py b/protocols/ts6_common.py index b113301..f333614 100644 --- a/protocols/ts6_common.py +++ b/protocols/ts6_common.py @@ -182,7 +182,7 @@ class TS6BaseProtocol(IRCS2SProtocol): if not utils.isServerName(name): raise ValueError('Invalid server name %r' % name) self._send_with_prefix(uplink, 'SID %s 1 %s :%s' % (name, sid, desc)) - self.servers[sid] = Server(uplink, name, internal=True, desc=desc) + self.servers[sid] = Server(self, uplink, name, internal=True, desc=desc) return sid def away(self, source, text): @@ -232,7 +232,7 @@ class TS6BaseProtocol(IRCS2SProtocol): # <- :services.int SERVER a.bc 2 :(H) [GL] test jupe servername = args[0].lower() sdesc = args[-1] - self.servers[servername] = Server(numeric, servername, desc=sdesc) + self.servers[servername] = Server(self, numeric, servername, desc=sdesc) return {'name': servername, 'sid': None, 'text': sdesc} def handle_sid(self, numeric, command, args): @@ -242,7 +242,7 @@ class TS6BaseProtocol(IRCS2SProtocol): sname = args[0].lower() sid = args[2] sdesc = args[-1] - self.servers[sid] = Server(numeric, sname, desc=sdesc) + self.servers[sid] = Server(self, numeric, sname, desc=sdesc) return {'name': sname, 'sid': sid, 'text': sdesc} def handle_svsnick(self, source, command, args): diff --git a/protocols/unreal.py b/protocols/unreal.py index 8538aac..3ffdc5f 100644 --- a/protocols/unreal.py +++ b/protocols/unreal.py @@ -69,7 +69,7 @@ class UnrealProtocol(TS6BaseProtocol): modes |= {('+x', None), ('+t', None)} raw_modes = self.join_modes(modes) - u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, + u = self.users[uid] = User(self, nick, ts, uid, server, ident=ident, host=host, realname=realname, realhost=realhost, ip=ip, manipulatable=manipulatable, opertype=opertype) self.apply_modes(uid, modes) self.servers[server].users.add(uid) @@ -415,7 +415,7 @@ class UnrealProtocol(TS6BaseProtocol): realname = args[-1] - self.users[uid] = User(self, nick, ts, uid, numeric, ident, host, realname, realhost, ip) + self.users[uid] = User(self, nick, ts, uid, numeric, ident, host, realname, realhost, ip) self.servers[numeric].users.add(uid) # Handle user modes @@ -480,7 +480,7 @@ class UnrealProtocol(TS6BaseProtocol): if protover < self.min_proto_ver: raise ProtocolError("Protocol version too old! (needs at least %s " "(Unreal 4.x), got %s)" % (self.min_proto_ver, protover)) - self.servers[numeric] = Server(None, sname, desc=sdesc) + self.servers[numeric] = Server(self, None, sname, desc=sdesc) # Set irc.connected to True, meaning that protocol negotiation passed. log.debug('(%s) self.connected set!', self.name)