3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-12-24 19:52:53 +01:00

Support prefix modes (+qaohv); refactor applyModes to apply in place; add removeuser() to IrcChannel

Closes #16.
This commit is contained in:
James Lu 2015-07-05 12:48:39 -07:00
parent d62a413c50
commit b22f674785
3 changed files with 52 additions and 40 deletions

View File

@ -1,3 +1,5 @@
from collections import defaultdict
class IrcUser():
def __init__(self, nick, ts, uid, ident='null', host='null',
realname='PyLink dummy client', realhost='null',
@ -37,13 +39,16 @@ class IrcChannel():
def __init__(self):
self.users = set()
self.modes = set()
'''
self.ops = []
self.halfops = []
self.voices = []
'''
self.prefixmodes = {'ops': set(), 'halfops': set(), 'voices': set(),
'owners': set(), 'admins': set()}
def __repr__(self):
return repr(self.__dict__)
def removeuser(self, target):
for s in self.prefixmodes.values():
s.discard(target)
self.users.discard(target)
class ProtocolError(Exception):
pass

View File

@ -73,11 +73,8 @@ def removeClient(irc, numeric):
Removes a client from our internal databases, regardless
of whether it's one of our pseudoclients or not."""
for k, v in copy(irc.channels).items():
irc.channels[k].users.discard(numeric)
if not irc.channels[k].users:
# Clear empty channels
del irc.channels[k]
for v in irc.channels.values():
v.removeuser(source)
sid = numeric[:3]
print('Removing client %s from irc.users' % numeric)
del irc.users[numeric]
@ -189,9 +186,7 @@ def handle_kick(irc, source, command, args):
def handle_part(irc, source, command, args):
channel = args[0].lower()
# We should only get PART commands for channels that exist, right??
irc.channels[channel].users.remove(source)
if not irc.channels[channel].users:
del irc.channels[channel]
irc.channels[channel].removeuser(source)
try:
reason = args[1]
except IndexError:
@ -209,24 +204,12 @@ def handle_fjoin(irc, servernumeric, command, args):
userlist = args[-1].split()
ts = args[1]
modestring = args[2:-1] or args[2]
irc.channels[channel].modes = utils.applyModes(irc.channels[channel].modes, utils.parseModes(irc, modestring))
utils.applyModes(irc, channel, utils.parseModes(irc, channel, modestring))
namelist = []
for user in userlist:
modeprefix, user = user.split(',', 1)
namelist.append(user)
'''
for mode in modeprefix:
# Note that a user can have more than one mode prefix (e.g. they have both +o and +v),
# so they would be added to both lists.
# left to right: m_ojoin, m_operprefix, owner (~/+q), admin (&/+a), and op (!/+o)
if mode in 'Yyqao':
irc.channels[channel].ops.append(user)
if mode == 'h':
irc.channels[channel].halfops.append(user)
if mode == 'v':
irc.channels[channel].voices.append(user)
'''
utils.applyModes(irc, channel, [('+%s' % mode, user) for mode in modeprefix])
irc.channels[channel].users.add(user)
return {'channel': channel, 'users': namelist}
@ -235,9 +218,9 @@ def handle_uid(irc, numeric, command, args):
uid, ts, nick, realhost, host, ident, ip = args[0:7]
realname = args[-1]
irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname, realhost, ip)
parsedmodes = utils.parseModes(irc, [args[8], args[9]], usermodes=True)
parsedmodes = utils.parseModes(irc, uid, [args[8], args[9]])
print('Applying modes %s for %s' % (parsedmodes, uid))
irc.users[uid].modes = utils.applyModes(irc.users[uid].modes, parsedmodes)
utils.applyModes(irc, uid, parsedmodes)
irc.servers[numeric].users.append(uid)
return {'uid': uid, 'ts': ts, 'nick': nick, 'realhost': realhost, 'host': host, 'ident': ident, 'ip': ip}
@ -284,8 +267,8 @@ def handle_fmode(irc, numeric, command, args):
# <- :70MAAAAAA FMODE #chat 1433653462 +hhT 70MAAAAAA 70MAAAAAD
channel = args[0].lower()
modes = args[2:]
changedmodes = utils.parseModes(irc, modes)
irc.channels[channel].modes = utils.applyModes(irc.channels[channel].modes, changedmodes)
changedmodes = utils.parseModes(irc, channel, modes)
utils.applyModes(irc, channel, changedmodes)
return {'target': channel, 'modes': changedmodes}
def handle_mode(irc, numeric, command, args):
@ -294,8 +277,8 @@ def handle_mode(irc, numeric, command, args):
# <- :70MAAAAAA MODE 70MAAAAAA -i+xc
target = args[0]
modestrings = args[1:]
changedmodes = utils.parseModes(irc, modestrings, usermodes=True)
irc.users[numeric].modes = utils.applyModes(irc.users[numeric].modes, changedmodes)
changedmodes = utils.parseModes(irc, numeric, modestrings)
utils.applyModes(irc, numeric, changedmodes)
return {'target': target, 'modes': changedmodes}
def handle_squit(irc, numeric, command, args):

View File

@ -83,7 +83,7 @@ def isServerName(s):
return _isASCII(s) and '.' in s and not s.startswith('.') \
and not s.endswith('.')
def parseModes(irc, args, usermodes=False):
def parseModes(irc, target, args):
"""Parses a mode string into a list of (mode, argument) tuples.
['+mitl-o', '3', 'person'] => [('+m', None), ('+i', None), ('+t', None), ('+l', '3'), ('-o', 'person')]
"""
@ -92,7 +92,7 @@ def parseModes(irc, args, usermodes=False):
# B = Mode that changes a setting and always has a parameter.
# C = Mode that changes a setting and only has a parameter when set.
# D = Mode that changes a setting and never has a parameter.
print(args)
usermodes = not isChannel(target)
modestring = args[0]
if not modestring:
return ValueError('No modes supplied in parseModes query: %r' % modes)
@ -117,8 +117,7 @@ def parseModes(irc, args, usermodes=False):
elif mode in irc.prefixmodes and not usermodes:
# We're setting a prefix mode on someone (e.g. +o user1)
print('%s: prefixmode.' % mode)
# TODO: handle this properly (issue #16).
continue
arg = args.pop(0)
elif prefix == '+' and mode in supported_modes['*C']:
# Only has parameter when setting.
print('%s: Only has parameter when setting.' % mode)
@ -126,11 +125,37 @@ def parseModes(irc, args, usermodes=False):
res.append((prefix + mode, arg))
return res
def applyModes(modelist, changedmodes):
modelist = modelist.copy()
def applyModes(irc, target, changedmodes):
usermodes = not isChannel(target)
print('usermodes? %s' % usermodes)
if usermodes:
modelist = irc.users[target].modes
else:
modelist = irc.channels[target].modes
print('Initial modelist: %s' % modelist)
print('Changedmodes: %r' % changedmodes)
for mode in changedmodes:
if not usermodes:
pmode = ''
for m in ('owner', 'admin', 'op', 'halfop', 'voice'):
if m in irc.cmodes and mode[0][1] == irc.cmodes[m]:
pmode = m+'s'
print('pmode? %s' % pmode)
if pmode:
print('pmode == True')
print(mode)
print(irc.channels[target].prefixmodes)
pmodelist = irc.channels[target].prefixmodes[pmode]
print(pmodelist)
print('Initial pmodelist: %s' % pmodelist)
if mode[0][0] == '+':
pmodelist.add(mode[1])
print('+')
else:
pmodelist.discard(mode[1])
print('-')
print('Final pmodelist: %s' % pmodelist)
continue
if mode[0][0] == '+':
# We're adding a mode
modelist.add(mode)
@ -141,7 +166,6 @@ def applyModes(modelist, changedmodes):
modelist.discard(mode)
print('Removing mode %r' % str(mode))
print('Final modelist: %s' % modelist)
return modelist
def joinModes(modes):
modelist = ''