mirror of
https://github.com/jlu5/PyLink.git
synced 2025-02-20 07:20:59 +01:00
Merge remote-tracking branch 'origin/clientbot-fixes' into devel
This commit is contained in:
commit
66c762b63f
@ -163,3 +163,29 @@ def handle_time(irc, source, command, args):
|
|||||||
timestring = time.ctime()
|
timestring = time.ctime()
|
||||||
irc.numeric(irc.sid, 391, source, '%s :%s' % (irc.hostname(), timestring))
|
irc.numeric(irc.sid, 391, source, '%s :%s' % (irc.hostname(), timestring))
|
||||||
utils.add_hook(handle_time, 'TIME')
|
utils.add_hook(handle_time, 'TIME')
|
||||||
|
|
||||||
|
def _state_cleanup_core(irc, source, channel):
|
||||||
|
"""
|
||||||
|
Handles PART and KICK on clientbot-like networks (where only the users and channels we see are available)
|
||||||
|
by deleting channels when we leave and users when they leave all shared channels.
|
||||||
|
"""
|
||||||
|
if irc.has_cap('visible-state-only'):
|
||||||
|
# Delete channels that we were removed from.
|
||||||
|
if irc.pseudoclient and source == irc.pseudoclient.uid:
|
||||||
|
log.debug('(%s) state_cleanup: removing channel %s since we have left', irc.name, channel)
|
||||||
|
del irc._channels[channel]
|
||||||
|
|
||||||
|
# Delete users no longer sharing a channel with us.
|
||||||
|
if not irc.users[source].channels:
|
||||||
|
log.debug('(%s) state_cleanup: removing user %s/%s who no longer shares a channel with us',
|
||||||
|
irc.name, source, irc.users[source].nick)
|
||||||
|
irc._remove_client(source)
|
||||||
|
|
||||||
|
def stats_cleanup_part(irc, source, command, args):
|
||||||
|
for channel in args['channels']:
|
||||||
|
_state_cleanup_core(irc, source, channel)
|
||||||
|
utils.add_hook(stats_cleanup_part, 'PART', priority=-100)
|
||||||
|
|
||||||
|
def stats_cleanup_kick(irc, source, command, args):
|
||||||
|
_state_cleanup_core(irc, args['target'], args['channel'])
|
||||||
|
utils.add_hook(stats_cleanup_kick, 'KICK', priority=-100)
|
||||||
|
@ -25,7 +25,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.protocol_caps = {'clear-channels-on-leave', 'slash-in-nicks', 'slash-in-hosts', 'underscore-in-hosts'}
|
self.protocol_caps = {'visible-state-only', 'slash-in-nicks', 'slash-in-hosts', 'underscore-in-hosts'}
|
||||||
|
|
||||||
self.has_eob = False
|
self.has_eob = False
|
||||||
|
|
||||||
@ -253,6 +253,13 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
|
|||||||
self.send('NICK :%s' % newnick)
|
self.send('NICK :%s' % newnick)
|
||||||
# No state update here: the IRCd will respond with a NICK acknowledgement if the change succeeds.
|
# No state update here: the IRCd will respond with a NICK acknowledgement if the change succeeds.
|
||||||
else:
|
else:
|
||||||
|
assert source, "No source given?"
|
||||||
|
# Check that the new nick exists and isn't the same client as the sender
|
||||||
|
# (for changing nick case)
|
||||||
|
nick_uid = self.nick_to_uid(newnick)
|
||||||
|
if nick_uid and nick_uid != source:
|
||||||
|
log.warning('(%s) Blocking attempt from virtual client %s to change nick to %s (nick in use)', self.name, source, newnick)
|
||||||
|
return
|
||||||
self.call_hooks([source, 'CLIENTBOT_NICK', {'newnick': newnick}])
|
self.call_hooks([source, 'CLIENTBOT_NICK', {'newnick': newnick}])
|
||||||
self.users[source].nick = newnick
|
self.users[source].nick = newnick
|
||||||
|
|
||||||
@ -355,20 +362,22 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
|
|||||||
Limited (internal) nick collision checking is done here to prevent Clientbot users from
|
Limited (internal) nick collision checking is done here to prevent Clientbot users from
|
||||||
being confused with virtual clients, and vice versa."""
|
being confused with virtual clients, and vice versa."""
|
||||||
self._check_puid_collision(nick)
|
self._check_puid_collision(nick)
|
||||||
|
|
||||||
idsource = self.nick_to_uid(nick)
|
idsource = self.nick_to_uid(nick)
|
||||||
is_internal = self.is_internal_client(idsource)
|
|
||||||
|
|
||||||
# If this sender isn't known or it is one of our virtual clients, spawn a new one.
|
if self.is_internal_client(idsource) and self.pseudoclient and idsource != self.pseudoclient.uid:
|
||||||
# This also takes care of any nick collisions caused by new, Clientbot users
|
# We got a message from a client with the same nick as an internal client.
|
||||||
# taking the same nick as one of our virtual clients, and will force the virtual client to lose.
|
# Fire a virtual nick collision to prevent mixing senders.
|
||||||
if (not idsource) or (is_internal and self.pseudoclient and idsource != self.pseudoclient.uid):
|
|
||||||
if idsource:
|
|
||||||
log.debug('(%s) Nick-colliding virtual client %s/%s', self.name, idsource, nick)
|
log.debug('(%s) Nick-colliding virtual client %s/%s', self.name, idsource, nick)
|
||||||
self.call_hooks([self.sid, 'CLIENTBOT_NICKCOLLIDE', {'target': idsource, 'parse_as': 'SAVE'}])
|
self.call_hooks([self.sid, 'SAVE', {'target': idsource}])
|
||||||
|
|
||||||
|
# Clear the UID for this nick and spawn a new client for the nick that was just freed.
|
||||||
|
idsource = None
|
||||||
|
|
||||||
|
if idsource is None:
|
||||||
|
# If this sender doesn't already exist, spawn a new client.
|
||||||
idsource = self.spawn_client(nick, ident or 'unknown', host or 'unknown',
|
idsource = self.spawn_client(nick, ident or 'unknown', host or 'unknown',
|
||||||
server=self.uplink, realname=FALLBACK_REALNAME).uid
|
server=self.uplink, realname=FALLBACK_REALNAME).uid
|
||||||
|
|
||||||
return idsource
|
return idsource
|
||||||
|
|
||||||
def parse_message_tags(self, data):
|
def parse_message_tags(self, data):
|
||||||
@ -907,11 +916,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
|
|||||||
|
|
||||||
if (not self.is_internal_client(source)) and not self.is_internal_server(source):
|
if (not self.is_internal_client(source)) and not self.is_internal_server(source):
|
||||||
# Don't repeat hooks if we're the kicker.
|
# Don't repeat hooks if we're the kicker.
|
||||||
self.call_hooks([source, 'KICK', {'channel': channel, 'target': target, 'text': reason}])
|
return {'channel': channel, 'target': target, 'text': reason}
|
||||||
|
|
||||||
# Delete channels that we were kicked from, for better state keeping.
|
|
||||||
if self.pseudoclient and target == self.pseudoclient.uid:
|
|
||||||
del self._channels[channel]
|
|
||||||
|
|
||||||
def handle_mode(self, source, command, args):
|
def handle_mode(self, source, command, args):
|
||||||
"""Handles MODE changes."""
|
"""Handles MODE changes."""
|
||||||
@ -975,21 +980,25 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
|
|||||||
def handle_nick(self, source, command, args):
|
def handle_nick(self, source, command, args):
|
||||||
"""Handles NICK changes."""
|
"""Handles NICK changes."""
|
||||||
# <- :GL|!~GL@127.0.0.1 NICK :GL_
|
# <- :GL|!~GL@127.0.0.1 NICK :GL_
|
||||||
|
newnick = args[0]
|
||||||
|
|
||||||
if not self.connected.is_set():
|
if not self.connected.is_set():
|
||||||
# We haven't properly logged on yet, so any initial NICK should be treated as a forced
|
# We haven't properly logged on yet, so any initial NICK should be treated as a forced
|
||||||
# nick change for us. For example, this clause is used to handle forced nick changes
|
# nick change for us. For example, this clause is used to handle forced nick changes
|
||||||
# sent by ZNC, when the login nick and the actual IRC nick of the bouncer differ.
|
# sent by ZNC, when the login nick and the actual IRC nick of the bouncer differ.
|
||||||
self.pseudoclient.nick = args[0]
|
self.pseudoclient.nick = newnick
|
||||||
log.debug('(%s) Pre-auth FNC: Changing our nick to %s', self.name, args[0])
|
log.debug('(%s) Pre-auth FNC: Changing our nick to %s', self.name, args[0])
|
||||||
return
|
return
|
||||||
elif source == self.pseudoclient.uid:
|
elif source == self.pseudoclient.uid:
|
||||||
self._nick_fails = 0 # Our last nick change succeeded.
|
self._nick_fails = 0 # Our last nick change succeeded.
|
||||||
|
|
||||||
oldnick = self.users[source].nick
|
oldnick = self.users[source].nick
|
||||||
self.users[source].nick = args[0]
|
|
||||||
|
|
||||||
return {'newnick': args[0], 'oldnick': oldnick}
|
# Check for any nick collisions with existing virtual clients.
|
||||||
|
self._check_nick_collision(newnick)
|
||||||
|
self.users[source].nick = newnick
|
||||||
|
|
||||||
|
return {'newnick': newnick, 'oldnick': oldnick}
|
||||||
|
|
||||||
def handle_part(self, source, command, args):
|
def handle_part(self, source, command, args):
|
||||||
"""
|
"""
|
||||||
@ -1006,12 +1015,7 @@ class ClientbotWrapperProtocol(IRCCommonProtocol):
|
|||||||
self._channels[channel].remove_user(source)
|
self._channels[channel].remove_user(source)
|
||||||
self.users[source].channels -= set(channels)
|
self.users[source].channels -= set(channels)
|
||||||
|
|
||||||
self.call_hooks([source, 'PART', {'channels': channels, 'text': reason}])
|
return {'channels': channels, 'text': reason}
|
||||||
|
|
||||||
# Clear channels that are empty, or that we're parting.
|
|
||||||
for channel in channels:
|
|
||||||
if (self.pseudoclient and source == self.pseudoclient.uid) or not self._channels[channel].users:
|
|
||||||
del self._channels[channel]
|
|
||||||
|
|
||||||
def handle_ping(self, source, command, args):
|
def handle_ping(self, source, command, args):
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user