diff --git a/classes.py b/classes.py index dcd02c5..bd61edb 100644 --- a/classes.py +++ b/classes.py @@ -262,7 +262,7 @@ class Irc(): 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', opertype='IRC Operator'): self.nick = nick self.ts = ts self.uid = uid diff --git a/plugins/relay.py b/plugins/relay.py index 1c1049d..e281365 100644 --- a/plugins/relay.py +++ b/plugins/relay.py @@ -150,9 +150,25 @@ def getRemoteUser(irc, remoteirc, user, spawnIfMissing=True): host = userobj.host[:64] realname = userobj.realname modes = getSupportedUmodes(irc, remoteirc, userobj.modes) + if hasattr(userobj, 'opertype'): + # InspIRCd's special OPERTYPE command; this is mandatory + # and setting of umode +/-o will fail unless this + # is used instead. This also sets an oper type for + # the user, which is used in WHOIS, etc. + + # If an opertype exists for the user, add " (remote)" + # for the relayed clone, so that it shows in whois. + # Janus does this too. :) + # OPERTYPE uses underscores instead of spaces, FYI. + log.debug('(%s) relay.getRemoteUser: setting OPERTYPE of client for %r to %s', + irc.name, user, userobj.opertype) + opertype = userobj.opertype + '_(remote)' + else: + opertype = 'IRC_Operator_(remote)' u = remoteirc.proto.spawnClient(remoteirc, nick, ident=ident, host=host, realname=realname, - modes=modes, ts=userobj.ts).uid + modes=modes, ts=userobj.ts, + opertype=opertype).uid remoteirc.users[u].remote = (irc.name, user) away = userobj.away if away: @@ -160,6 +176,14 @@ def getRemoteUser(irc, remoteirc, user, spawnIfMissing=True): relayusers[(irc.name, user)][remoteirc.name] = u return u +def handle_operup(irc, numeric, command, args): + newtype = args['text'] + '_(remote)' + for netname, user in relayusers[(irc.name, numeric)].items(): + log.debug('(%s) relay.handle_opertype: setting OPERTYPE of %s/%s to %s', irc.name, user, netname, newtype) + remoteirc = world.networkobjects[netname] + remoteirc.users[user].opertype = newtype +utils.add_hook(handle_operup, 'PYLINK_CLIENT_OPERED') + def getLocalUser(irc, user, targetirc=None): """ [] diff --git a/protocols/inspircd.py b/protocols/inspircd.py index 7583911..d97640a 100644 --- a/protocols/inspircd.py +++ b/protocols/inspircd.py @@ -703,7 +703,10 @@ def handle_opertype(irc, numeric, command, args): omode = [('+o', None)] irc.users[numeric].opertype = opertype = args[0] utils.applyModes(irc, numeric, omode) - return {'target': numeric, 'modes': omode, 'text': opertype} + # OPERTYPE is essentially umode +o and metadata in one command; + # we'll call that too. + irc.callHooks([numeric, 'PYLINK_CLIENT_OPERED', {'text': opertype}]) + return {'target': numeric, 'modes': omode} def handle_fident(irc, numeric, command, args): # :70MAAAAAB FHOST test diff --git a/protocols/ts6.py b/protocols/ts6.py index 0508e4f..366d805 100644 --- a/protocols/ts6.py +++ b/protocols/ts6.py @@ -40,7 +40,7 @@ def spawnClient(irc, nick, ident='null', host='null', realhost=None, modes=set() realhost = realhost or host raw_modes = utils.joinModes(modes) u = irc.users[uid] = IrcUser(nick, ts, uid, ident=ident, host=host, realname=realname, - realhost=realhost, ip=ip) + realhost=realhost, ip=ip, opertype=opertype or 'IRC_Operator') utils.applyModes(irc, uid, modes) irc.servers[server].users.add(uid) _send(irc, server, "EUID {nick} 1 {ts} {modes} {ident} {host} {ip} {uid} " @@ -470,6 +470,9 @@ def handle_euid(irc, numeric, command, args): log.debug('Applying modes %s for %s', parsedmodes, uid) utils.applyModes(irc, uid, parsedmodes) irc.servers[numeric].users.add(uid) + if ('o', None) in parsedmodes: + otype = 'Server_Administrator' if ('a', None) in parsedmodes else 'IRC_Operator' + irc.callHooks([uid, 'PYLINK_CLIENT_OPERED', {'text': otype}]) return {'uid': uid, 'ts': ts, 'nick': nick, 'realhost': realhost, 'host': host, 'ident': ident, 'ip': ip} def handle_uid(irc, numeric, command, args): @@ -502,6 +505,17 @@ def handle_tmode(irc, numeric, command, args): ts = int(args[0]) return {'target': channel, 'modes': changedmodes, 'ts': ts} +def handle_mode(irc, numeric, command, args): + # <- :70MAAAAAA MODE 70MAAAAAA -i+xc + target = args[0] + modestrings = args[1:] + changedmodes = utils.parseModes(irc, numeric, modestrings) + utils.applyModes(irc, target, changedmodes) + if ('+o', None) in changedmodes: + otype = 'Server_Administrator' if ('a', None) in irc.users[target].modes else 'IRC_Operator' + irc.callHooks([target, 'PYLINK_CLIENT_OPERED', {'text': otype}]) + return {'target': target, 'modes': changedmodes} + def handle_events(irc, data): # TS6 messages: # :42X COMMAND arg1 arg2 :final long arg