2015-04-25 08:00:01 +02:00
|
|
|
# commands.py: base PyLink commands
|
2015-05-31 07:35:00 +02:00
|
|
|
import sys
|
|
|
|
import os
|
2015-08-30 04:29:05 +02:00
|
|
|
from time import ctime
|
2015-05-31 07:35:00 +02:00
|
|
|
|
2015-04-25 08:00:01 +02:00
|
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
2015-05-31 08:00:39 +02:00
|
|
|
import utils
|
2015-07-05 22:44:48 +02:00
|
|
|
from log import log
|
2015-08-29 18:39:33 +02:00
|
|
|
import world
|
2015-04-25 08:00:01 +02:00
|
|
|
|
2015-05-31 21:20:09 +02:00
|
|
|
@utils.add_cmd
|
|
|
|
def status(irc, source, args):
|
2015-07-18 07:21:16 +02:00
|
|
|
"""takes no arguments.
|
|
|
|
|
|
|
|
Returns your current PyLink login status."""
|
2015-05-31 21:20:09 +02:00
|
|
|
identified = irc.users[source].identified
|
|
|
|
if identified:
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply('You are identified as \x02%s\x02.' % identified)
|
2015-05-31 21:20:09 +02:00
|
|
|
else:
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply('You are not identified as anyone.')
|
2016-05-01 01:54:11 +02:00
|
|
|
irc.reply('Operator access: \x02%s\x02' % bool(irc.isOper(source)))
|
2015-05-31 07:35:00 +02:00
|
|
|
|
2015-05-31 21:20:09 +02:00
|
|
|
def listcommands(irc, source, args):
|
2015-07-18 07:21:16 +02:00
|
|
|
"""takes no arguments.
|
|
|
|
|
|
|
|
Returns a list of available commands PyLink has to offer."""
|
2015-09-27 19:53:25 +02:00
|
|
|
cmds = list(world.commands.keys())
|
2015-05-31 21:20:09 +02:00
|
|
|
cmds.sort()
|
2015-08-30 04:29:49 +02:00
|
|
|
for idx, cmd in enumerate(cmds):
|
2015-09-27 19:53:25 +02:00
|
|
|
nfuncs = len(world.commands[cmd])
|
2015-08-30 04:29:49 +02:00
|
|
|
if nfuncs > 1:
|
|
|
|
cmds[idx] = '%s(x%s)' % (cmd, nfuncs)
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply('Available commands include: %s' % ', '.join(cmds))
|
|
|
|
irc.reply('To see help on a specific command, type \x02help <command>\x02.')
|
2015-05-31 21:20:09 +02:00
|
|
|
utils.add_cmd(listcommands, 'list')
|
2015-07-18 07:21:16 +02:00
|
|
|
|
|
|
|
@utils.add_cmd
|
|
|
|
def help(irc, source, args):
|
|
|
|
"""<command>
|
|
|
|
|
|
|
|
Gives help for <command>, if it is available."""
|
|
|
|
try:
|
|
|
|
command = args[0].lower()
|
|
|
|
except IndexError: # No argument given, just return 'list' output
|
|
|
|
listcommands(irc, source, args)
|
|
|
|
return
|
2015-09-27 19:53:25 +02:00
|
|
|
if command not in world.commands:
|
2015-09-07 07:23:44 +02:00
|
|
|
irc.msg(source, 'Error: Unknown command %r.' % command)
|
2015-07-18 07:21:16 +02:00
|
|
|
return
|
|
|
|
else:
|
2015-09-27 19:53:25 +02:00
|
|
|
funcs = world.commands[command]
|
2015-08-30 04:24:32 +02:00
|
|
|
if len(funcs) > 1:
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply('The following \x02%s\x02 plugins bind to the \x02%s\x02 command: %s'
|
2015-08-30 04:24:32 +02:00
|
|
|
% (len(funcs), command, ', '.join([func.__module__ for func in funcs])))
|
|
|
|
for func in funcs:
|
|
|
|
doc = func.__doc__
|
|
|
|
mod = func.__module__
|
|
|
|
if doc:
|
|
|
|
lines = doc.split('\n')
|
|
|
|
# Bold the first line, which usually just tells you what
|
|
|
|
# arguments the command takes.
|
|
|
|
lines[0] = '\x02%s %s\x02 (plugin: %r)' % (command, lines[0], mod)
|
|
|
|
for line in lines:
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply(line.strip())
|
2015-08-30 04:24:32 +02:00
|
|
|
else:
|
2015-09-07 07:23:44 +02:00
|
|
|
irc.msg(source, "Error: Command %r (from plugin %r) "
|
2015-08-30 04:24:32 +02:00
|
|
|
"doesn't offer any help." % (command, mod))
|
|
|
|
return
|
|
|
|
|
2016-02-21 03:24:29 +01:00
|
|
|
_none = '\x1D(none)\x1D'
|
2015-08-30 04:29:05 +02:00
|
|
|
@utils.add_cmd
|
|
|
|
def showuser(irc, source, args):
|
|
|
|
"""<user>
|
|
|
|
|
|
|
|
Shows information about <user>."""
|
|
|
|
try:
|
|
|
|
target = args[0]
|
|
|
|
except IndexError:
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply("Error: Not enough arguments. Needs 1: nick.")
|
2015-08-30 04:29:05 +02:00
|
|
|
return
|
2016-01-01 02:28:47 +01:00
|
|
|
u = irc.nickToUid(target) or target
|
2015-08-30 04:29:05 +02:00
|
|
|
# Only show private info if the person is calling 'showuser' on themselves,
|
|
|
|
# or is an oper.
|
2016-05-01 01:54:11 +02:00
|
|
|
verbose = irc.isOper(source) or u == source
|
2015-08-30 04:29:05 +02:00
|
|
|
if u not in irc.users:
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply('Error: Unknown user %r.' % target)
|
2015-08-30 04:29:05 +02:00
|
|
|
return
|
|
|
|
|
2015-09-07 07:23:44 +02:00
|
|
|
f = lambda s: irc.msg(source, s)
|
2015-08-30 04:29:05 +02:00
|
|
|
userobj = irc.users[u]
|
|
|
|
f('Information on user \x02%s\x02 (%s@%s): %s' % (userobj.nick, userobj.ident,
|
|
|
|
userobj.host, userobj.realname))
|
2016-01-01 02:28:47 +01:00
|
|
|
|
|
|
|
sid = irc.getServer(u)
|
2015-08-30 04:29:05 +02:00
|
|
|
serverobj = irc.servers[sid]
|
|
|
|
ts = userobj.ts
|
2016-02-21 03:24:29 +01:00
|
|
|
|
|
|
|
# Show connected server & signon time
|
2015-08-30 04:29:05 +02:00
|
|
|
f('\x02Home server\x02: %s (%s); \x02Signon time:\x02 %s (%s)' % \
|
|
|
|
(serverobj.name, sid, ctime(float(ts)), ts))
|
2016-02-21 03:24:29 +01:00
|
|
|
|
|
|
|
if verbose: # Oper only data: user modes, channels on, account info, etc.
|
|
|
|
|
2016-05-01 01:33:46 +02:00
|
|
|
f('\x02User modes\x02: %s' % irc.joinModes(userobj.modes))
|
2016-02-21 03:24:29 +01:00
|
|
|
f('\x02Protocol UID\x02: %s; \x02Real host\x02: %s; \x02IP\x02: %s' % \
|
|
|
|
(u, userobj.realhost, userobj.ip))
|
2016-03-14 22:35:09 +01:00
|
|
|
channels = sorted(userobj.channels)
|
|
|
|
f('\x02Channels\x02: %s' % (' '.join(channels) or _none))
|
2016-02-21 03:24:29 +01:00
|
|
|
f('\x02PyLink identification\x02: %s; \x02Services account\x02: %s; \x02Away status\x02: %s' % \
|
|
|
|
((userobj.identified or _none), (userobj.services_account or _none), userobj.away or _none))
|
|
|
|
|
2015-09-03 08:46:59 +02:00
|
|
|
|
2015-09-15 03:43:19 +02:00
|
|
|
@utils.add_cmd
|
|
|
|
def showchan(irc, source, args):
|
|
|
|
"""<channel>
|
|
|
|
|
|
|
|
Shows information about <channel>."""
|
|
|
|
try:
|
|
|
|
channel = utils.toLower(irc, args[0])
|
|
|
|
except IndexError:
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply("Error: Not enough arguments. Needs 1: channel.")
|
2015-09-15 03:43:19 +02:00
|
|
|
return
|
|
|
|
if channel not in irc.channels:
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply('Error: Unknown channel %r.' % channel)
|
2015-09-15 03:43:19 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
f = lambda s: irc.msg(source, s)
|
|
|
|
c = irc.channels[channel]
|
|
|
|
# Only show verbose info if caller is oper or is in the target channel.
|
2016-05-01 01:54:11 +02:00
|
|
|
verbose = source in c.users or irc.isOper(source)
|
2015-09-15 03:43:19 +02:00
|
|
|
secret = ('s', None) in c.modes
|
|
|
|
if secret and not verbose:
|
|
|
|
# Hide secret channels from normal users.
|
|
|
|
irc.msg(source, 'Error: Unknown channel %r.' % channel)
|
|
|
|
return
|
|
|
|
|
|
|
|
nicks = [irc.users[u].nick for u in c.users]
|
|
|
|
pmodes = ('owner', 'admin', 'op', 'halfop', 'voice')
|
|
|
|
|
|
|
|
f('Information on channel \x02%s\x02:' % channel)
|
|
|
|
f('\x02Channel topic\x02: %s' % c.topic)
|
|
|
|
f('\x02Channel creation time\x02: %s (%s)' % (ctime(c.ts), c.ts))
|
|
|
|
# Show only modes that aren't list-style modes.
|
2016-05-01 01:33:46 +02:00
|
|
|
modes = irc.joinModes([m for m in c.modes if m[0] not in irc.cmodes['*A']])
|
2015-09-15 03:43:19 +02:00
|
|
|
f('\x02Channel modes\x02: %s' % modes)
|
|
|
|
if verbose:
|
|
|
|
nicklist = []
|
|
|
|
# Iterate over the user list, sorted by nick.
|
|
|
|
for user, nick in sorted(zip(c.users, nicks),
|
|
|
|
key=lambda userpair: userpair[1].lower()):
|
|
|
|
prefixmodes = [irc.prefixmodes.get(irc.cmodes.get(pmode, ''), '')
|
2016-03-20 01:25:04 +01:00
|
|
|
for pmode in pmodes if user in c.prefixmodes[pmode]]
|
2015-09-15 03:43:19 +02:00
|
|
|
nicklist.append(''.join(prefixmodes) + nick)
|
|
|
|
|
|
|
|
while nicklist[:20]: # 20 nicks per line to prevent message cutoff.
|
|
|
|
f('\x02User list\x02: %s' % ' '.join(nicklist[:20]))
|
|
|
|
nicklist = nicklist[20:]
|
|
|
|
|
2015-09-19 20:51:56 +02:00
|
|
|
@utils.add_cmd
|
|
|
|
def version(irc, source, args):
|
|
|
|
"""takes no arguments.
|
|
|
|
|
|
|
|
Returns the version of the currently running PyLink instance."""
|
2015-10-24 03:29:10 +02:00
|
|
|
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)
|
2015-09-26 19:15:07 +02:00
|
|
|
|
|
|
|
@utils.add_cmd
|
|
|
|
def echo(irc, source, args):
|
|
|
|
"""<text>
|
|
|
|
|
|
|
|
Echoes the text given."""
|
2015-10-24 03:29:10 +02:00
|
|
|
irc.reply(' '.join(args))
|
2015-09-27 20:54:06 +02:00
|
|
|
|
2015-10-25 18:18:51 +01:00
|
|
|
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."""
|
2016-05-01 01:54:11 +02:00
|
|
|
irc.checkAuthenticated(source, allowOper=False)
|
2015-10-25 18:18:51 +01:00
|
|
|
try:
|
|
|
|
level = args[0].upper()
|
|
|
|
try:
|
|
|
|
loglevel = loglevels[level]
|
|
|
|
except KeyError:
|
|
|
|
irc.reply('Error: Unknown log level "%s".' % level)
|
|
|
|
return
|
|
|
|
else:
|
2016-04-23 20:05:49 +02:00
|
|
|
world.stdout_handler.setLevel(loglevel)
|
2015-10-25 18:18:51 +01:00
|
|
|
irc.reply("Done.")
|
|
|
|
except IndexError:
|
2016-04-23 20:05:49 +02:00
|
|
|
irc.reply(world.stdout_handler.level)
|