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