3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-12-24 11:42:51 +01:00

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)
This commit is contained in:
James Lu 2017-08-25 02:11:48 -07:00
parent f34198647e
commit 80766e051e
9 changed files with 137 additions and 132 deletions

View File

@ -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.

View File

@ -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):
"""

View File

@ -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):

View File

@ -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

View File

@ -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}

View File

@ -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}

View File

@ -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 = []

View File

@ -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):

View File

@ -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}