From 379f442a141860d490009420ed219d46fe5841a2 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sat, 20 Jun 2015 20:36:35 -0700 Subject: [PATCH] Add basic user mode tracking (Closes #10) --- classes.py | 3 ++- protocols/inspircd.py | 30 ++++++++++++++++++++---------- utils.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/classes.py b/classes.py index f1c0322..2c0bd31 100644 --- a/classes.py +++ b/classes.py @@ -1,7 +1,7 @@ class IrcUser(): def __init__(self, nick, ts, uid, ident='null', host='null', realname='PyLink dummy client', realhost='null', - ip='0.0.0.0'): + ip='0.0.0.0', modes=[]): self.nick = nick self.ts = ts self.uid = uid @@ -10,6 +10,7 @@ class IrcUser(): self.realhost = realhost self.ip = ip self.realname = realname + self.modes = modes self.identified = False diff --git a/protocols/inspircd.py b/protocols/inspircd.py index 62d6dc7..d7afcf3 100644 --- a/protocols/inspircd.py +++ b/protocols/inspircd.py @@ -3,12 +3,12 @@ import time import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from utils import * +import utils from copy import copy import traceback from classes import * -uidgen = TS6UIDGenerator() +uidgen = utils.TS6UIDGenerator() def _sendFromServer(irc, msg): irc.send(':%s %s' % (irc.sid, msg)) @@ -19,7 +19,7 @@ def _sendFromUser(irc, numeric, msg): def spawnClient(irc, nick, ident, host, *args): uid = uidgen.next_uid(irc.sid) ts = int(time.time()) - if not isNick(nick): + if not utils.isNick(nick): raise ValueError('Invalid nickname %r.' % nick) _sendFromServer(irc, "UID {uid} {ts} {nick} {host} {host} {ident} 0.0.0.0 {ts} +o +" " :PyLink Client".format(ts=ts, host=host, @@ -32,7 +32,7 @@ def joinClient(irc, client, channel): # One channel per line here! if not isInternalClient(irc, client): raise LookupError('No such PyLink PseudoClient exists.') - if not isChannel(channel): + if not utils.isChannel(channel): raise ValueError('Invalid channel name %r.' % channel) _sendFromServer(irc, "FJOIN {channel} {ts} + :,{uid}".format( ts=int(time.time()), uid=client, channel=channel)) @@ -41,7 +41,7 @@ def partClient(irc, client, channel, reason=None): if not isInternalClient(irc, client): raise LookupError('No such PyLink PseudoClient exists.') msg = "PART %s" % channel - if not isChannel(channel): + if not utils.isChannel(channel): raise ValueError('Invalid channel name %r.' % channel) if reason: msg += " :%s" % reason @@ -98,7 +98,7 @@ def nickClient(irc, numeric, newnick): Changes the nick of a PyLink PseudoClient.""" if not isInternalClient(irc, numeric): raise LookupError('No such PyLink PseudoClient exists.') - if not isNick(newnick): + if not utils.isNick(newnick): raise ValueError('Invalid nickname %r.' % nick) _sendFromUser(irc, numeric, 'NICK %s %s' % (newnick, int(time.time()))) irc.users[numeric].nick = newnick @@ -142,15 +142,15 @@ def handle_privmsg(irc, source, command, args): except IndexError: cmd_args = [] try: - func = bot_commands[cmd] + func = utils.bot_commands[cmd] except KeyError: - msg(irc, source, 'Unknown command %r.' % cmd) + utils.msg(irc, source, 'Unknown command %r.' % cmd) return try: func(irc, source, cmd_args) except Exception as e: traceback.print_exc() - msg(irc, source, 'Uncaught exception in command %r: %s: %s' % (cmd, type(e).__name__, str(e))) + utils.msg(irc, source, 'Uncaught exception in command %r: %s: %s' % (cmd, type(e).__name__, str(e))) return def handle_kill(irc, source, command, args): @@ -205,8 +205,9 @@ def handle_fjoin(irc, servernumeric, command, args): def handle_uid(irc, numeric, command, args): # :70M UID 70MAAAAAB 1429934638 GL 0::1 hidden-7j810p.9mdf.lrek.0000.0000.IP gl 0::1 1429934638 +Wioswx +ACGKNOQXacfgklnoqvx :realname uid, ts, nick, realhost, host, ident, ip = args[0:7] + modes = utils.parseModes(args[8:9]) 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, modes) irc.servers[numeric].users.append(uid) def handle_quit(irc, numeric, command, args): @@ -246,6 +247,15 @@ def handle_fmode(irc, numeric, command, args): modestrings = args[3:] ''' +def handle_mode(irc, numeric, command, args): + # In InspIRCd, MODE is used for setting user modes and + # FMODE is used for channel modes: + # <- :70MAAAAAA MODE 70MAAAAAA -i+xc + target = args[0] + modestrings = args[1:] + changedmodes = utils.parseModes(modestrings) + utils.applyModes(irc.users[numeric].modes, changedmodes) + def handle_squit(irc, numeric, command, args): # :70M SQUIT 1ML :Server quit by GL!gl@0::1 split_server = args[0] diff --git a/utils.py b/utils.py index 141c563..b1b735c 100644 --- a/utils.py +++ b/utils.py @@ -57,3 +57,33 @@ def isNick(s, nicklen=None): def isChannel(s): return bool(s.startswith('#')) + +def parseModes(args): + """['+mitl-o', '3', 'person'] => ['+m', '+i', '+t', '-o'] + + TODO: handle modes with extra arguments (mainly channel modes like +beIqlk) + """ + modes = args[0] + extramodes = args[1:] + if not modes: + return ValueError('No modes supplied in parseModes query: %r' % modes) + res = [] + for mode in modes: + if mode in '+-': + prefix = mode + else: + res.append(prefix + mode) + return res + +def applyModes(modelist, changedmodes): + for mode in changedmodes: + if mode[0] == '+': + # We're adding a mode + modelist.append(mode) + else: + # We're removing a mode + try: + modelist.remove(mode.replace('-', '+')) + except ValueError: + print('Attempted to remove modes %r not in %s\'s modes' % (mode, numeric)) + return modelist