mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-27 21:19:31 +01:00
Merge branch 'master' into wip/unrealircd
This commit is contained in:
commit
cedcb9b11a
@ -178,11 +178,13 @@ class Irc():
|
||||
return
|
||||
|
||||
def callCommand(self, source, text):
|
||||
"""Calls a PyLink bot command."""
|
||||
cmd_args = text.strip().split(' ')
|
||||
cmd = cmd_args[0].lower()
|
||||
cmd_args = cmd_args[1:]
|
||||
if cmd not in world.commands:
|
||||
self.msg(self.called_by or source, 'Error: Unknown command %r.' % cmd)
|
||||
log.info('(%s) Received unknown command %r from %s', self.name, cmd, utils.getHostmask(self, source))
|
||||
return
|
||||
log.info('(%s) Calling command %r for %s', self.name, cmd, utils.getHostmask(self, source))
|
||||
for func in world.commands[cmd]:
|
||||
@ -206,6 +208,10 @@ class Irc():
|
||||
cmd = 'PYLINK_SELF_PRIVMSG'
|
||||
self.callHooks([source, cmd, {'target': target, 'text': text}])
|
||||
|
||||
def reply(self, text, notice=False, source=None):
|
||||
"""Replies to the last caller in context."""
|
||||
self.msg(self.called_by, text, notice=notice, source=source)
|
||||
|
||||
def _disconnect(self):
|
||||
log.debug('(%s) Canceling pingTimer at %s due to _disconnect() call', self.name, time.time())
|
||||
self.connected.clear()
|
||||
|
160
coreplugin.py
160
coreplugin.py
@ -1,4 +1,7 @@
|
||||
## coreplugin.py - Core PyLink plugin
|
||||
# coreplugin.py - Implements core PyLink functions as a plugin
|
||||
|
||||
import gc
|
||||
import sys
|
||||
|
||||
import utils
|
||||
from log import log
|
||||
@ -107,3 +110,158 @@ def handle_mode(irc, source, command, args):
|
||||
if ('-o', None) in modes and (target == irc.pseudoclient.uid or not utils.isManipulatableClient(irc, target)):
|
||||
irc.proto.modeServer(irc.sid, target, {('+o', None)})
|
||||
utils.add_hook(handle_mode, 'MODE')
|
||||
|
||||
def handle_operup(irc, source, command, args):
|
||||
"""Logs successful oper-ups on networks."""
|
||||
log.info("(%s) Successful oper-up (opertype %r) from %s", irc.name, args.get('text'), utils.getHostmask(irc, source))
|
||||
utils.add_hook(handle_operup, 'PYLINK_CLIENT_OPERED')
|
||||
|
||||
# Essential, core commands go here so that the "commands" plugin with less-important,
|
||||
# but still generic functions can be reloaded.
|
||||
|
||||
@utils.add_cmd
|
||||
def identify(irc, source, args):
|
||||
"""<username> <password>
|
||||
|
||||
Logs in to PyLink using the configured administrator account."""
|
||||
if utils.isChannel(irc.called_by):
|
||||
irc.reply('Error: This command must be sent in private. '
|
||||
'(Would you really type a password inside a channel?)')
|
||||
return
|
||||
try:
|
||||
username, password = args[0], args[1]
|
||||
except IndexError:
|
||||
irc.msg(source, 'Error: Not enough arguments.')
|
||||
return
|
||||
# Usernames are case-insensitive, passwords are NOT.
|
||||
if username.lower() == irc.conf['login']['user'].lower() and password == irc.conf['login']['password']:
|
||||
realuser = irc.conf['login']['user']
|
||||
irc.users[source].identified = realuser
|
||||
irc.msg(source, 'Successfully logged in as %s.' % realuser)
|
||||
log.info("(%s) Successful login to %r by %s",
|
||||
irc.name, username, utils.getHostmask(irc, source))
|
||||
else:
|
||||
irc.msg(source, 'Error: Incorrect credentials.')
|
||||
u = irc.users[source]
|
||||
log.warning("(%s) Failed login to %r from %s",
|
||||
irc.name, username, utils.getHostmask(irc, source))
|
||||
|
||||
@utils.add_cmd
|
||||
def shutdown(irc, source, args):
|
||||
"""takes no arguments.
|
||||
|
||||
Exits PyLink by disconnecting all networks."""
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
u = irc.users[source]
|
||||
log.info('(%s) SHUTDOWN requested by "%s!%s@%s", exiting...', irc.name, u.nick,
|
||||
u.ident, u.host)
|
||||
for ircobj in world.networkobjects.values():
|
||||
# Disable auto-connect first by setting the time to negative.
|
||||
ircobj.serverdata['autoconnect'] = -1
|
||||
ircobj.aborted.set()
|
||||
|
||||
def load(irc, source, args):
|
||||
"""<plugin name>.
|
||||
|
||||
Loads a plugin from the plugin folder."""
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
try:
|
||||
name = args[0]
|
||||
except IndexError:
|
||||
irc.reply("Error: Not enough arguments. Needs 1: plugin name.")
|
||||
return
|
||||
if name in world.plugins:
|
||||
irc.reply("Error: %r is already loaded." % name)
|
||||
return
|
||||
log.info('(%s) Loading plugin %r for %s', irc.name, name, utils.getHostmask(irc, source))
|
||||
try:
|
||||
world.plugins[name] = pl = utils.loadModuleFromFolder(name, world.plugins_folder)
|
||||
except ImportError as e:
|
||||
if str(e) == ('No module named %r' % name):
|
||||
log.exception('Failed to load plugin %r: The plugin could not be found.', name)
|
||||
else:
|
||||
log.exception('Failed to load plugin %r: ImportError.', name)
|
||||
raise
|
||||
else:
|
||||
if hasattr(pl, 'main'):
|
||||
log.debug('Calling main() function of plugin %r', pl)
|
||||
pl.main(irc)
|
||||
irc.reply("Loaded plugin %r." % name)
|
||||
utils.add_cmd(load)
|
||||
|
||||
def unload(irc, source, args):
|
||||
"""<plugin name>.
|
||||
|
||||
Unloads a currently loaded plugin."""
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
try:
|
||||
name = args[0]
|
||||
except IndexError:
|
||||
irc.reply("Error: Not enough arguments. Needs 1: plugin name.")
|
||||
return
|
||||
if name in world.plugins:
|
||||
log.info('(%s) Unloading plugin %r for %s', irc.name, name, utils.getHostmask(irc, source))
|
||||
pl = world.plugins[name]
|
||||
log.debug('sys.getrefcount of plugin %s is %s', pl, sys.getrefcount(pl))
|
||||
# Remove any command functions set by the plugin.
|
||||
for cmdname, cmdfuncs in world.commands.copy().items():
|
||||
log.debug('cmdname=%s, cmdfuncs=%s', cmdname, cmdfuncs)
|
||||
for cmdfunc in cmdfuncs:
|
||||
log.debug('__module__ of cmdfunc %s is %s', cmdfunc, cmdfunc.__module__)
|
||||
if cmdfunc.__module__ == name:
|
||||
log.debug('Removing %s from world.commands[%s]', cmdfunc, cmdname)
|
||||
world.commands[cmdname].remove(cmdfunc)
|
||||
# If the cmdfunc list is empty, remove it.
|
||||
if not cmdfuncs:
|
||||
log.debug("Removing world.commands[%s] (it's empty now)", cmdname)
|
||||
del world.commands[cmdname]
|
||||
|
||||
# Remove any command hooks set by the plugin.
|
||||
for hookname, hookfuncs in world.hooks.copy().items():
|
||||
for hookfunc in hookfuncs:
|
||||
if hookfunc.__module__ == name:
|
||||
world.hooks[hookname].remove(hookfunc)
|
||||
# If the hookfuncs list is empty, remove it.
|
||||
if not hookfuncs:
|
||||
del world.hooks[hookname]
|
||||
|
||||
# Remove whois handlers too.
|
||||
for f in world.whois_handlers:
|
||||
if f.__module__ == name:
|
||||
world.whois_handlers.remove(f)
|
||||
|
||||
# Call the die() function in the plugin, if present.
|
||||
if hasattr(pl, 'die'):
|
||||
try:
|
||||
pl.die(irc)
|
||||
except: # But don't allow it to crash the server.
|
||||
log.exception('(%s) Error occurred in die() of plugin %s, skipping...', irc.name, pl)
|
||||
|
||||
# Delete it from memory (hopefully).
|
||||
del world.plugins[name]
|
||||
if name in sys.modules:
|
||||
del sys.modules[name]
|
||||
if name in globals():
|
||||
del globals()[name]
|
||||
|
||||
# Garbage collect.
|
||||
gc.collect()
|
||||
|
||||
irc.reply("Unloaded plugin %r." % name)
|
||||
return True # We succeeded, make it clear (this status is used by reload() below)
|
||||
else:
|
||||
irc.reply("Unknown plugin %r." % name)
|
||||
utils.add_cmd(unload)
|
||||
|
||||
@utils.add_cmd
|
||||
def reload(irc, source, args):
|
||||
"""<plugin name>.
|
||||
|
||||
Loads a plugin from the plugin folder."""
|
||||
try:
|
||||
name = args[0]
|
||||
except IndexError:
|
||||
irc.reply("Error: Not enough arguments. Needs 1: plugin name.")
|
||||
return
|
||||
if unload(irc, source, args):
|
||||
load(irc, source, args)
|
||||
|
@ -20,7 +20,7 @@ def spawnclient(irc, source, args):
|
||||
try:
|
||||
nick, ident, host = args[:3]
|
||||
except ValueError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 3: nick, user, host.")
|
||||
irc.reply("Error: Not enough arguments. Needs 3: nick, user, host.")
|
||||
return
|
||||
irc.proto.spawnClient(nick, ident, host, manipulatable=True)
|
||||
|
||||
@ -33,15 +33,15 @@ def quit(irc, source, args):
|
||||
try:
|
||||
nick = args[0]
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1-2: nick, reason (optional).")
|
||||
irc.reply("Error: Not enough arguments. Needs 1-2: nick, reason (optional).")
|
||||
return
|
||||
if irc.pseudoclient.uid == utils.nickToUid(irc, nick):
|
||||
irc.msg(irc.called_by, "Error: Cannot quit the main PyLink PseudoClient!")
|
||||
irc.reply("Error: Cannot quit the main PyLink PseudoClient!")
|
||||
return
|
||||
u = utils.nickToUid(irc, nick)
|
||||
quitmsg = ' '.join(args[1:]) or 'Client Quit'
|
||||
if not utils.isManipulatableClient(irc, u):
|
||||
irc.msg(irc.called_by, "Error: Cannot force quit a protected PyLink services client.")
|
||||
irc.reply("Error: Cannot force quit a protected PyLink services client.")
|
||||
return
|
||||
irc.proto.quitClient(u, quitmsg)
|
||||
irc.callHooks([u, 'PYLINK_BOTSPLUGIN_QUIT', {'text': quitmsg, 'parse_as': 'QUIT'}])
|
||||
@ -57,15 +57,15 @@ def joinclient(irc, source, args):
|
||||
if not clist:
|
||||
raise IndexError
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 2: nick, comma separated list of channels.")
|
||||
irc.reply("Error: Not enough arguments. Needs 2: nick, comma separated list of channels.")
|
||||
return
|
||||
u = utils.nickToUid(irc, nick)
|
||||
if not utils.isManipulatableClient(irc, u):
|
||||
irc.msg(irc.called_by, "Error: Cannot force join a protected PyLink services client.")
|
||||
irc.reply("Error: Cannot force join a protected PyLink services client.")
|
||||
return
|
||||
for channel in clist:
|
||||
if not utils.isChannel(channel):
|
||||
irc.msg(irc.called_by, "Error: Invalid channel name %r." % channel)
|
||||
irc.reply("Error: Invalid channel name %r." % channel)
|
||||
return
|
||||
irc.proto.joinClient(u, channel)
|
||||
irc.callHooks([u, 'PYLINK_BOTSPLUGIN_JOIN', {'channel': channel, 'users': [u],
|
||||
@ -83,16 +83,16 @@ def nick(irc, source, args):
|
||||
nick = args[0]
|
||||
newnick = args[1]
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 2: nick, newnick.")
|
||||
irc.reply("Error: Not enough arguments. Needs 2: nick, newnick.")
|
||||
return
|
||||
u = utils.nickToUid(irc, nick)
|
||||
if newnick in ('0', u):
|
||||
newnick = u
|
||||
elif not utils.isNick(newnick):
|
||||
irc.msg(irc.called_by, 'Error: Invalid nickname %r.' % newnick)
|
||||
irc.reply('Error: Invalid nickname %r.' % newnick)
|
||||
return
|
||||
elif not utils.isManipulatableClient(irc, u):
|
||||
irc.msg(irc.called_by, "Error: Cannot force nick changes for a protected PyLink services client.")
|
||||
irc.reply("Error: Cannot force nick changes for a protected PyLink services client.")
|
||||
return
|
||||
irc.proto.nickClient(u, newnick)
|
||||
irc.callHooks([u, 'PYLINK_BOTSPLUGIN_NICK', {'newnick': newnick, 'oldnick': nick, 'parse_as': 'NICK'}])
|
||||
@ -108,15 +108,15 @@ def part(irc, source, args):
|
||||
clist = args[1].split(',')
|
||||
reason = ' '.join(args[2:])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 2: nick, comma separated list of channels.")
|
||||
irc.reply("Error: Not enough arguments. Needs 2: nick, comma separated list of channels.")
|
||||
return
|
||||
u = utils.nickToUid(irc, nick)
|
||||
if not utils.isManipulatableClient(irc, u):
|
||||
irc.msg(irc.called_by, "Error: Cannot force part a protected PyLink services client.")
|
||||
irc.reply("Error: Cannot force part a protected PyLink services client.")
|
||||
return
|
||||
for channel in clist:
|
||||
if not utils.isChannel(channel):
|
||||
irc.msg(irc.called_by, "Error: Invalid channel name %r." % channel)
|
||||
irc.reply("Error: Invalid channel name %r." % channel)
|
||||
return
|
||||
irc.proto.partClient(u, channel, reason)
|
||||
irc.callHooks([u, 'PYLINK_BOTSPLUGIN_PART', {'channels': clist, 'text': reason, 'parse_as': 'PART'}])
|
||||
@ -133,12 +133,12 @@ def kick(irc, source, args):
|
||||
target = args[2]
|
||||
reason = ' '.join(args[3:])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 3-4: source nick, channel, target, reason (optional).")
|
||||
irc.reply("Error: Not enough arguments. Needs 3-4: source nick, channel, target, reason (optional).")
|
||||
return
|
||||
u = utils.nickToUid(irc, nick) or nick
|
||||
targetu = utils.nickToUid(irc, target)
|
||||
if not utils.isChannel(channel):
|
||||
irc.msg(irc.called_by, "Error: Invalid channel name %r." % channel)
|
||||
irc.reply("Error: Invalid channel name %r." % channel)
|
||||
return
|
||||
if utils.isInternalServer(irc, u):
|
||||
irc.proto.kickServer(u, channel, targetu, reason)
|
||||
@ -155,20 +155,20 @@ def mode(irc, source, args):
|
||||
try:
|
||||
modesource, target, modes = args[0], args[1], args[2:]
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, 'Error: Not enough arguments. Needs 3: source nick, target, modes to set.')
|
||||
irc.reply('Error: Not enough arguments. Needs 3: source nick, target, modes to set.')
|
||||
return
|
||||
target = utils.nickToUid(irc, target) or target
|
||||
extclient = target in irc.users and not utils.isInternalClient(irc, target)
|
||||
parsedmodes = utils.parseModes(irc, target, modes)
|
||||
ischannel = target in irc.channels
|
||||
if not (target in irc.users or ischannel):
|
||||
irc.msg(irc.called_by, "Error: Invalid channel or nick %r." % target)
|
||||
irc.reply("Error: Invalid channel or nick %r." % target)
|
||||
return
|
||||
elif not parsedmodes:
|
||||
irc.msg(irc.called_by, "Error: No valid modes were given.")
|
||||
irc.reply("Error: No valid modes were given.")
|
||||
return
|
||||
elif not (ischannel or utils.isManipulatableClient(irc, target)):
|
||||
irc.msg(irc.called_by, "Error: Can only set modes on channels or non-protected PyLink clients.")
|
||||
irc.reply("Error: Can only set modes on channels or non-protected PyLink clients.")
|
||||
return
|
||||
if utils.isInternalServer(irc, modesource):
|
||||
# Setting modes from a server.
|
||||
@ -189,21 +189,21 @@ def msg(irc, source, args):
|
||||
try:
|
||||
msgsource, target, text = args[0], args[1], ' '.join(args[2:])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, 'Error: Not enough arguments. Needs 3: source nick, target, text.')
|
||||
irc.reply('Error: Not enough arguments. Needs 3: source nick, target, text.')
|
||||
return
|
||||
sourceuid = utils.nickToUid(irc, msgsource)
|
||||
if not sourceuid:
|
||||
irc.msg(irc.called_by, 'Error: Unknown user %r.' % msgsource)
|
||||
irc.reply('Error: Unknown user %r.' % msgsource)
|
||||
return
|
||||
if not utils.isChannel(target):
|
||||
real_target = utils.nickToUid(irc, target)
|
||||
if real_target is None:
|
||||
irc.msg(irc.called_by, 'Error: Unknown user %r.' % target)
|
||||
irc.reply('Error: Unknown user %r.' % target)
|
||||
return
|
||||
else:
|
||||
real_target = target
|
||||
if not text:
|
||||
irc.msg(irc.called_by, 'Error: No text given.')
|
||||
irc.reply('Error: No text given.')
|
||||
return
|
||||
irc.proto.messageClient(sourceuid, real_target, text)
|
||||
irc.callHooks([sourceuid, 'PYLINK_BOTSPLUGIN_MSG', {'target': real_target, 'text': text, 'parse_as': 'PRIVMSG'}])
|
||||
|
@ -2,8 +2,6 @@
|
||||
import sys
|
||||
import os
|
||||
from time import ctime
|
||||
import itertools
|
||||
import gc
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
import utils
|
||||
@ -19,36 +17,10 @@ def status(irc, source, args):
|
||||
Returns your current PyLink login status."""
|
||||
identified = irc.users[source].identified
|
||||
if identified:
|
||||
irc.msg(irc.called_by, 'You are identified as \x02%s\x02.' % identified)
|
||||
irc.reply('You are identified as \x02%s\x02.' % identified)
|
||||
else:
|
||||
irc.msg(irc.called_by, 'You are not identified as anyone.')
|
||||
irc.msg(irc.called_by, 'Operator access: \x02%s\x02' % bool(utils.isOper(irc, source)))
|
||||
|
||||
@utils.add_cmd
|
||||
def identify(irc, source, args):
|
||||
"""<username> <password>
|
||||
|
||||
Logs in to PyLink using the configured administrator account."""
|
||||
if utils.isChannel(irc.called_by):
|
||||
irc.msg(irc.called_by, 'Error: This command must be sent in private. '
|
||||
'(Would you really type a password inside a public channel?)')
|
||||
try:
|
||||
username, password = args[0], args[1]
|
||||
except IndexError:
|
||||
irc.msg(source, 'Error: Not enough arguments.')
|
||||
return
|
||||
# Usernames are case-insensitive, passwords are NOT.
|
||||
if username.lower() == irc.conf['login']['user'].lower() and password == irc.conf['login']['password']:
|
||||
realuser = irc.conf['login']['user']
|
||||
irc.users[source].identified = realuser
|
||||
irc.msg(source, 'Successfully logged in as %s.' % realuser)
|
||||
log.info("(%s) Successful login to %r by %s.",
|
||||
irc.name, username, utils.getHostmask(irc, source))
|
||||
else:
|
||||
irc.msg(source, 'Error: Incorrect credentials.')
|
||||
u = irc.users[source]
|
||||
log.warning("(%s) Failed login to %r from %s.",
|
||||
irc.name, username, utils.getHostmask(irc, source))
|
||||
irc.reply('You are not identified as anyone.')
|
||||
irc.reply('Operator access: \x02%s\x02' % bool(utils.isOper(irc, source)))
|
||||
|
||||
def listcommands(irc, source, args):
|
||||
"""takes no arguments.
|
||||
@ -60,8 +32,8 @@ def listcommands(irc, source, args):
|
||||
nfuncs = len(world.commands[cmd])
|
||||
if nfuncs > 1:
|
||||
cmds[idx] = '%s(x%s)' % (cmd, nfuncs)
|
||||
irc.msg(irc.called_by, 'Available commands include: %s' % ', '.join(cmds))
|
||||
irc.msg(irc.called_by, 'To see help on a specific command, type \x02help <command>\x02.')
|
||||
irc.reply('Available commands include: %s' % ', '.join(cmds))
|
||||
irc.reply('To see help on a specific command, type \x02help <command>\x02.')
|
||||
utils.add_cmd(listcommands, 'list')
|
||||
|
||||
@utils.add_cmd
|
||||
@ -80,7 +52,7 @@ def help(irc, source, args):
|
||||
else:
|
||||
funcs = world.commands[command]
|
||||
if len(funcs) > 1:
|
||||
irc.msg(irc.called_by, 'The following \x02%s\x02 plugins bind to the \x02%s\x02 command: %s'
|
||||
irc.reply('The following \x02%s\x02 plugins bind to the \x02%s\x02 command: %s'
|
||||
% (len(funcs), command, ', '.join([func.__module__ for func in funcs])))
|
||||
for func in funcs:
|
||||
doc = func.__doc__
|
||||
@ -91,7 +63,7 @@ def help(irc, source, args):
|
||||
# arguments the command takes.
|
||||
lines[0] = '\x02%s %s\x02 (plugin: %r)' % (command, lines[0], mod)
|
||||
for line in lines:
|
||||
irc.msg(irc.called_by, line.strip())
|
||||
irc.reply(line.strip())
|
||||
else:
|
||||
irc.msg(source, "Error: Command %r (from plugin %r) "
|
||||
"doesn't offer any help." % (command, mod))
|
||||
@ -105,14 +77,14 @@ def showuser(irc, source, args):
|
||||
try:
|
||||
target = args[0]
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1: nick.")
|
||||
irc.reply("Error: Not enough arguments. Needs 1: nick.")
|
||||
return
|
||||
u = utils.nickToUid(irc, target) or target
|
||||
# Only show private info if the person is calling 'showuser' on themselves,
|
||||
# or is an oper.
|
||||
verbose = utils.isOper(irc, source) or u == source
|
||||
if u not in irc.users:
|
||||
irc.msg(irc.called_by, 'Error: Unknown user %r.' % target)
|
||||
irc.reply('Error: Unknown user %r.' % target)
|
||||
return
|
||||
|
||||
f = lambda s: irc.msg(source, s)
|
||||
@ -140,10 +112,10 @@ def showchan(irc, source, args):
|
||||
try:
|
||||
channel = utils.toLower(irc, args[0])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1: channel.")
|
||||
irc.reply("Error: Not enough arguments. Needs 1: channel.")
|
||||
return
|
||||
if channel not in irc.channels:
|
||||
irc.msg(irc.called_by, 'Error: Unknown channel %r.' % channel)
|
||||
irc.reply('Error: Unknown channel %r.' % channel)
|
||||
return
|
||||
|
||||
f = lambda s: irc.msg(source, s)
|
||||
@ -178,141 +150,20 @@ def showchan(irc, source, args):
|
||||
f('\x02User list\x02: %s' % ' '.join(nicklist[:20]))
|
||||
nicklist = nicklist[20:]
|
||||
|
||||
@utils.add_cmd
|
||||
def shutdown(irc, source, args):
|
||||
"""takes no arguments.
|
||||
|
||||
Exits PyLink by disconnecting all networks."""
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
u = irc.users[source]
|
||||
log.info('(%s) SHUTDOWN requested by "%s!%s@%s", exiting...', irc.name, u.nick,
|
||||
u.ident, u.host)
|
||||
for ircobj in world.networkobjects.values():
|
||||
# Disable auto-connect first by setting the time to negative.
|
||||
ircobj.serverdata['autoconnect'] = -1
|
||||
ircobj.aborted.set()
|
||||
|
||||
@utils.add_cmd
|
||||
def version(irc, source, args):
|
||||
"""takes no arguments.
|
||||
|
||||
Returns the version of the currently running PyLink instance."""
|
||||
irc.msg(irc.called_by, "PyLink version \x02%s\x02, released under the Mozilla Public License version 2.0." % world.version)
|
||||
irc.msg(irc.called_by, "The source of this program is available at \x02%s\x02." % world.source)
|
||||
irc.reply("PyLink version \x02%s\x02, released under the Mozilla Public License version 2.0." % world.version)
|
||||
irc.reply("The source of this program is available at \x02%s\x02." % world.source)
|
||||
|
||||
@utils.add_cmd
|
||||
def echo(irc, source, args):
|
||||
"""<text>
|
||||
|
||||
Echoes the text given."""
|
||||
irc.msg(irc.called_by, ' '.join(args))
|
||||
|
||||
def load(irc, source, args):
|
||||
"""<plugin name>.
|
||||
|
||||
Loads a plugin from the plugin folder."""
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
try:
|
||||
name = args[0]
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1: plugin name.")
|
||||
return
|
||||
if name in world.plugins:
|
||||
irc.msg(irc.called_by, "Error: %r is already loaded." % name)
|
||||
return
|
||||
try:
|
||||
world.plugins[name] = pl = utils.loadModuleFromFolder(name, world.plugins_folder)
|
||||
except ImportError as e:
|
||||
if str(e) == ('No module named %r' % name):
|
||||
log.exception('Failed to load plugin %r: The plugin could not be found.', name)
|
||||
else:
|
||||
log.exception('Failed to load plugin %r: ImportError.', name)
|
||||
raise
|
||||
else:
|
||||
if hasattr(pl, 'main'):
|
||||
log.debug('Calling main() function of plugin %r', pl)
|
||||
pl.main(irc)
|
||||
irc.msg(irc.called_by, "Loaded plugin %r." % name)
|
||||
utils.add_cmd(load)
|
||||
|
||||
def unload(irc, source, args):
|
||||
"""<plugin name>.
|
||||
|
||||
Unloads a currently loaded plugin."""
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
try:
|
||||
name = args[0]
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1: plugin name.")
|
||||
return
|
||||
if name == 'commands':
|
||||
irc.msg(irc.called_by, "Error: Cannot unload the commands plugin!")
|
||||
return
|
||||
elif name in world.plugins:
|
||||
pl = world.plugins[name]
|
||||
log.debug('sys.getrefcount of plugin %s is %s', pl, sys.getrefcount(pl))
|
||||
# Remove any command functions set by the plugin.
|
||||
for cmdname, cmdfuncs in world.commands.copy().items():
|
||||
log.debug('cmdname=%s, cmdfuncs=%s', cmdname, cmdfuncs)
|
||||
for cmdfunc in cmdfuncs:
|
||||
log.debug('__module__ of cmdfunc %s is %s', cmdfunc, cmdfunc.__module__)
|
||||
if cmdfunc.__module__ == name:
|
||||
log.debug('Removing %s from world.commands[%s]', cmdfunc, cmdname)
|
||||
world.commands[cmdname].remove(cmdfunc)
|
||||
# If the cmdfunc list is empty, remove it.
|
||||
if not cmdfuncs:
|
||||
log.debug("Removing world.commands[%s] (it's empty now)", cmdname)
|
||||
del world.commands[cmdname]
|
||||
|
||||
# Remove any command hooks set by the plugin.
|
||||
for hookname, hookfuncs in world.hooks.copy().items():
|
||||
for hookfunc in hookfuncs:
|
||||
if hookfunc.__module__ == name:
|
||||
world.hooks[hookname].remove(hookfunc)
|
||||
# If the hookfuncs list is empty, remove it.
|
||||
if not hookfuncs:
|
||||
del world.hooks[hookname]
|
||||
|
||||
# Remove whois handlers too.
|
||||
for f in world.whois_handlers:
|
||||
if f.__module__ == name:
|
||||
world.whois_handlers.remove(f)
|
||||
|
||||
# Call the die() function in the plugin, if present.
|
||||
if hasattr(pl, 'die'):
|
||||
try:
|
||||
pl.die(irc)
|
||||
except: # But don't allow it to crash the server.
|
||||
log.exception('(%s) Error occurred in die() of plugin %s, skipping...', irc.name, pl)
|
||||
|
||||
# Delete it from memory (hopefully).
|
||||
del world.plugins[name]
|
||||
if name in sys.modules:
|
||||
del sys.modules[name]
|
||||
if name in globals():
|
||||
del globals()[name]
|
||||
|
||||
# Garbage collect.
|
||||
gc.collect()
|
||||
|
||||
irc.msg(irc.called_by, "Unloaded plugin %r." % name)
|
||||
return True # We succeeded, make it clear (this status is used by reload() below)
|
||||
else:
|
||||
irc.msg(irc.called_by, "Unknown plugin %r." % name)
|
||||
utils.add_cmd(unload)
|
||||
|
||||
@utils.add_cmd
|
||||
def reload(irc, source, args):
|
||||
"""<plugin name>.
|
||||
|
||||
Loads a plugin from the plugin folder."""
|
||||
try:
|
||||
name = args[0]
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1: plugin name.")
|
||||
return
|
||||
if unload(irc, source, args):
|
||||
load(irc, source, args)
|
||||
irc.reply(' '.join(args))
|
||||
|
||||
@utils.add_cmd
|
||||
def rehash(irc, source, args):
|
||||
@ -327,7 +178,7 @@ def rehash(irc, source, args):
|
||||
new_conf = conf.validateConf(conf.loadConf(fname))
|
||||
except Exception as e: # Something went wrong, abort.
|
||||
log.exception("Error REHASH'ing config: ")
|
||||
irc.msg(irc.called_by, "Error loading configuration file: %s: %s", type(e).__name__, e)
|
||||
irc.reply("Error loading configuration file: %s: %s", type(e).__name__, e)
|
||||
return
|
||||
conf.conf = new_conf
|
||||
for network, ircobj in world.networkobjects.copy().items():
|
||||
@ -347,4 +198,25 @@ def rehash(irc, source, args):
|
||||
if network not in world.networkobjects:
|
||||
proto = utils.getProtoModule(sdata['protocol'])
|
||||
world.networkobjects[network] = classes.Irc(network, proto, new_conf)
|
||||
irc.msg(irc.called_by, "Done.")
|
||||
irc.reply("Done.")
|
||||
|
||||
loglevels = {'DEBUG': 10, 'INFO': 20, 'WARNING': 30, 'ERROR': 40, 'CRITICAL': 50}
|
||||
@utils.add_cmd
|
||||
def loglevel(irc, source, args):
|
||||
"""<level>
|
||||
|
||||
Sets the log level to the given <level>. <level> must be either DEBUG, INFO, WARNING, ERROR, or CRITICAL.
|
||||
If no log level is given, shows the current one."""
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
try:
|
||||
level = args[0].upper()
|
||||
try:
|
||||
loglevel = loglevels[level]
|
||||
except KeyError:
|
||||
irc.reply('Error: Unknown log level "%s".' % level)
|
||||
return
|
||||
else:
|
||||
log.setLevel(loglevel)
|
||||
irc.reply("Done.")
|
||||
except IndexError:
|
||||
irc.reply(log.getEffectiveLevel())
|
||||
|
6
plugins/exec.py
Executable file → Normal file
6
plugins/exec.py
Executable file → Normal file
@ -17,7 +17,7 @@ def _exec(irc, source, args):
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
args = ' '.join(args)
|
||||
if not args.strip():
|
||||
irc.msg(irc.called_by, 'No code entered!')
|
||||
irc.reply('No code entered!')
|
||||
return
|
||||
log.info('(%s) Executing %r for %s', irc.name, args, utils.getHostmask(irc, source))
|
||||
exec(args, globals(), locals())
|
||||
@ -31,8 +31,8 @@ def _eval(irc, source, args):
|
||||
utils.checkAuthenticated(irc, source, allowOper=False)
|
||||
args = ' '.join(args)
|
||||
if not args.strip():
|
||||
irc.msg(irc.called_by, 'No code entered!')
|
||||
irc.reply('No code entered!')
|
||||
return
|
||||
log.info('(%s) Evaluating %r for %s', irc.name, args, utils.getHostmask(irc, source))
|
||||
irc.msg(irc.called_by, eval(args))
|
||||
irc.reply(eval(args))
|
||||
utils.add_cmd(_eval, 'eval')
|
||||
|
0
plugins/fantasy.py
Executable file → Normal file
0
plugins/fantasy.py
Executable file → Normal file
@ -22,12 +22,12 @@ def disconnect(irc, source, args):
|
||||
netname = args[0]
|
||||
network = world.networkobjects[netname]
|
||||
except IndexError: # No argument given.
|
||||
irc.msg(irc.called_by, 'Error: Not enough arguments (needs 1: network name (case sensitive)).')
|
||||
irc.reply('Error: Not enough arguments (needs 1: network name (case sensitive)).')
|
||||
return
|
||||
except KeyError: # Unknown network.
|
||||
irc.msg(irc.called_by, 'Error: No such network "%s" (case sensitive).' % netname)
|
||||
irc.reply('Error: No such network "%s" (case sensitive).' % netname)
|
||||
return
|
||||
irc.msg(irc.called_by, "Done.")
|
||||
irc.reply("Done.")
|
||||
# Abort the connection! Simple as that.
|
||||
network.aborted.set()
|
||||
|
||||
@ -41,18 +41,18 @@ def connect(irc, source, args):
|
||||
netname = args[0]
|
||||
network = world.networkobjects[netname]
|
||||
except IndexError: # No argument given.
|
||||
irc.msg(irc.called_by, 'Error: Not enough arguments (needs 1: network name (case sensitive)).')
|
||||
irc.reply('Error: Not enough arguments (needs 1: network name (case sensitive)).')
|
||||
return
|
||||
except KeyError: # Unknown network.
|
||||
irc.msg(irc.called_by, 'Error: No such network "%s" (case sensitive).' % netname)
|
||||
irc.reply('Error: No such network "%s" (case sensitive).' % netname)
|
||||
return
|
||||
if network.connection_thread.is_alive():
|
||||
irc.msg(irc.called_by, 'Error: Network "%s" seems to be already connected.' % netname)
|
||||
irc.reply('Error: Network "%s" seems to be already connected.' % netname)
|
||||
else: # Reconnect the network!
|
||||
network.initVars()
|
||||
network.connection_thread = threading.Thread(target=network.connect)
|
||||
network.connection_thread.start()
|
||||
irc.msg(irc.called_by, "Done.")
|
||||
irc.reply("Done.")
|
||||
|
||||
@utils.add_cmd
|
||||
def autoconnect(irc, source, args):
|
||||
@ -66,13 +66,13 @@ def autoconnect(irc, source, args):
|
||||
seconds = float(args[1])
|
||||
network = world.networkobjects[netname]
|
||||
except IndexError: # Arguments not given.
|
||||
irc.msg(irc.called_by, 'Error: Not enough arguments (needs 2: network name (case sensitive), autoconnect time (in seconds)).')
|
||||
irc.reply('Error: Not enough arguments (needs 2: network name (case sensitive), autoconnect time (in seconds)).')
|
||||
return
|
||||
except KeyError: # Unknown network.
|
||||
irc.msg(irc.called_by, 'Error: No such network "%s" (case sensitive).' % netname)
|
||||
irc.reply('Error: No such network "%s" (case sensitive).' % netname)
|
||||
return
|
||||
except ValueError:
|
||||
irc.msg(irc.called_by, 'Error: Invalid argument "%s" for <seconds>.' % seconds)
|
||||
irc.reply('Error: Invalid argument "%s" for <seconds>.' % seconds)
|
||||
return
|
||||
network.serverdata['autoconnect'] = seconds
|
||||
irc.msg(irc.called_by, "Done.")
|
||||
irc.reply("Done.")
|
||||
|
@ -363,6 +363,7 @@ def initializeChannel(irc, channel):
|
||||
# Send our users and channel modes to the other nets
|
||||
log.debug('(%s) initializeChannel: joining our (%s) users: %s', irc.name, remotenet, irc.channels[channel].users)
|
||||
relayJoins(irc, channel, irc.channels[channel].users, irc.channels[channel].ts)
|
||||
if irc.pseudoclient.uid not in irc.channels[channel].users:
|
||||
irc.proto.joinClient(irc.pseudoclient.uid, channel)
|
||||
|
||||
def removeChannel(irc, channel):
|
||||
@ -822,8 +823,8 @@ def handle_kick(irc, source, command, args):
|
||||
remoteirc.proto.kickServer(rsid, remotechan, real_target, text)
|
||||
|
||||
# If the target isn't on any channels, quit them.
|
||||
if origuser and origuser[0] != remoteirc.name and not remoteirc.users[real_target].channels:
|
||||
del relayusers[origuser][remoteirc.name]
|
||||
if remoteirc != irc and (not remoteirc.users[real_target].channels) and not origuser:
|
||||
del relayusers[(irc.name, target)][remoteirc.name]
|
||||
remoteirc.proto.quitClient(real_target, 'Left all shared channels.')
|
||||
|
||||
if origuser and not irc.users[target].channels:
|
||||
@ -1011,7 +1012,7 @@ def handle_disconnect(irc, numeric, command, args):
|
||||
del relayusers[k][irc.name]
|
||||
if k[0] == irc.name:
|
||||
try:
|
||||
handle_quit(irc, k[1], 'PYLINK_DISCONNECT', {'text': 'Home network lost connection.'})
|
||||
handle_quit(irc, k[1], 'PYLINK_DISCONNECT', {'text': 'Relay network lost connection.'})
|
||||
del relayusers[k]
|
||||
except KeyError:
|
||||
pass
|
||||
@ -1024,7 +1025,7 @@ def handle_disconnect(irc, numeric, command, args):
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
ircobj.proto.squitServer(ircobj.sid, rsid, text='Home network lost connection.')
|
||||
ircobj.proto.squitServer(ircobj.sid, rsid, text='Relay network lost connection.')
|
||||
del relayservers[name][irc.name]
|
||||
try:
|
||||
del relayservers[irc.name]
|
||||
@ -1074,22 +1075,22 @@ def create(irc, source, args):
|
||||
try:
|
||||
channel = utils.toLower(irc, args[0])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1: channel.")
|
||||
irc.reply("Error: Not enough arguments. Needs 1: channel.")
|
||||
return
|
||||
if not utils.isChannel(channel):
|
||||
irc.msg(irc.called_by, 'Error: Invalid channel %r.' % channel)
|
||||
irc.reply('Error: Invalid channel %r.' % channel)
|
||||
return
|
||||
if source not in irc.channels[channel].users:
|
||||
irc.msg(irc.called_by, 'Error: You must be in %r to complete this operation.' % channel)
|
||||
irc.reply('Error: You must be in %r to complete this operation.' % channel)
|
||||
return
|
||||
utils.checkAuthenticated(irc, source)
|
||||
localentry = getRelay((irc.name, channel))
|
||||
if localentry:
|
||||
irc.msg(irc.called_by, 'Error: Channel %r is already part of a relay.' % channel)
|
||||
irc.reply('Error: Channel %r is already part of a relay.' % channel)
|
||||
return
|
||||
db[(irc.name, channel)] = {'claim': [irc.name], 'links': set(), 'blocked_nets': set()}
|
||||
initializeChannel(irc, channel)
|
||||
irc.msg(irc.called_by, 'Done.')
|
||||
irc.reply('Done.')
|
||||
|
||||
@utils.add_cmd
|
||||
def destroy(irc, source, args):
|
||||
@ -1099,10 +1100,10 @@ def destroy(irc, source, args):
|
||||
try:
|
||||
channel = utils.toLower(irc, args[0])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1: channel.")
|
||||
irc.reply("Error: Not enough arguments. Needs 1: channel.")
|
||||
return
|
||||
if not utils.isChannel(channel):
|
||||
irc.msg(irc.called_by, 'Error: Invalid channel %r.' % channel)
|
||||
irc.reply('Error: Invalid channel %r.' % channel)
|
||||
return
|
||||
utils.checkAuthenticated(irc, source)
|
||||
|
||||
@ -1112,9 +1113,9 @@ def destroy(irc, source, args):
|
||||
removeChannel(world.networkobjects.get(link[0]), link[1])
|
||||
removeChannel(irc, channel)
|
||||
del db[entry]
|
||||
irc.msg(irc.called_by, 'Done.')
|
||||
irc.reply('Done.')
|
||||
else:
|
||||
irc.msg(irc.called_by, 'Error: No such relay %r exists.' % channel)
|
||||
irc.reply('Error: No such relay %r exists.' % channel)
|
||||
return
|
||||
|
||||
@utils.add_cmd
|
||||
@ -1127,7 +1128,7 @@ def link(irc, source, args):
|
||||
channel = utils.toLower(irc, args[1])
|
||||
remotenet = args[0].lower()
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 2-3: remote netname, channel, local channel name (optional).")
|
||||
irc.reply("Error: Not enough arguments. Needs 2-3: remote netname, channel, local channel name (optional).")
|
||||
return
|
||||
try:
|
||||
localchan = utils.toLower(irc, args[2])
|
||||
@ -1135,37 +1136,37 @@ def link(irc, source, args):
|
||||
localchan = channel
|
||||
for c in (channel, localchan):
|
||||
if not utils.isChannel(c):
|
||||
irc.msg(irc.called_by, 'Error: Invalid channel %r.' % c)
|
||||
irc.reply('Error: Invalid channel %r.' % c)
|
||||
return
|
||||
if source not in irc.channels[localchan].users:
|
||||
irc.msg(irc.called_by, 'Error: You must be in %r to complete this operation.' % localchan)
|
||||
irc.reply('Error: You must be in %r to complete this operation.' % localchan)
|
||||
return
|
||||
utils.checkAuthenticated(irc, source)
|
||||
if remotenet not in world.networkobjects:
|
||||
irc.msg(irc.called_by, 'Error: No network named %r exists.' % remotenet)
|
||||
irc.reply('Error: No network named %r exists.' % remotenet)
|
||||
return
|
||||
localentry = getRelay((irc.name, localchan))
|
||||
if localentry:
|
||||
irc.msg(irc.called_by, 'Error: Channel %r is already part of a relay.' % localchan)
|
||||
irc.reply('Error: Channel %r is already part of a relay.' % localchan)
|
||||
return
|
||||
try:
|
||||
entry = db[(remotenet, channel)]
|
||||
except KeyError:
|
||||
irc.msg(irc.called_by, 'Error: No such relay %r exists.' % channel)
|
||||
irc.reply('Error: No such relay %r exists.' % channel)
|
||||
return
|
||||
else:
|
||||
if irc.name in entry['blocked_nets']:
|
||||
irc.msg(irc.called_by, 'Error: Access denied (network is banned from linking to this channel).')
|
||||
irc.reply('Error: Access denied (network is banned from linking to this channel).')
|
||||
return
|
||||
for link in entry['links']:
|
||||
if link[0] == irc.name:
|
||||
irc.msg(irc.called_by, "Error: Remote channel '%s%s' is already"
|
||||
irc.reply("Error: Remote channel '%s%s' is already"
|
||||
" linked here as %r." % (remotenet,
|
||||
channel, link[1]))
|
||||
return
|
||||
entry['links'].add((irc.name, localchan))
|
||||
initializeChannel(irc, localchan)
|
||||
irc.msg(irc.called_by, 'Done.')
|
||||
irc.reply('Done.')
|
||||
|
||||
@utils.add_cmd
|
||||
def delink(irc, source, args):
|
||||
@ -1176,7 +1177,7 @@ def delink(irc, source, args):
|
||||
try:
|
||||
channel = utils.toLower(irc, args[0])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1-2: channel, remote netname (optional).")
|
||||
irc.reply("Error: Not enough arguments. Needs 1-2: channel, remote netname (optional).")
|
||||
return
|
||||
try:
|
||||
remotenet = args[1].lower()
|
||||
@ -1184,13 +1185,13 @@ def delink(irc, source, args):
|
||||
remotenet = None
|
||||
utils.checkAuthenticated(irc, source)
|
||||
if not utils.isChannel(channel):
|
||||
irc.msg(irc.called_by, 'Error: Invalid channel %r.' % channel)
|
||||
irc.reply('Error: Invalid channel %r.' % channel)
|
||||
return
|
||||
entry = getRelay((irc.name, channel))
|
||||
if entry:
|
||||
if entry[0] == irc.name: # We own this channel.
|
||||
if not remotenet:
|
||||
irc.msg(irc.called_by, "Error: You must select a network to "
|
||||
irc.reply("Error: You must select a network to "
|
||||
"delink, or use the 'destroy' command to remove "
|
||||
"this relay entirely (it was created on the current "
|
||||
"network).")
|
||||
@ -1203,9 +1204,9 @@ def delink(irc, source, args):
|
||||
else:
|
||||
removeChannel(irc, channel)
|
||||
db[entry]['links'].remove((irc.name, channel))
|
||||
irc.msg(irc.called_by, 'Done.')
|
||||
irc.reply('Done.')
|
||||
else:
|
||||
irc.msg(irc.called_by, 'Error: No such relay %r.' % channel)
|
||||
irc.reply('Error: No such relay %r.' % channel)
|
||||
|
||||
@utils.add_cmd
|
||||
def linked(irc, source, args):
|
||||
@ -1247,37 +1248,37 @@ def linkacl(irc, source, args):
|
||||
cmd = args[0].lower()
|
||||
channel = utils.toLower(irc, args[1])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, missingargs)
|
||||
irc.reply(missingargs)
|
||||
return
|
||||
if not utils.isChannel(channel):
|
||||
irc.msg(irc.called_by, 'Error: Invalid channel %r.' % channel)
|
||||
irc.reply('Error: Invalid channel %r.' % channel)
|
||||
return
|
||||
relay = getRelay((irc.name, channel))
|
||||
if not relay:
|
||||
irc.msg(irc.called_by, 'Error: No such relay %r exists.' % channel)
|
||||
irc.reply('Error: No such relay %r exists.' % channel)
|
||||
return
|
||||
if cmd == 'list':
|
||||
s = 'Blocked networks for \x02%s\x02: \x02%s\x02' % (channel, ', '.join(db[relay]['blocked_nets']) or '(empty)')
|
||||
irc.msg(irc.called_by, s)
|
||||
irc.reply(s)
|
||||
return
|
||||
|
||||
try:
|
||||
remotenet = args[2]
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, missingargs)
|
||||
irc.reply(missingargs)
|
||||
return
|
||||
if cmd == 'deny':
|
||||
db[relay]['blocked_nets'].add(remotenet)
|
||||
irc.msg(irc.called_by, 'Done.')
|
||||
irc.reply('Done.')
|
||||
elif cmd == 'allow':
|
||||
try:
|
||||
db[relay]['blocked_nets'].remove(remotenet)
|
||||
except KeyError:
|
||||
irc.msg(irc.called_by, 'Error: Network %r is not on the blacklist for %r.' % (remotenet, channel))
|
||||
irc.reply('Error: Network %r is not on the blacklist for %r.' % (remotenet, channel))
|
||||
else:
|
||||
irc.msg(irc.called_by, 'Done.')
|
||||
irc.reply('Done.')
|
||||
else:
|
||||
irc.msg(irc.called_by, 'Error: Unknown subcommand %r: valid ones are ALLOW, DENY, and LIST.' % cmd)
|
||||
irc.reply('Error: Unknown subcommand %r: valid ones are ALLOW, DENY, and LIST.' % cmd)
|
||||
|
||||
@utils.add_cmd
|
||||
def showuser(irc, source, args):
|
||||
@ -1322,7 +1323,7 @@ def save(irc, source, args):
|
||||
Saves the relay database to disk."""
|
||||
utils.checkAuthenticated(irc, source)
|
||||
exportDB()
|
||||
irc.msg(irc.called_by, 'Done.')
|
||||
irc.reply('Done.')
|
||||
|
||||
@utils.add_cmd
|
||||
def claim(irc, source, args):
|
||||
@ -1335,19 +1336,19 @@ def claim(irc, source, args):
|
||||
try:
|
||||
channel = utils.toLower(irc, args[0])
|
||||
except IndexError:
|
||||
irc.msg(irc.called_by, "Error: Not enough arguments. Needs 1-2: channel, list of networks (optional).")
|
||||
irc.reply("Error: Not enough arguments. Needs 1-2: channel, list of networks (optional).")
|
||||
return
|
||||
|
||||
# We override getRelay() here to limit the search to the current network.
|
||||
relay = (irc.name, channel)
|
||||
if relay not in db:
|
||||
irc.msg(irc.called_by, 'Error: No such relay %r exists.' % channel)
|
||||
irc.reply('Error: No such relay %r exists.' % channel)
|
||||
return
|
||||
claimed = db[relay]["claim"]
|
||||
try:
|
||||
nets = args[1].strip()
|
||||
except IndexError: # No networks given.
|
||||
irc.msg(irc.called_by, 'Channel \x02%s\x02 is claimed by: %s' %
|
||||
irc.reply('Channel \x02%s\x02 is claimed by: %s' %
|
||||
(channel, ', '.join(claimed) or '\x1D(none)\x1D'))
|
||||
else:
|
||||
if nets == '-' or not nets:
|
||||
@ -1355,5 +1356,5 @@ def claim(irc, source, args):
|
||||
else:
|
||||
claimed = set(nets.split(','))
|
||||
db[relay]["claim"] = claimed
|
||||
irc.msg(irc.called_by, 'CLAIM for channel \x02%s\x02 set to: %s' %
|
||||
irc.reply('CLAIM for channel \x02%s\x02 set to: %s' %
|
||||
(channel, ', '.join(claimed) or '\x1D(none)\x1D'))
|
||||
|
@ -23,7 +23,7 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
||||
# are called with the right hooks.
|
||||
self.hook_map = {'FJOIN': 'JOIN', 'RSQUIT': 'SQUIT', 'FMODE': 'MODE',
|
||||
'FTOPIC': 'TOPIC', 'OPERTYPE': 'MODE', 'FHOST': 'CHGHOST',
|
||||
'FIDENT': 'CHGIDENT', 'FNAME': 'CHGNAME'}
|
||||
'FIDENT': 'CHGIDENT', 'FNAME': 'CHGNAME', 'SVSTOPIC': 'TOPIC'}
|
||||
self.sidgen = utils.TS6SIDGenerator(self.irc)
|
||||
self.uidgen = {}
|
||||
|
||||
@ -514,6 +514,9 @@ class InspIRCdProtocol(TS6BaseProtocol):
|
||||
self.irc.channels[channel].topicset = True
|
||||
return {'channel': channel, 'setter': setter, 'ts': ts, 'topic': topic}
|
||||
|
||||
# SVSTOPIC is used by InspIRCd module m_topiclock - its arguments are the same as FTOPIC
|
||||
handle_svstopic = handle_ftopic
|
||||
|
||||
def handle_invite(self, numeric, command, args):
|
||||
"""Handles incoming INVITEs."""
|
||||
# <- :70MAAAAAC INVITE 0ALAAAAAA #blah 0
|
||||
|
@ -578,9 +578,9 @@ class TS6Protocol(TS6BaseProtocol):
|
||||
log.debug('Applying modes %s for %s', parsedmodes, uid)
|
||||
utils.applyModes(self.irc, uid, parsedmodes)
|
||||
self.irc.servers[numeric].users.add(uid)
|
||||
# Call the OPERED UP hook if +o is in the mode list.
|
||||
if ('o', None) in parsedmodes:
|
||||
otype = 'Server_Administrator' if ('a', None) in parsedmodes else 'IRC_Operator'
|
||||
# Call the OPERED UP hook if +o is being added to the mode list.
|
||||
if ('+o', None) in parsedmodes:
|
||||
otype = 'Server_Administrator' if ('+a', None) in parsedmodes else 'IRC_Operator'
|
||||
self.irc.callHooks([uid, 'PYLINK_CLIENT_OPERED', {'text': otype}])
|
||||
return {'uid': uid, 'ts': ts, 'nick': nick, 'realhost': realhost, 'host': host, 'ident': ident, 'ip': ip}
|
||||
|
||||
|
5
utils.py
5
utils.py
@ -104,15 +104,18 @@ class TS6SIDGenerator():
|
||||
return sid
|
||||
|
||||
def add_cmd(func, name=None):
|
||||
"""Binds a command to the given command name."""
|
||||
if name is None:
|
||||
name = func.__name__
|
||||
name = name.lower()
|
||||
world.commands[name].append(func)
|
||||
return func
|
||||
|
||||
def add_hook(func, command):
|
||||
"""Add a hook <func> for command <command>."""
|
||||
"""Binds a hook function to the given command."""
|
||||
command = command.upper()
|
||||
world.hooks[command].append(func)
|
||||
return func
|
||||
|
||||
def toLower(irc, text):
|
||||
"""Returns a lowercase representation of text based on the IRC object's
|
||||
|
Loading…
Reference in New Issue
Block a user