3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-27 13:09:23 +01:00

bots, opercmds: handle cases where target nick is disambiguous

This commit is contained in:
James Lu 2019-06-16 10:45:05 -07:00
parent 242267a4a2
commit fc4a16eda1
2 changed files with 69 additions and 39 deletions

View File

@ -39,13 +39,16 @@ def quit(irc, source, args):
irc.error("Not enough arguments. Needs 1-2: nick, reason (optional).") irc.error("Not enough arguments. Needs 1-2: nick, reason (optional).")
return return
u = irc.nick_to_uid(nick) u = irc.nick_to_uid(nick, filterfunc=irc.is_internal_client)
if u is None:
irc.error("Unknown user %r" % nick)
return
if irc.pseudoclient.uid == u: if irc.pseudoclient.uid == u:
irc.error("Cannot quit the main PyLink client!") irc.error("Cannot quit the main PyLink client!")
return return
quitmsg = ' '.join(args[1:]) or 'Client Quit' quitmsg = ' '.join(args[1:]) or 'Client Quit'
if not irc.is_manipulatable_client(u): if not irc.is_manipulatable_client(u):
irc.error("Cannot force quit a protected PyLink services client.") irc.error("Cannot force quit a protected PyLink services client.")
@ -69,13 +72,13 @@ def joinclient(irc, source, args):
try: try:
# Check if the first argument is an existing PyLink client. If it is not, # Check if the first argument is an existing PyLink client. If it is not,
# then assume that the first argument was actually the channels being joined. # then assume that the first argument was actually the channels being joined.
u = irc.nick_to_uid(args[0]) u = irc.nick_to_uid(args[0], filterfunc=irc.is_internal_client)
if not irc.is_internal_client(u): # First argument isn't one of our clients if u is None: # First argument isn't one of our clients
raise IndexError raise IndexError
clist = args[1] clist = args[1]
except IndexError: # No nick was given; shift arguments one to the left. except IndexError: # No valid nick was given; shift arguments one to the left.
u = irc.pseudoclient.uid u = irc.pseudoclient.uid
try: try:
clist = args[0] clist = args[0]
@ -114,7 +117,7 @@ def joinclient(irc, source, args):
except KeyError: except KeyError:
modes = [] modes = []
# Call a join hook manually so other plugins like relay can understand it. # Signal the join to other plugins
irc.call_hooks([u, 'PYLINK_BOTSPLUGIN_JOIN', {'channel': real_channel, 'users': [u], irc.call_hooks([u, 'PYLINK_BOTSPLUGIN_JOIN', {'channel': real_channel, 'users': [u],
'modes': modes, 'parse_as': 'JOIN'}]) 'modes': modes, 'parse_as': 'JOIN'}])
irc.reply("Done.") irc.reply("Done.")
@ -138,7 +141,7 @@ def nick(irc, source, args):
except IndexError: except IndexError:
irc.error("Not enough arguments. Needs 1-2: nick (optional), newnick.") irc.error("Not enough arguments. Needs 1-2: nick (optional), newnick.")
return return
u = irc.nick_to_uid(nick) u = irc.nick_to_uid(nick, filterfunc=irc.is_internal_client)
if newnick in ('0', u): # Allow /nick 0 to work if newnick in ('0', u): # Allow /nick 0 to work
newnick = u newnick = u
@ -153,7 +156,7 @@ def nick(irc, source, args):
irc.nick(u, newnick) irc.nick(u, newnick)
irc.reply("Done.") irc.reply("Done.")
# Ditto above: manually send a NICK change hook payload to other plugins. # Signal the nick change to other plugins
irc.call_hooks([u, 'PYLINK_BOTSPLUGIN_NICK', {'newnick': newnick, 'oldnick': nick, 'parse_as': 'NICK'}]) irc.call_hooks([u, 'PYLINK_BOTSPLUGIN_NICK', {'newnick': newnick, 'oldnick': nick, 'parse_as': 'NICK'}])
@utils.add_cmd @utils.add_cmd
@ -171,8 +174,8 @@ def part(irc, source, args):
# First, check if the first argument is an existing PyLink client. If it is not, # First, check if the first argument is an existing PyLink client. If it is not,
# then assume that the first argument was actually the channels being parted. # then assume that the first argument was actually the channels being parted.
u = irc.nick_to_uid(nick) u = irc.nick_to_uid(nick, filterfunc=irc.is_internal_client)
if not irc.is_internal_client(u): # First argument isn't one of our clients if u is None: # First argument isn't one of our clients
raise IndexError raise IndexError
except IndexError: # No nick was given; shift arguments one to the left. except IndexError: # No nick was given; shift arguments one to the left.
@ -217,12 +220,11 @@ def msg(irc, source, args):
# First, check if the first argument is an existing PyLink client. If it is not, # First, check if the first argument is an existing PyLink client. If it is not,
# then assume that the first argument was actually the message TARGET. # then assume that the first argument was actually the message TARGET.
sourceuid = irc.nick_to_uid(msgsource) sourceuid = irc.nick_to_uid(msgsource, filterfunc=irc.is_internal_client)
if not irc.is_internal_client(sourceuid): # First argument isn't one of our clients
if sourceuid is None or not text: # First argument isn't one of our clients
raise IndexError raise IndexError
if not text:
raise IndexError
except IndexError: except IndexError:
try: try:
sourceuid = irc.pseudoclient.uid sourceuid = irc.pseudoclient.uid
@ -236,12 +238,26 @@ def msg(irc, source, args):
irc.error('No text given.') irc.error('No text given.')
return return
if not irc.is_channel(target): try:
# Convert nick of the message target to a UID, if the target isn't a channel int_u = int(target)
real_target = irc.nick_to_uid(target) except:
if real_target is None: # Unknown target user, if target isn't a valid channel name int_u = None
if int_u and int_u in irc.users:
real_target = int_u # Some protocols use numeric UIDs
elif target in irc.users:
real_target = target
elif not irc.is_channel(target):
# Convert nick of the message target to a UID, if the target isn't a channel or UID
potential_targets = irc.nick_to_uid(target, multi=True)
if not potential_targets: # Unknown target user, if target isn't a valid channel name
irc.error('Unknown user %r.' % target) irc.error('Unknown user %r.' % target)
return return
elif len(potential_targets) > 1:
irc.error('Multiple users with the nick %r found: please select the right UID: %s' % (target, str(potential_targets)))
return
else:
real_target = potential_targets[0]
else: else:
real_target = target real_target = target

View File

@ -333,6 +333,29 @@ def jupe(irc, source, args):
irc.reply("Done.") irc.reply("Done.")
def _try_find_target(irc, nick):
"""
Tries to find the target UID for the given nick, raising LookupError if it doesn't exist or is ambiguous.
"""
try:
int_u = int(nick)
except:
int_u = None
if int_u and int_u in irc.users:
return int_u # Some protocols use numeric UIDs
elif nick in irc.users:
return nick
potential_targets = irc.nick_to_uid(nick, multi=True)
if not potential_targets:
# Whatever we were told to kick doesn't exist!
raise LookupError("No such target %r." % nick)
elif len(potential_targets) > 1:
raise LookupError("Multiple users with the nick %r found: please select the right UID: %s" % (nick, str(potential_targets)))
else:
return potential_targets[0]
@utils.add_cmd @utils.add_cmd
def kick(irc, source, args): def kick(irc, source, args):
"""<channel> <user> [<reason>] """<channel> <user> [<reason>]
@ -347,16 +370,11 @@ def kick(irc, source, args):
irc.error("Not enough arguments. Needs 2-3: channel, target, reason (optional).") irc.error("Not enough arguments. Needs 2-3: channel, target, reason (optional).")
return return
targetu = irc.nick_to_uid(target)
if channel not in irc.channels: # KICK only works on channels that exist. if channel not in irc.channels: # KICK only works on channels that exist.
irc.error("Unknown channel %r." % channel) irc.error("Unknown channel %r." % channel)
return return
if not targetu: targetu = _try_find_target(irc, target)
# Whatever we were told to kick doesn't exist!
irc.error("No such target nick %r." % target)
return
sender = irc.pseudoclient.uid sender = irc.pseudoclient.uid
irc.kick(sender, channel, targetu, reason) irc.kick(sender, channel, targetu, reason)
@ -379,17 +397,15 @@ def kill(irc, source, args):
# Convert the source and target nicks to UIDs. # Convert the source and target nicks to UIDs.
sender = irc.pseudoclient.uid sender = irc.pseudoclient.uid
targetu = irc.nick_to_uid(target)
userdata = irc.users.get(targetu)
if targetu not in irc.users: targetu = _try_find_target(irc, target)
# Whatever we were told to kick doesn't exist!
irc.error("No such nick %r." % target) if irc.pseudoclient.uid == targetu:
return
elif irc.pseudoclient.uid == targetu:
irc.error("Cannot kill the main PyLink client!") irc.error("Cannot kill the main PyLink client!")
return return
userdata = irc.users.get(targetu)
# Deliver a more complete kill reason if our target is a non-PyLink client. # Deliver a more complete kill reason if our target is a non-PyLink client.
# We skip this for PyLink clients so that relayed kills don't get # We skip this for PyLink clients so that relayed kills don't get
# "Killed (abc (...))" tacked on both here and by the receiving IRCd. # "Killed (abc (...))" tacked on both here and by the receiving IRCd.
@ -473,23 +489,24 @@ def chghost(irc, source, args):
"""<user> <new host> """<user> <new host>
Changes the visible host of the target user.""" Changes the visible host of the target user."""
chgfield(irc, source, args, 'host') _chgfield(irc, source, args, 'host')
@utils.add_cmd @utils.add_cmd
def chgident(irc, source, args): def chgident(irc, source, args):
"""<user> <new ident> """<user> <new ident>
Changes the ident of the target user.""" Changes the ident of the target user."""
chgfield(irc, source, args, 'ident') _chgfield(irc, source, args, 'ident')
@utils.add_cmd @utils.add_cmd
def chgname(irc, source, args): def chgname(irc, source, args):
"""<user> <new name> """<user> <new name>
Changes the GECOS (realname) of the target user.""" Changes the GECOS (realname) of the target user."""
chgfield(irc, source, args, 'name', 'GECOS') _chgfield(irc, source, args, 'name', 'GECOS')
def chgfield(irc, source, args, human_field, internal_field=None): def _chgfield(irc, source, args, human_field, internal_field=None):
"""Helper function for chghost/chgident/chgname."""
permissions.check_permissions(irc, source, ['opercmds.chg' + human_field]) permissions.check_permissions(irc, source, ['opercmds.chg' + human_field])
try: try:
target = args[0] target = args[0]
@ -499,10 +516,7 @@ def chgfield(irc, source, args, human_field, internal_field=None):
return return
# Find the user # Find the user
targetu = irc.nick_to_uid(target) targetu = _try_find_target(irc, target)
if targetu not in irc.users:
irc.error("No such nick %r." % target)
return
internal_field = internal_field or human_field.upper() internal_field = internal_field or human_field.upper()
irc.update_client(targetu, internal_field, new) irc.update_client(targetu, internal_field, new)