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

View File

@ -73,11 +73,8 @@ def removeClient(irc, numeric):
Removes a client from our internal databases, regardless Removes a client from our internal databases, regardless
of whether it's one of our pseudoclients or not.""" of whether it's one of our pseudoclients or not."""
for k, v in copy(irc.channels).items(): for v in irc.channels.values():
irc.channels[k].users.discard(numeric) v.removeuser(source)
if not irc.channels[k].users:
# Clear empty channels
del irc.channels[k]
sid = numeric[:3] sid = numeric[:3]
print('Removing client %s from irc.users' % numeric) print('Removing client %s from irc.users' % numeric)
del 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): def handle_part(irc, source, command, args):
channel = args[0].lower() channel = args[0].lower()
# We should only get PART commands for channels that exist, right?? # We should only get PART commands for channels that exist, right??
irc.channels[channel].users.remove(source) irc.channels[channel].removeuser(source)
if not irc.channels[channel].users:
del irc.channels[channel]
try: try:
reason = args[1] reason = args[1]
except IndexError: except IndexError:
@ -209,24 +204,12 @@ def handle_fjoin(irc, servernumeric, command, args):
userlist = args[-1].split() userlist = args[-1].split()
ts = args[1] ts = args[1]
modestring = args[2:-1] or args[2] 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 = [] namelist = []
for user in userlist: for user in userlist:
modeprefix, user = user.split(',', 1) modeprefix, user = user.split(',', 1)
namelist.append(user) namelist.append(user)
''' utils.applyModes(irc, channel, [('+%s' % mode, user) for mode in modeprefix])
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)
'''
irc.channels[channel].users.add(user) irc.channels[channel].users.add(user)
return {'channel': channel, 'users': namelist} 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] uid, ts, nick, realhost, host, ident, ip = args[0:7]
realname = args[-1] realname = args[-1]
irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname, realhost, ip) 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)) 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) irc.servers[numeric].users.append(uid)
return {'uid': uid, 'ts': ts, 'nick': nick, 'realhost': realhost, 'host': host, 'ident': ident, 'ip': ip} 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 # <- :70MAAAAAA FMODE #chat 1433653462 +hhT 70MAAAAAA 70MAAAAAD
channel = args[0].lower() channel = args[0].lower()
modes = args[2:] modes = args[2:]
changedmodes = utils.parseModes(irc, modes) changedmodes = utils.parseModes(irc, channel, modes)
irc.channels[channel].modes = utils.applyModes(irc.channels[channel].modes, changedmodes) utils.applyModes(irc, channel, changedmodes)
return {'target': channel, 'modes': changedmodes} return {'target': channel, 'modes': changedmodes}
def handle_mode(irc, numeric, command, args): def handle_mode(irc, numeric, command, args):
@ -294,8 +277,8 @@ def handle_mode(irc, numeric, command, args):
# <- :70MAAAAAA MODE 70MAAAAAA -i+xc # <- :70MAAAAAA MODE 70MAAAAAA -i+xc
target = args[0] target = args[0]
modestrings = args[1:] modestrings = args[1:]
changedmodes = utils.parseModes(irc, modestrings, usermodes=True) changedmodes = utils.parseModes(irc, numeric, modestrings)
irc.users[numeric].modes = utils.applyModes(irc.users[numeric].modes, changedmodes) utils.applyModes(irc, numeric, changedmodes)
return {'target': target, 'modes': changedmodes} return {'target': target, 'modes': changedmodes}
def handle_squit(irc, numeric, command, args): 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('.') \ return _isASCII(s) and '.' in s and not s.startswith('.') \
and not s.endswith('.') 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. """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')] ['+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. # B = Mode that changes a setting and always has a parameter.
# C = Mode that changes a setting and only has a parameter when set. # C = Mode that changes a setting and only has a parameter when set.
# D = Mode that changes a setting and never has a parameter. # D = Mode that changes a setting and never has a parameter.
print(args) usermodes = not isChannel(target)
modestring = args[0] modestring = args[0]
if not modestring: if not modestring:
return ValueError('No modes supplied in parseModes query: %r' % modes) 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: elif mode in irc.prefixmodes and not usermodes:
# We're setting a prefix mode on someone (e.g. +o user1) # We're setting a prefix mode on someone (e.g. +o user1)
print('%s: prefixmode.' % mode) print('%s: prefixmode.' % mode)
# TODO: handle this properly (issue #16). arg = args.pop(0)
continue
elif prefix == '+' and mode in supported_modes['*C']: elif prefix == '+' and mode in supported_modes['*C']:
# Only has parameter when setting. # Only has parameter when setting.
print('%s: Only has parameter when setting.' % mode) print('%s: Only has parameter when setting.' % mode)
@ -126,11 +125,37 @@ def parseModes(irc, args, usermodes=False):
res.append((prefix + mode, arg)) res.append((prefix + mode, arg))
return res return res
def applyModes(modelist, changedmodes): def applyModes(irc, target, changedmodes):
modelist = modelist.copy() 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('Initial modelist: %s' % modelist)
print('Changedmodes: %r' % changedmodes) print('Changedmodes: %r' % changedmodes)
for mode in 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] == '+': if mode[0][0] == '+':
# We're adding a mode # We're adding a mode
modelist.add(mode) modelist.add(mode)
@ -141,7 +166,6 @@ def applyModes(modelist, changedmodes):
modelist.discard(mode) modelist.discard(mode)
print('Removing mode %r' % str(mode)) print('Removing mode %r' % str(mode))
print('Final modelist: %s' % modelist) print('Final modelist: %s' % modelist)
return modelist
def joinModes(modes): def joinModes(modes):
modelist = '' modelist = ''