From 80766e051e729a3907c169911ee21b623e81e036 Mon Sep 17 00:00:00 2001 From: James Lu Date: Fri, 25 Aug 2017 02:11:48 -0700 Subject: [PATCH] core: define two (joined) versions of the channels index Closes #509. PyLinkNetworkCore.channels is split into the following: - irc._channels which implicitly creates channels on access (mostly used in protocol modules) - irc.channels which does not (recommended for use by plugins) --- classes.py | 29 +++++++++++++--------- protocols/clientbot.py | 32 ++++++++++++------------ protocols/hybrid.py | 10 ++++---- protocols/inspircd.py | 32 ++++++++++++------------ protocols/ircs2s_common.py | 22 ++++++++--------- protocols/ngircd.py | 16 ++++++------ protocols/p10.py | 50 +++++++++++++++++++------------------- protocols/ts6.py | 44 ++++++++++++++++----------------- protocols/unreal.py | 34 +++++++++++++------------- 9 files changed, 137 insertions(+), 132 deletions(-) diff --git a/classes.py b/classes.py index 75f7c4b..b83ea26 100644 --- a/classes.py +++ b/classes.py @@ -130,11 +130,16 @@ class PyLinkNetworkCore(utils.DeprecatedAttributesObject, utils.CamelCaseToSnake self.called_in = None # Intialize the server, channel, and user indexes to be populated by - # our protocol module. For the server index, we can add ourselves right - # now. + # our protocol module. self.servers = {} self.users = {} - self.channels = ChannelState(self) + + # Two versions of the channels index exist in PyLink 2.0, and they are joined together + # - irc._channels which implicitly creates channels on access (mostly used + # in protocol modules) + # - irc.channels which does not (recommended for use by plugins) + self._channels = ChannelState(self) + self.channels = structures.IRCCaseInsensitiveDict(self, data=self._channels._data) # This sets the list of supported channel and user modes: the default # RFC1459 modes are implied. Named modes are used here to make @@ -531,7 +536,7 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): log.debug('(%s) Using self.cmodes for this query: %s', self.name, self.cmodes) supported_modes = self.cmodes - oldmodes = self.channels[target].modes + oldmodes = self._channels[target].modes res = [] for mode in modestring: if mode in '+-': @@ -601,7 +606,7 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): old_modelist = self.users[target].modes supported_modes = self.umodes else: - old_modelist = self.channels[target].modes + old_modelist = self._channels[target].modes supported_modes = self.cmodes except KeyError: log.warning('(%s) Possible desync? Mode target %s is unknown.', self.name, target) @@ -621,7 +626,7 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): # if the IRCd supports this mode and it is the one being set, add/remove # the person from the corresponding prefix mode list (e.g. c.prefixmodes['op'] # for ops). - for pmode, pmodelist in self.channels[target].prefixmodes.items(): + for pmode, pmodelist in self._channels[target].prefixmodes.items(): if pmode in self.cmodes and real_mode[0] == self.cmodes[pmode]: log.debug('(%s) Initial prefixmodes list: %s', self.name, pmodelist) if mode[0][0] == '+': @@ -668,7 +673,7 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): if usermodes: self.users[target].modes = modelist else: - self.channels[target].modes = modelist + self._channels[target].modes = modelist except KeyError: log.warning("(%s) Invalid MODE target %s (usermodes=%s)", self.name, target, usermodes) @@ -706,7 +711,7 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): modes = self.parse_modes(target, modes.split(" ")) # Get the current mode list first. if utils.isChannel(target): - c = oldobj or self.channels[target] + c = oldobj or self._channels[target] oldmodes = c.modes.copy() possible_modes = self.cmodes.copy() # For channels, this also includes the list of prefix modes. @@ -1116,8 +1121,8 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): def _clear(): log.debug("(%s) Clearing local modes from channel %s due to TS change", self.name, channel) - self.channels[channel].modes.clear() - for p in self.channels[channel].prefixmodes.values(): + self._channels[channel].modes.clear() + for p in self._channels[channel].prefixmodes.values(): for user in p.copy(): if not self.is_internal_client(user): p.discard(user) @@ -1131,7 +1136,7 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): # Use a lock so only one thread can change a channel's TS at once: this prevents race # conditions that would otherwise desync channel modes. with self._ts_lock: - our_ts = self.channels[channel].ts + our_ts = self._channels[channel].ts assert isinstance(our_ts, int), "Wrong type for our_ts (expected int, got %s)" % type(our_ts) assert isinstance(their_ts, int), "Wrong type for their_ts (expected int, got %s)" % type(their_ts) @@ -1153,7 +1158,7 @@ class PyLinkNetworkCoreWithUtils(PyLinkNetworkCore): else: log.debug('(%s) Resetting channel TS of %s from %s to %s (remote has lower TS)', self.name, channel, our_ts, their_ts) - self.channels[channel].ts = their_ts + self._channels[channel].ts = their_ts # Remote TS was lower and we're receiving modes. Clear the modelist and apply theirs. diff --git a/protocols/clientbot.py b/protocols/clientbot.py index 6e9d85b..9b6fb27 100644 --- a/protocols/clientbot.py +++ b/protocols/clientbot.py @@ -168,7 +168,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): if self.pseudoclient and client == self.pseudoclient.uid: self.send('JOIN %s' % channel) else: - self.channels[channel].users.add(client) + self._channels[channel].users.add(client) self.users[client].channels.add(channel) log.debug('(%s) join: faking JOIN of client %s/%s to %s', self.name, client, @@ -272,7 +272,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): def part(self, source, channel, reason=''): """STUB: Parts a user from a channel.""" - self.channels[channel].remove_user(source) + self._channels[channel].remove_user(source) self.users[source].channels.discard(channel) # Only parts for the main PyLink client are actually forwarded. Others are ignored. @@ -300,7 +300,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): # Otherwise, track the state for our virtual clients. self.users[user].channels.add(channel) - self.channels[channel].users |= puids + self._channels[channel].users |= puids nicks = {self.get_friendly_name(u) for u in puids} self.call_hooks([server, 'CLIENTBOT_SJOIN', {'channel': channel, 'nicks': nicks}]) @@ -671,7 +671,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): # Queue these virtual users to be joined if they're not already in the channel, # or we're waiting for a kick acknowledgment for them. - if (idsource not in self.channels[channel].users) or (idsource in \ + if (idsource not in self._channels[channel].users) or (idsource in \ self.kick_queue.get(channel, ([],))[0]): names.add(idsource) self.users[idsource].channels.add(channel) @@ -686,7 +686,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): break # Statekeeping: make sure the channel's user list is updated! - self.channels[channel].users |= names + self._channels[channel].users |= names self.apply_modes(channel, modes) log.debug('(%s) handle_353: adding users %s to %s', self.name, names, channel) @@ -698,7 +698,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): fully_synced_names = [uid for uid in names if hasattr(self.users[uid], '_clientbot_identhost_received')] if fully_synced_names: log.debug('(%s) handle_353: sending pre-WHO JOIN hook for %s: %s', self.name, channel, fully_synced_names) - return {'channel': channel, 'users': fully_synced_names, 'modes': self.channels[channel].modes, + return {'channel': channel, 'users': fully_synced_names, 'modes': self._channels[channel].modes, 'parse_as': "JOIN"} def _check_puid_collision(self, nick): @@ -796,7 +796,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): self.who_received.clear() channel = args[1] - c = self.channels[channel] + c = self._channels[channel] modes = set(c.modes) for user in users.copy(): @@ -848,7 +848,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): # With extended-join: # <- :GL|!~GL@127.0.0.1 JOIN #whatever accountname :realname channel = args[0] - self.channels[channel].users.add(source) + self._channels[channel].users.add(source) self.users[source].channels.add(channel) if len(args) >= 3: @@ -864,7 +864,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): self._send_who(channel) else: self.call_hooks([source, 'CLIENTBOT_JOIN', {'channel': channel}]) - return {'channel': channel, 'users': [source], 'modes': self.channels[channel].modes} + return {'channel': channel, 'users': [source], 'modes': self._channels[channel].modes} def handle_kick(self, source, command, args): """ @@ -891,7 +891,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): del self.kick_queue[channel] # Statekeeping: remove the target from the channel they were previously in. - self.channels[channel].remove_user(target) + self._channels[channel].remove_user(target) try: self.users[target].channels.remove(channel) except KeyError: @@ -903,7 +903,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): # Delete channels that we were kicked from, for better state keeping. if self.pseudoclient and target == self.pseudoclient.uid: - del self.channels[channel] + del self._channels[channel] def handle_mode(self, source, command, args): """Handles MODE changes.""" @@ -911,7 +911,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): # <- :ice MODE ice :+Zi target = args[0] if utils.isChannel(target): - oldobj = self.channels[target].deepcopy() + oldobj = self._channels[target].deepcopy() else: target = self.nick_to_uid(target) oldobj = None @@ -944,7 +944,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): """Handles TS announcements via RPL_CREATIONTIME.""" channel = args[1] ts = int(args[2]) - self.channels[channel].ts = ts + self._channels[channel].ts = ts def handle_chghost(self, source, command, args): """Handles the IRCv3 CHGHOST command.""" @@ -995,15 +995,15 @@ class ClientbotWrapperProtocol(IRCCommonProtocol): reason = '' for channel in channels: - self.channels[channel].remove_user(source) + self._channels[channel].remove_user(source) self.users[source].channels -= set(channels) self.call_hooks([source, 'PART', {'channels': channels, 'text': reason}]) # Clear channels that are empty, or that we're parting. for channel in channels: - if (self.pseudoclient and source == self.pseudoclient.uid) or not self.channels[channel].users: - del self.channels[channel] + if (self.pseudoclient and source == self.pseudoclient.uid) or not self._channels[channel].users: + del self._channels[channel] def handle_ping(self, source, command, args): """ diff --git a/protocols/hybrid.py b/protocols/hybrid.py index 70db96d..fda5fb0 100644 --- a/protocols/hybrid.py +++ b/protocols/hybrid.py @@ -162,12 +162,12 @@ class HybridProtocol(TS6Protocol): if not self.is_internal_server(numeric): raise LookupError('No such PyLink server exists.') - ts = self.channels[target].ts + ts = self._channels[target].ts servername = self.servers[numeric].name self._send_with_prefix(numeric, 'TBURST %s %s %s %s :%s' % (ts, target, int(time.time()), servername, text)) - self.channels[target].topic = text - self.channels[target].topicset = True + self._channels[target].topic = text + self._channels[target].topicset = True # command handlers @@ -221,8 +221,8 @@ class HybridProtocol(TS6Protocol): ts = args[2] setter = args[3] topic = args[-1] - self.channels[channel].topic = topic - self.channels[channel].topicset = True + self._channels[channel].topic = topic + self._channels[channel].topicset = True return {'channel': channel, 'setter': setter, 'ts': ts, 'text': topic} def handle_eob(self, numeric, command, args): diff --git a/protocols/inspircd.py b/protocols/inspircd.py index 0bdd54a..6b845c9 100644 --- a/protocols/inspircd.py +++ b/protocols/inspircd.py @@ -83,11 +83,11 @@ class InspIRCdProtocol(TS6BaseProtocol): raise LookupError('No such PyLink client exists.') # Strip out list-modes, they shouldn't be ever sent in FJOIN. - modes = [m for m in self.channels[channel].modes if m[0] not in self.cmodes['*A']] + modes = [m for m in self._channels[channel].modes if m[0] not in self.cmodes['*A']] self._send_with_prefix(server, "FJOIN {channel} {ts} {modes} :,{uid}".format( - ts=self.channels[channel].ts, uid=client, channel=channel, + ts=self._channels[channel].ts, uid=client, channel=channel, modes=self.join_modes(modes))) - self.channels[channel].users.add(client) + self._channels[channel].users.add(client) self.users[client].channels.add(channel) def sjoin(self, server, channel, users, ts=None, modes=set()): @@ -109,8 +109,8 @@ class InspIRCdProtocol(TS6BaseProtocol): raise LookupError('No such PyLink client exists.') # Strip out list-modes, they shouldn't ever be sent in FJOIN (protocol rules). - modes = modes or self.channels[channel].modes - orig_ts = self.channels[channel].ts + modes = modes or self._channels[channel].modes + orig_ts = self._channels[channel].ts ts = ts or orig_ts banmodes = [] @@ -120,7 +120,7 @@ class InspIRCdProtocol(TS6BaseProtocol): if modechar in self.cmodes['*A']: # Track bans separately (they are sent as a normal FMODE instead of in FJOIN. # However, don't reset bans that have already been set. - if (modechar, mode[1]) not in self.channels[channel].modes: + if (modechar, mode[1]) not in self._channels[channel].modes: banmodes.append(mode) else: regularmodes.append(mode) @@ -146,7 +146,7 @@ class InspIRCdProtocol(TS6BaseProtocol): self._send_with_prefix(server, "FJOIN {channel} {ts} {modes} :{users}".format( ts=ts, users=namelist, channel=channel, modes=self.join_modes(modes))) - self.channels[channel].users.update(uids) + self._channels[channel].users.update(uids) if banmodes: # Burst ban modes if there are any. @@ -207,7 +207,7 @@ class InspIRCdProtocol(TS6BaseProtocol): self.apply_modes(target, modes) joinedmodes = self.join_modes(modes) if utils.isChannel(target): - ts = ts or self.channels[target].ts + ts = ts or self._channels[target].ts self._send_with_prefix(numeric, 'FMODE %s %s %s' % (target, ts, joinedmodes)) else: self._send_with_prefix(numeric, 'MODE %s %s' % (target, joinedmodes)) @@ -241,8 +241,8 @@ class InspIRCdProtocol(TS6BaseProtocol): ts = int(time.time()) servername = self.servers[numeric].name self._send_with_prefix(numeric, 'FTOPIC %s %s %s :%s' % (target, ts, servername, text)) - self.channels[target].topic = text - self.channels[target].topicset = True + self._channels[target].topic = text + self._channels[target].topicset = True def knock(self, numeric, target, text): """Sends a KNOCK from a PyLink client.""" @@ -539,7 +539,7 @@ class InspIRCdProtocol(TS6BaseProtocol): """Handles incoming FJOIN commands (InspIRCd equivalent of JOIN/SJOIN).""" # :70M FJOIN #chat 1423790411 +AFPfjnt 6:5 7:5 9:5 :o,1SRAABIT4 v,1IOAAF53R <...> channel = args[0] - chandata = self.channels[channel].deepcopy() + chandata = self._channels[channel].deepcopy() # InspIRCd sends each channel's users in the form of 'modeprefix(es),UID' userlist = args[-1].split() @@ -565,7 +565,7 @@ class InspIRCdProtocol(TS6BaseProtocol): # Only save mode changes if the remote has lower TS than us. changedmodes |= {('+%s' % mode, user) for mode in modeprefix} - self.channels[channel].users.add(user) + self._channels[channel].users.add(user) # Statekeeping with timestamps. Note: some service packages (Anope 1.8) send a trailing # 'd' after the timestamp, which we should strip out to prevent int() from erroring. @@ -574,7 +574,7 @@ class InspIRCdProtocol(TS6BaseProtocol): # <- :3AX FJOIN #monitor 1485462109d + :,3AXAAAAAK their_ts = int(''.join(char for char in args[1] if char.isdigit())) - our_ts = self.channels[channel].ts + our_ts = self._channels[channel].ts self.updateTS(servernumeric, channel, their_ts, changedmodes) return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts, @@ -627,7 +627,7 @@ class InspIRCdProtocol(TS6BaseProtocol): """Handles the FMODE command, used for channel mode changes.""" # <- :70MAAAAAA FMODE #chat 1433653462 +hhT 70MAAAAAA 70MAAAAAD channel = args[0] - oldobj = self.channels[channel].deepcopy() + oldobj = self._channels[channel].deepcopy() modes = args[2:] changedmodes = self.parse_modes(channel, modes) self.apply_modes(channel, changedmodes) @@ -661,8 +661,8 @@ class InspIRCdProtocol(TS6BaseProtocol): ts = args[1] setter = args[2] topic = args[-1] - self.channels[channel].topic = topic - self.channels[channel].topicset = True + self._channels[channel].topic = topic + self._channels[channel].topicset = True return {'channel': channel, 'setter': setter, 'ts': ts, 'text': topic} # SVSTOPIC is used by InspIRCd module m_topiclock - its arguments are the same as FTOPIC diff --git a/protocols/ircs2s_common.py b/protocols/ircs2s_common.py index 277d8bb..10a0b14 100644 --- a/protocols/ircs2s_common.py +++ b/protocols/ircs2s_common.py @@ -110,7 +110,7 @@ class IRCCommonProtocol(IRCNetwork): # Prevent RuntimeError: dictionary changed size during iteration old_servers = self.servers.copy() - old_channels = self.channels.copy() + old_channels = self._channels.copy() # Cycle through our list of servers. If any server's uplink is the one that is being SQUIT, # remove them and all their users too. @@ -468,8 +468,8 @@ class IRCS2SProtocol(IRCCommonProtocol): raise LookupError('No such PyLink client/server exists.') self._send_with_prefix(source, 'TOPIC %s :%s' % (target, text)) - self.channels[target].topic = text - self.channels[target].topicset = True + self._channels[target].topic = text + self._channels[target].topicset = True topic_burst = topic def handle_invite(self, numeric, command, args): @@ -590,7 +590,7 @@ class IRCS2SProtocol(IRCCommonProtocol): # <- ABAAA OM #test +h ABAAA target = self._get_UID(args[0]) if utils.isChannel(target): - channeldata = self.channels[target].deepcopy() + channeldata = self._channels[target].deepcopy() else: channeldata = None @@ -611,11 +611,11 @@ class IRCS2SProtocol(IRCCommonProtocol): channels = args[0].split(',') for channel in channels.copy(): - if channel not in self.channels or source not in self.channels[channel].users: + if channel not in self._channels or source not in self._channels[channel].users: # Ignore channels the user isn't on, and remove them from any hook payloads. channels.remove(channel) - self.channels[channel].remove_user(source) + self._channels[channel].remove_user(source) try: self.users[source].channels.discard(channel) except KeyError: @@ -627,8 +627,8 @@ class IRCS2SProtocol(IRCCommonProtocol): reason = '' # Clear empty non-permanent channels. - if not (self.channels[channel].users or ((self.cmodes.get('permanent'), None) in self.channels[channel].modes)): - del self.channels[channel] + if not (self._channels[channel].users or ((self.cmodes.get('permanent'), None) in self._channels[channel].modes)): + del self._channels[channel] if channels: return {'channels': channels, 'text': reason} @@ -685,9 +685,9 @@ class IRCS2SProtocol(IRCCommonProtocol): channel = args[0] topic = args[1] - oldtopic = self.channels[channel].topic - self.channels[channel].topic = topic - self.channels[channel].topicset = True + oldtopic = self._channels[channel].topic + self._channels[channel].topic = topic + self._channels[channel].topicset = True return {'channel': channel, 'setter': numeric, 'text': topic, 'oldtopic': oldtopic} diff --git a/protocols/ngircd.py b/protocols/ngircd.py index d5173ef..ef2a44a 100644 --- a/protocols/ngircd.py +++ b/protocols/ngircd.py @@ -154,7 +154,7 @@ class NgIRCdProtocol(IRCS2SProtocol): raise LookupError('No such PyLink client exists.') self._send_with_prefix(client, "JOIN %s" % channel) - self.channels[channel].users.add(client) + self._channels[channel].users.add(client) self.users[client].channels.add(channel) def kill(self, source, target, reason): @@ -241,7 +241,7 @@ class NgIRCdProtocol(IRCS2SProtocol): # Add the affected users to our state. for userpair in users: uid = userpair[1] - self.channels[channel].users.add(uid) + self._channels[channel].users.add(uid) try: self.users[uid].channels.add(channel) except KeyError: # Not initialized yet? @@ -337,8 +337,8 @@ class NgIRCdProtocol(IRCS2SProtocol): topic = args[-1] if topic: log.debug('(%s) handle_chaninfo: setting topic for %s to %r', self.name, channel, topic) - self.channels[channel].topic = topic - self.channels[channel].topicset = True + self._channels[channel].topic = topic + self._channels[channel].topicset = True if len(args) >= 5: key = args[2] @@ -364,10 +364,10 @@ class NgIRCdProtocol(IRCS2SProtocol): except ValueError: channel = chanpair - c = self.channels[channel] + c = self._channels[channel] self.users[source].channels.add(channel) - self.channels[channel].users.add(source) + self._channels[channel].users.add(source) # Call hooks manually, because one JOIN command have multiple channels. self.call_hooks([source, command, {'channel': channel, 'users': [source], 'modes': c.modes}]) @@ -469,7 +469,7 @@ class NgIRCdProtocol(IRCS2SProtocol): # <- :ngircd.midnight.local NJOIN #test :tester,@%GL channel = args[0] - chandata = self.channels[channel].deepcopy() + chandata = self._channels[channel].deepcopy() namelist = [] # Reverse the modechar->modeprefix mapping for quicker lookup @@ -487,7 +487,7 @@ class NgIRCdProtocol(IRCS2SProtocol): # Final bits of state tracking. (I hate having to do this everywhere...) self.users[user].channels.add(channel) - self.channels[channel].users.add(user) + self._channels[channel].users.add(user) return {'channel': channel, 'users': namelist, 'modes': [], 'channeldata': chandata} diff --git a/protocols/p10.py b/protocols/p10.py index 519b0ea..8ded65f 100644 --- a/protocols/p10.py +++ b/protocols/p10.py @@ -322,23 +322,23 @@ class P10Protocol(IRCS2SProtocol): nick = self.users[target].nick - self._send_with_prefix(numeric, 'I %s %s %s' % (nick, channel, self.channels[channel].ts)) + self._send_with_prefix(numeric, 'I %s %s %s' % (nick, channel, self._channels[channel].ts)) def join(self, client, channel): """Joins a PyLink client to a channel.""" # <- ABAAB J #test3 1460744371 - ts = self.channels[channel].ts + ts = self._channels[channel].ts if not self.is_internal_client(client): raise LookupError('No such PyLink client exists.') - if not self.channels[channel].users: + if not self._channels[channel].users: # Empty channels should be created with the CREATE command. self._send_with_prefix(client, "C {channel} {ts}".format(ts=ts, channel=channel)) else: self._send_with_prefix(client, "J {channel} {ts}".format(ts=ts, channel=channel)) - self.channels[channel].users.add(client) + self._channels[channel].users.add(client) self.users[client].channels.add(channel) def kick(self, numeric, channel, target, reason=None): @@ -351,7 +351,7 @@ class P10Protocol(IRCS2SProtocol): if not reason: reason = 'No reason given' - cobj = self.channels[channel] + cobj = self._channels[channel] # Prevent kick bounces by sending our kick through the server if # the sender isn't op. if numeric not in self.servers and (not cobj.is_halfop_plus(numeric)): @@ -409,7 +409,7 @@ class P10Protocol(IRCS2SProtocol): is_cmode = utils.isChannel(target) if is_cmode: # Channel mode changes have a trailing TS. User mode changes do not. - cobj = self.channels[target] + cobj = self._channels[target] ts = ts or cobj.ts # Prevent mode bounces by sending our mode through the server if @@ -530,8 +530,8 @@ class P10Protocol(IRCS2SProtocol): # <- AB B #test 1460742014 +tnl 10 ABAAB,ABAAA:o :%*!*@other.bad.host *!*@bad.host # <- AB B #test2 1460743539 +l 10 ABAAA:vo :%*!*@bad.host # <- AB B #test 1460747615 ABAAA:o :% ~ *!*@test.host - modes = modes or self.channels[channel].modes - orig_ts = self.channels[channel].ts + modes = modes or self._channels[channel].modes + orig_ts = self._channels[channel].ts ts = ts or orig_ts bans = [] @@ -541,7 +541,7 @@ class P10Protocol(IRCS2SProtocol): modechar = mode[0][-1] # Store bans and exempts in separate lists for processing, but don't reset bans that have already been set. if modechar in self.cmodes['*A']: - if (modechar, mode[1]) not in self.channels[channel].modes: + if (modechar, mode[1]) not in self._channels[channel].modes: if modechar == 'b': bans.append(mode[1]) elif modechar == 'e': @@ -624,7 +624,7 @@ class P10Protocol(IRCS2SProtocol): self.send(wrapped_msg) - self.channels[channel].users.update(changedusers) + self._channels[channel].users.update(changedusers) # Technically we can send bans together with the above user introductions, but # it's easier to line wrap them separately. @@ -699,12 +699,12 @@ class P10Protocol(IRCS2SProtocol): # For servers, just show the server name. sendername = self.get_friendly_name(source) - creationts = self.channels[target].ts + creationts = self._channels[target].ts self._send_with_prefix(source, 'T %s %s %s %s :%s' % (target, sendername, creationts, int(time.time()), text)) - self.channels[target].topic = text - self.channels[target].topicset = True + self._channels[target].topic = text + self._channels[target].topicset = True topic_burst = topic def update_client(self, target, field, text): @@ -1004,7 +1004,7 @@ class P10Protocol(IRCS2SProtocol): return channel = args[0] - chandata = self.channels[channel].deepcopy() + chandata = self._channels[channel].deepcopy() bans = [] if args[-1].startswith('%'): @@ -1068,11 +1068,11 @@ class P10Protocol(IRCS2SProtocol): # Only save mode changes if the remote has lower TS than us. changedmodes |= {('+%s' % mode, user) for mode in prefixes} - self.channels[channel].users.add(user) + self._channels[channel].users.add(user) # Statekeeping with timestamps their_ts = int(args[1]) - our_ts = self.channels[channel].ts + our_ts = self._channels[channel].ts self.updateTS(source, channel, their_ts, changedmodes) return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts, @@ -1096,7 +1096,7 @@ class P10Protocol(IRCS2SProtocol): self.name, source, oldchans) for channel in oldchans: - self.channels[channel].users.discard(source) + self._channels[channel].users.discard(source) self.users[source].channels.discard(channel) return {'channels': oldchans, 'text': 'Left all channels.', 'parse_as': 'PART'} @@ -1106,10 +1106,10 @@ class P10Protocol(IRCS2SProtocol): self.updateTS(source, channel, ts) self.users[source].channels.add(channel) - self.channels[channel].users.add(source) + self._channels[channel].users.add(source) return {'channel': channel, 'users': [source], 'modes': - self.channels[channel].modes, 'ts': ts or int(time.time())} + self._channels[channel].modes, 'ts': ts or int(time.time())} handle_create = handle_join def handle_end_of_burst(self, source, command, args): @@ -1140,9 +1140,9 @@ class P10Protocol(IRCS2SProtocol): channel = args[0] topic = args[-1] - oldtopic = self.channels[channel].topic - self.channels[channel].topic = topic - self.channels[channel].topicset = True + oldtopic = self._channels[channel].topic + self._channels[channel].topic = topic + self._channels[channel].topicset = True return {'channel': channel, 'setter': args[1], 'text': topic, 'oldtopic': oldtopic} @@ -1154,14 +1154,14 @@ class P10Protocol(IRCS2SProtocol): modes = args[1] # Enumerate a list of our existing modes, including prefix modes. - existing = list(self.channels[channel].modes) - for pmode, userlist in self.channels[channel].prefixmodes.items(): + existing = list(self._channels[channel].modes) + for pmode, userlist in self._channels[channel].prefixmodes.items(): # Expand the prefix modes lists to individual ('o', 'UID') mode pairs. modechar = self.cmodes.get(pmode) existing += [(modechar, user) for user in userlist] # Back up the channel state. - oldobj = self.channels[channel].deepcopy() + oldobj = self._channels[channel].deepcopy() changedmodes = [] diff --git a/protocols/ts6.py b/protocols/ts6.py index 585dcd5..8e5a9db 100644 --- a/protocols/ts6.py +++ b/protocols/ts6.py @@ -76,8 +76,8 @@ class TS6Protocol(TS6BaseProtocol): if not self.is_internal_client(client): log.error('(%s) Error trying to join %r to %r (no such client exists)', self.name, client, channel) raise LookupError('No such PyLink client exists.') - self._send_with_prefix(client, "JOIN {ts} {channel} +".format(ts=self.channels[channel].ts, channel=channel)) - self.channels[channel].users.add(client) + self._send_with_prefix(client, "JOIN {ts} {channel} +".format(ts=self._channels[channel].ts, channel=channel)) + self._channels[channel].users.add(client) self.users[client].channels.add(channel) def sjoin(self, server, channel, users, ts=None, modes=set()): @@ -106,8 +106,8 @@ class TS6Protocol(TS6BaseProtocol): if not server: raise LookupError('No such PyLink client exists.') - modes = set(modes or self.channels[channel].modes) - orig_ts = self.channels[channel].ts + modes = set(modes or self._channels[channel].modes) + orig_ts = self._channels[channel].ts ts = ts or orig_ts # Get all the ban modes in a separate list. These are bursted using a separate BMASK @@ -119,7 +119,7 @@ class TS6Protocol(TS6BaseProtocol): modechar = mode[0][-1] if modechar in self.cmodes['*A']: # Mode character is one of 'beIq' - if (modechar, mode[1]) in self.channels[channel].modes: + if (modechar, mode[1]) in self._channels[channel].modes: # Don't reset modes that are already set. continue @@ -153,7 +153,7 @@ class TS6Protocol(TS6BaseProtocol): self._send_with_prefix(server, "SJOIN {ts} {channel} {modes} :{users}".format( ts=ts, users=namelist, channel=channel, modes=self.join_modes(regularmodes))) - self.channels[channel].users.update(uids) + self._channels[channel].users.update(uids) # Now, burst bans. # <- :42X BMASK 1424222769 #dev b :*!test@*.isp.net *!badident@* @@ -183,7 +183,7 @@ class TS6Protocol(TS6BaseProtocol): modes = list(modes) if utils.isChannel(target): - ts = ts or self.channels[target].ts + ts = ts or self._channels[target].ts # TMODE: # parameters: channelTS, channel, cmode changes, opt. cmode parameters... @@ -207,17 +207,17 @@ class TS6Protocol(TS6BaseProtocol): # source: server # propagation: broadcast # parameters: channel, topicTS, opt. topic setter, topic - ts = self.channels[target].ts + ts = self._channels[target].ts servername = self.servers[numeric].name self._send_with_prefix(numeric, 'TB %s %s %s :%s' % (target, ts, servername, text)) - self.channels[target].topic = text - self.channels[target].topicset = True + self._channels[target].topic = text + self._channels[target].topicset = True def invite(self, numeric, target, channel): """Sends an INVITE from a PyLink client..""" if not self.is_internal_client(numeric): raise LookupError('No such PyLink client exists.') - self._send_with_prefix(numeric, 'INVITE %s %s %s' % (target, channel, self.channels[channel].ts)) + self._send_with_prefix(numeric, 'INVITE %s %s %s' % (target, channel, self._channels[channel].ts)) def knock(self, numeric, target, text): """Sends a KNOCK from a PyLink client.""" @@ -458,7 +458,7 @@ class TS6Protocol(TS6BaseProtocol): # parameters: channelTS, channel, simple modes, opt. mode parameters..., nicklist # <- :0UY SJOIN 1451041566 #channel +nt :@0UYAAAAAB channel = args[1] - chandata = self.channels[channel].deepcopy() + chandata = self._channels[channel].deepcopy() userlist = args[-1].split() modestring = args[2:-1] or args[2] @@ -495,11 +495,11 @@ class TS6Protocol(TS6BaseProtocol): # Only save mode changes if the remote has lower TS than us. changedmodes |= {('+%s' % mode, user) for mode in finalprefix} - self.channels[channel].users.add(user) + self._channels[channel].users.add(user) # Statekeeping with timestamps their_ts = int(args[0]) - our_ts = self.channels[channel].ts + our_ts = self._channels[channel].ts self.updateTS(servernumeric, channel, their_ts, changedmodes) return {'channel': channel, 'users': namelist, 'modes': parsedmodes, 'ts': their_ts, @@ -516,7 +516,7 @@ class TS6Protocol(TS6BaseProtocol): log.debug('(%s) Got /join 0 from %r, channel list is %r', self.name, numeric, oldchans) for channel in oldchans: - self.channels[channel].users.discard(numeric) + self._channels[channel].users.discard(numeric) self.users[numeric].channels.discard(channel) return {'channels': oldchans, 'text': 'Left all channels.', 'parse_as': 'PART'} else: @@ -524,12 +524,12 @@ class TS6Protocol(TS6BaseProtocol): self.updateTS(numeric, channel, ts) self.users[numeric].channels.add(channel) - self.channels[channel].users.add(numeric) + self._channels[channel].users.add(numeric) # We send users and modes here because SJOIN and JOIN both use one hook, # for simplicity's sake (with plugins). return {'channel': channel, 'users': [numeric], 'modes': - self.channels[channel].modes, 'ts': ts} + self._channels[channel].modes, 'ts': ts} def handle_euid(self, numeric, command, args): """Handles incoming EUID commands (user introduction).""" @@ -610,7 +610,7 @@ class TS6Protocol(TS6BaseProtocol): # <- :42XAAAAAB TMODE 1437450768 #test -c+lkC 3 agte4 # <- :0UYAAAAAD TMODE 0 #a +h 0UYAAAAAD channel = args[1] - oldobj = self.channels[channel].deepcopy() + oldobj = self._channels[channel].deepcopy() modes = args[2:] changedmodes = self.parse_modes(channel, modes) self.apply_modes(channel, changedmodes) @@ -625,8 +625,8 @@ class TS6Protocol(TS6BaseProtocol): ts = args[1] setter = args[2] topic = args[-1] - self.channels[channel].topic = topic - self.channels[channel].topicset = True + self._channels[channel].topic = topic + self._channels[channel].topicset = True return {'channel': channel, 'setter': setter, 'ts': ts, 'text': topic} def handle_etb(self, numeric, command, args): @@ -637,8 +637,8 @@ class TS6Protocol(TS6BaseProtocol): ts = args[2] setter = args[3] topic = args[-1] - self.channels[channel].topic = topic - self.channels[channel].topicset = True + self._channels[channel].topic = topic + self._channels[channel].topicset = True return {'channel': channel, 'setter': setter, 'ts': ts, 'text': topic} def handle_chghost(self, numeric, command, args): diff --git a/protocols/unreal.py b/protocols/unreal.py index ebb1b69..8691b75 100644 --- a/protocols/unreal.py +++ b/protocols/unreal.py @@ -106,7 +106,7 @@ class UnrealProtocol(TS6BaseProtocol): if not self.is_internal_client(client): raise LookupError('No such PyLink client exists.') self._send_with_prefix(client, "JOIN %s" % channel) - self.channels[channel].users.add(client) + self._channels[channel].users.add(client) self.users[client].channels.add(channel) def sjoin(self, server, channel, users, ts=None, modes=set()): @@ -126,8 +126,8 @@ class UnrealProtocol(TS6BaseProtocol): if not server: raise LookupError('No such PyLink server exists.') - changedmodes = set(modes or self.channels[channel].modes) - orig_ts = self.channels[channel].ts + changedmodes = set(modes or self._channels[channel].modes) + orig_ts = self._channels[channel].ts ts = ts or orig_ts uids = [] itemlist = [] @@ -158,7 +158,7 @@ class UnrealProtocol(TS6BaseProtocol): if modepair[0][-1] in self.cmodes['*A']: # Bans, exempts, invex get expanded to forms like "&*!*@some.host" in SJOIN. - if (modepair[0][-1], modepair[1]) in self.channels[channel].modes: + if (modepair[0][-1], modepair[1]) in self._channels[channel].modes: # Mode is already set; skip it. continue @@ -182,7 +182,7 @@ class UnrealProtocol(TS6BaseProtocol): for line in utils.wrapArguments(sjoin_prefix, itemlist, self.S2S_BUFSIZE): self.send(line) - self.channels[channel].users.update(uids) + self._channels[channel].users.update(uids) self.updateTS(server, channel, ts, changedmodes) @@ -217,7 +217,7 @@ class UnrealProtocol(TS6BaseProtocol): modes[idx] = (mode[0], self._expandPUID(mode[1])) # The MODE command is used for channel mode changes only - ts = ts or self.channels[target].ts + ts = ts or self._channels[target].ts # 7 characters for "MODE", the space between MODE and the target, the space between the # target and mode list, and the space between the mode list and TS. @@ -532,15 +532,15 @@ class UnrealProtocol(TS6BaseProtocol): log.debug('(%s) Got /join 0 from %r, channel list is %r', self.name, numeric, oldchans) for ch in oldchans: - self.channels[ch].users.discard(numeric) + self._channels[ch].users.discard(numeric) self.users[numeric].channels.discard(ch) return {'channels': oldchans, 'text': 'Left all channels.', 'parse_as': 'PART'} else: for channel in args[0].split(','): - c = self.channels[channel] + c = self._channels[channel] self.users[numeric].channels.add(channel) - self.channels[channel].users.add(numeric) + self._channels[channel].users.add(numeric) # Call hooks manually, because one JOIN command in UnrealIRCd can # have multiple channels... self.call_hooks([numeric, command, {'channel': channel, 'users': [numeric], 'modes': @@ -551,7 +551,7 @@ class UnrealProtocol(TS6BaseProtocol): # <- :001 SJOIN 1444361345 #test :001AAAAAA @001AAAAAB +001AAAAAC # <- :001 SJOIN 1483250129 #services +nt :+001OR9V02 @*~001DH6901 &*!*@test "*!*@blah.blah '*!*@yes.no channel = args[1] - chandata = self.channels[channel].deepcopy() + chandata = self._channels[channel].deepcopy() userlist = args[-1].split() namelist = [] @@ -614,9 +614,9 @@ class UnrealProtocol(TS6BaseProtocol): # Only merge the remote's prefix modes if their TS is smaller or equal to ours. changedmodes |= {('+%s' % mode, user) for mode in finalprefix} - self.channels[channel].users.add(user) + self._channels[channel].users.add(user) - our_ts = self.channels[channel].ts + our_ts = self._channels[channel].ts their_ts = int(args[0]) self.updateTS(numeric, channel, their_ts, changedmodes) @@ -677,7 +677,7 @@ class UnrealProtocol(TS6BaseProtocol): # Also, we need to get rid of that extra space following the +f argument. :| if utils.isChannel(args[0]): channel = args[0] - oldobj = self.channels[channel].deepcopy() + oldobj = self._channels[channel].deepcopy() modes = [arg for arg in args[1:] if arg] # normalize whitespace parsedmodes = self.parse_modes(channel, modes) @@ -688,7 +688,7 @@ class UnrealProtocol(TS6BaseProtocol): # attempt to set modes by us was rejected for some reason (usually due to # timestamps). Drop the mode change to prevent mode floods. log.debug("(%s) Received mode bounce %s in channel %s! Our TS: %s", - self.name, modes, channel, self.channels[channel].ts) + self.name, modes, channel, self._channels[channel].ts) return self.apply_modes(channel, parsedmodes) @@ -849,9 +849,9 @@ class UnrealProtocol(TS6BaseProtocol): setter = args[1] ts = args[2] - oldtopic = self.channels[channel].topic - self.channels[channel].topic = topic - self.channels[channel].topicset = True + oldtopic = self._channels[channel].topic + self._channels[channel].topic = topic + self._channels[channel].topicset = True return {'channel': channel, 'setter': setter, 'ts': ts, 'text': topic, 'oldtopic': oldtopic}