mirror of
https://github.com/jlu5/PyLink.git
synced 2025-01-11 20:52:42 +01:00
Merge branch 'wip/protocol-caps' into devel
This commit is contained in:
commit
c894beed2e
@ -1409,6 +1409,12 @@ class Protocol():
|
||||
|
||||
return real_args
|
||||
|
||||
def hasCap(self, capab):
|
||||
"""
|
||||
Returns whether this protocol module instance has the requested capability.
|
||||
"""
|
||||
return capab.lower() in self.protocol_caps
|
||||
|
||||
def removeClient(self, numeric):
|
||||
"""Internal function to remove a client from our internal state."""
|
||||
for c, v in self.irc.channels.copy().items():
|
||||
|
@ -14,6 +14,11 @@ def spawn_service(irc, source, command, args):
|
||||
# Service name
|
||||
name = args['name']
|
||||
|
||||
if name != 'pylink' and not irc.proto.hasCap('can-spawn-clients'):
|
||||
log.debug("(%s) Not spawning service %s because the server doesn't support spawning clients",
|
||||
irc.name, name)
|
||||
return
|
||||
|
||||
# Get the ServiceBot object.
|
||||
sbot = world.services[name]
|
||||
|
||||
@ -26,10 +31,6 @@ def spawn_service(irc, source, command, args):
|
||||
nick = irc.serverdata.get("%s_nick" % name) or conf.conf.get(name, {}).get('nick') or sbot.nick or name
|
||||
ident = irc.serverdata.get("%s_ident" % name) or conf.conf.get(name, {}).get('ident') or sbot.ident or name
|
||||
|
||||
if name != 'pylink' and irc.protoname == 'clientbot':
|
||||
# Prefix service bots spawned on Clientbot to prevent possible nick collisions.
|
||||
nick = 'PyLinkService@' + nick
|
||||
|
||||
# TODO: make this configurable?
|
||||
host = irc.hostname()
|
||||
|
||||
|
@ -108,7 +108,7 @@ def showchan(irc, source, args):
|
||||
if c.topic:
|
||||
f('\x02Channel topic\x02: %s' % c.topic)
|
||||
|
||||
if irc.protoname != 'clientbot':
|
||||
if irc.proto.hasCap('has-ts'):
|
||||
# Clientbot-specific hack: don't show channel TS because it's not properly tracked.
|
||||
f('\x02Channel creation time\x02: %s (%s)' % (ctime(c.ts), c.ts))
|
||||
|
||||
|
@ -112,13 +112,12 @@ def normalize_nick(irc, netname, nick, times_tagged=0, uid=''):
|
||||
|
||||
log.debug('(%s) relay.normalize_nick: using %r as separator.', irc.name, separator)
|
||||
orig_nick = nick
|
||||
protoname = irc.protoname
|
||||
maxnicklen = irc.maxnicklen
|
||||
|
||||
# Charybdis, IRCu, etc. don't allow / in nicks, and will SQUIT with a protocol
|
||||
# violation if it sees one. Or it might just ignore the client introduction and
|
||||
# cause bad desyncs.
|
||||
protocol_allows_slashes = protoname.startswith(('insp', 'unreal', 'clientbot')) or \
|
||||
protocol_allows_slashes = irc.proto.hasCap('slash-in-nicks') or \
|
||||
irc.serverdata.get('relay_force_slashes')
|
||||
|
||||
if '/' not in separator or not protocol_allows_slashes:
|
||||
@ -177,12 +176,12 @@ def normalize_host(irc, host):
|
||||
log.debug('(%s) relay.normalize_host: IRCd=%s, host=%s', irc.name, irc.protoname, host)
|
||||
|
||||
allowed_chars = string.ascii_letters + string.digits + '-.:'
|
||||
if irc.protoname in ('inspircd', 'ts6', 'clientbot', 'nefarious'):
|
||||
if irc.proto.hasCap('slash-in-hosts'):
|
||||
# UnrealIRCd and IRCd-Hybrid don't allow slashes in hostnames
|
||||
allowed_chars += '/'
|
||||
|
||||
if irc.protoname in ('inspircd', 'clientbot', 'nefarious', 'unreal'):
|
||||
# The above IRCds allow _ in hostnames, while TS6-like IRCds do not.
|
||||
if irc.proto.hasCap('underscore-in-hosts'):
|
||||
# Most IRCds allow _ in hostnames, but hybrid/charybdis/ratbox IRCds do not.
|
||||
allowed_chars += '_'
|
||||
|
||||
for char in host:
|
||||
@ -648,7 +647,7 @@ def relay_joins(irc, channel, users, ts, burst=True):
|
||||
|
||||
# Fetch the known channel TS and all the prefix modes for each user. This ensures
|
||||
# the different sides of the relay are merged properly.
|
||||
if irc.protoname == 'clientbot':
|
||||
if not irc.proto.hasCap('has-ts'):
|
||||
# Special hack for clientbot: just use the remote's modes so mode changes
|
||||
# take precendence. protocols/clientbot does not track channel TS.
|
||||
ts = remoteirc.channels[remotechan].ts
|
||||
@ -783,7 +782,7 @@ def get_supported_cmodes(irc, remoteirc, channel, modes):
|
||||
"for network %r.",
|
||||
irc.name, modechar, arg, remoteirc.name)
|
||||
|
||||
if irc.protoname == 'clientbot' and irc.pseudoclient and arg == irc.pseudoclient.uid:
|
||||
if (not irc.proto.hasCap('can-spawn-clients')) and irc.pseudoclient and arg == irc.pseudoclient.uid:
|
||||
# Skip modesync on the main PyLink client.
|
||||
log.debug("(%s) relay.get_supported_cmodes: filtering prefix change (%r, %r) on Clientbot relayer",
|
||||
irc.name, name, arg)
|
||||
@ -876,7 +875,7 @@ def handle_relay_whois(irc, source, command, args):
|
||||
# Send account information if told to and the target is logged in.
|
||||
wreply(330, "%s :is logged in (on %s) as" % (realuser.services_account, netname))
|
||||
|
||||
if checkSendKey('whois_show_server') and realirc.protoname != 'clientbot':
|
||||
if checkSendKey('whois_show_server') and realirc.proto.hasCap('can-track-servers'):
|
||||
wreply(320, ":is actually connected via the following server:")
|
||||
realserver = realirc.getServer(uid)
|
||||
realserver = realirc.servers[realserver]
|
||||
@ -1017,7 +1016,7 @@ def handle_part(irc, numeric, command, args):
|
||||
if numeric == irc.pseudoclient.uid:
|
||||
# For clientbot: treat forced parts to the bot as clearchan, and attempt to rejoin only
|
||||
# if it affected a relay.
|
||||
if irc.protoname == 'clientbot':
|
||||
if not irc.proto.hasCap('can-spawn-clients'):
|
||||
for channel in [c for c in channels if get_relay((irc.name, c))]:
|
||||
for user in irc.channels[channel].users:
|
||||
if (not irc.isInternalClient(user)) and (not isRelayClient(irc, user)):
|
||||
@ -1087,8 +1086,9 @@ def handle_messages(irc, numeric, command, args):
|
||||
# No relay clone exists for the sender; route the message through our
|
||||
# main client (or SID for notices).
|
||||
|
||||
# Skip "from:" formatting for servers; it's messy with longer hostnames
|
||||
if numeric not in irc.servers:
|
||||
# Skip "from:" formatting for servers; it's messy with longer hostnames.
|
||||
# Also skip this formatting for servicebot relaying.
|
||||
if numeric not in irc.servers and not irc.getServiceBot(numeric):
|
||||
displayedname = irc.getFriendlyName(numeric)
|
||||
real_text = '<%s/%s> %s' % (displayedname, irc.name, text)
|
||||
else:
|
||||
@ -1148,7 +1148,7 @@ def handle_messages(irc, numeric, command, args):
|
||||
return
|
||||
remoteirc = world.networkobjects[homenet]
|
||||
|
||||
if remoteirc.protoname == 'clientbot' and not conf.conf.get('relay', {}).get('allow_clientbot_pms'):
|
||||
if (not remoteirc.proto.hasCap('can-spawn-clients')) and not conf.conf.get('relay', {}).get('allow_clientbot_pms'):
|
||||
irc.msg(numeric, 'Private messages to users connected via Clientbot have '
|
||||
'been administratively disabled.', notice=True)
|
||||
return
|
||||
@ -1179,7 +1179,7 @@ def handle_kick(irc, source, command, args):
|
||||
relay = get_relay((irc.name, channel))
|
||||
|
||||
# Special case for clientbot: treat kicks to the PyLink service bot as channel clear.
|
||||
if irc.protoname == 'clientbot' and irc.pseudoclient and target == irc.pseudoclient.uid:
|
||||
if (not irc.proto.hasCap('can-spawn-clients')) and irc.pseudoclient and target == irc.pseudoclient.uid:
|
||||
for user in irc.channels[channel].users:
|
||||
if (not irc.isInternalClient(user)) and (not isRelayClient(irc, user)):
|
||||
reason = "Clientbot kicked by %s (Reason: %s)" % (irc.getFriendlyName(source), text)
|
||||
@ -1246,7 +1246,7 @@ def handle_kick(irc, source, command, args):
|
||||
# common channels with the target relay network.
|
||||
rsid = get_remote_sid(remoteirc, irc)
|
||||
log.debug('(%s) relay.handle_kick: Kicking %s from channel %s via %s on behalf of %s/%s', irc.name, real_target, remotechan, rsid, kicker, irc.name)
|
||||
if irc.protoname == 'clientbot':
|
||||
if not irc.proto.hasCap('can-spawn-clients'):
|
||||
# Special case for clientbot: no kick prefixes are needed.
|
||||
text = args['text']
|
||||
else:
|
||||
@ -1582,7 +1582,7 @@ def create(irc, source, args):
|
||||
if not utils.isChannel(channel):
|
||||
irc.error('Invalid channel %r.' % channel)
|
||||
return
|
||||
if irc.protoname == 'clientbot':
|
||||
if not irc.proto.hasCap('can-host-relay'):
|
||||
irc.error('Clientbot networks cannot be used to host a relay.')
|
||||
return
|
||||
if source not in irc.channels[channel].users:
|
||||
@ -1780,7 +1780,7 @@ def link(irc, source, args):
|
||||
|
||||
our_ts = irc.channels[localchan].ts
|
||||
their_ts = world.networkobjects[remotenet].channels[args.channel].ts
|
||||
if (our_ts < their_ts) and irc.protoname != 'clientbot':
|
||||
if (our_ts < their_ts) and irc.proto.hasCap('has-ts'):
|
||||
log.debug('(%s) relay: Blocking link request %s%s -> %s%s due to bad TS (%s < %s)', irc.name,
|
||||
irc.name, localchan, remotenet, args.channel, our_ts, their_ts)
|
||||
irc.error("The channel creation date (TS) on %s (%s) is lower than the target "
|
||||
|
@ -204,7 +204,7 @@ def rpm(irc, source, args):
|
||||
return
|
||||
|
||||
relay = world.plugins.get('relay')
|
||||
if irc.protoname != 'clientbot':
|
||||
if irc.proto.hasCap('can-spawn-clients'):
|
||||
irc.error('This command is only supported on Clientbot networks. Try /msg %s <text>' % target)
|
||||
return
|
||||
elif relay is None:
|
||||
|
@ -78,7 +78,7 @@ def _map(irc, source, args, show_relay=True):
|
||||
# This is a relay server - display the remote map of the network it represents
|
||||
relay_server = serverlist[leaf].remote
|
||||
remoteirc = world.networkobjects[relay_server]
|
||||
if remoteirc.protoname != 'clientbot':
|
||||
if remoteirc.proto.hasCap('can-track-servers'):
|
||||
# Only ever show relay subservers once - this prevents infinite loops.
|
||||
showall(remoteirc, remoteirc.sid, hops=hops, is_relay_server=True)
|
||||
|
||||
|
@ -14,6 +14,8 @@ class ClientbotWrapperProtocol(Protocol):
|
||||
def __init__(self, irc):
|
||||
super().__init__(irc)
|
||||
|
||||
self.protocol_caps = {'clear-channels-on-leave', 'slash-in-nicks', 'slash-in-hosts', 'underscore-in-hosts'}
|
||||
|
||||
self.has_eob = False
|
||||
|
||||
# Remove conf key checks for those not needed for Clientbot.
|
||||
|
@ -13,6 +13,9 @@ from pylinkirc.protocols.ts6_common import *
|
||||
class InspIRCdProtocol(TS6BaseProtocol):
|
||||
def __init__(self, irc):
|
||||
super().__init__(irc)
|
||||
|
||||
self.protocol_caps |= {'slash-in-nicks', 'slash-in-hosts', 'underscore-in-hosts'}
|
||||
|
||||
# Set our case mapping (rfc1459 maps "\" and "|" together, for example).
|
||||
self.casemapping = 'rfc1459'
|
||||
|
||||
|
@ -35,6 +35,7 @@ def p10b64encode(num, length=2):
|
||||
class P10SIDGenerator():
|
||||
def __init__(self, irc):
|
||||
self.irc = irc
|
||||
|
||||
try:
|
||||
query = irc.serverdata["sidrange"]
|
||||
except (KeyError, ValueError):
|
||||
@ -74,6 +75,8 @@ class P10Protocol(IRCS2SProtocol):
|
||||
|
||||
self.hook_map = {'END_OF_BURST': 'ENDBURST', 'OPMODE': 'MODE', 'CLEARMODE': 'MODE', 'BURST': 'JOIN'}
|
||||
|
||||
self.protocol_caps |= {'slash-in-hosts', 'underscore-in-hosts'}
|
||||
|
||||
def _send(self, source, text):
|
||||
self.irc.send("%s %s" % (source, text))
|
||||
|
||||
|
@ -15,6 +15,7 @@ S2S_BUFSIZE = 510
|
||||
class TS6Protocol(TS6BaseProtocol):
|
||||
def __init__(self, irc):
|
||||
super().__init__(irc)
|
||||
self.protocol_caps |= {'slash-in-hosts'}
|
||||
self.casemapping = 'rfc1459'
|
||||
self.hook_map = {'SJOIN': 'JOIN', 'TB': 'TOPIC', 'TMODE': 'MODE', 'BMASK': 'MODE',
|
||||
'EUID': 'UID', 'RSFNC': 'SVSNICK', 'ETB': 'TOPIC'}
|
||||
|
@ -23,6 +23,7 @@ S2S_BUFSIZE = 427
|
||||
class UnrealProtocol(TS6BaseProtocol):
|
||||
def __init__(self, irc):
|
||||
super().__init__(irc)
|
||||
self.protocol_caps |= {'slash-in-nicks', 'underscore-in-hosts'}
|
||||
# Set our case mapping (rfc1459 maps "\" and "|" together, for example)
|
||||
self.casemapping = 'ascii'
|
||||
self.proto_ver = 4000
|
||||
|
Loading…
Reference in New Issue
Block a user