diff --git a/conf.py b/conf.py new file mode 100644 index 0000000..6bdda47 --- /dev/null +++ b/conf.py @@ -0,0 +1,5 @@ +import yaml + +with open("config.yml", 'r') as f: + global conf + conf = yaml.load(f) diff --git a/main.py b/main.py index 4b18df8..db94430 100755 --- a/main.py +++ b/main.py @@ -1,20 +1,17 @@ #!/usr/bin/python3 -import yaml import imp import os import socket import time import sys +from conf import conf import proto -print('PyLink starting...') -with open("config.yml", 'r') as f: - conf = yaml.load(f) - -# if conf['login']['password'] == 'changeme': -# print("You have not set the login details correctly! Exiting...") +if conf['login']['password'] == 'changeme': + print("You have not set the login details correctly! Exiting...") + sys.exit(2) class Irc(): def __init__(self): @@ -74,5 +71,6 @@ class Irc(): self.loaded.append(imp.load_source(plugin, moduleinfo[1])) print("loaded plugins: %s" % self.loaded) - -irc_obj = Irc() +if __name__ == '__main__': + print('PyLink starting...') + irc_obj = Irc() diff --git a/plugins/commands.py b/plugins/commands.py index 59c31ed..ec22a81 100644 --- a/plugins/commands.py +++ b/plugins/commands.py @@ -3,22 +3,54 @@ import sys, os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import proto import utils +from conf import conf -@proto.add_cmd +@utils.add_cmd def tell(irc, source, args): try: target, text = args[0], ' '.join(args[1:]) except IndexError: - utils._msg(irc, source, 'Error: not enough arguments.', notice=False) + utils.msg(irc, source, 'Error: not enough arguments.') return targetuid = proto._nicktoUid(irc, target) if targetuid is None: - utils._msg(irc, source, 'Error: unknown user %r' % target, notice=False) + utils.msg(irc, source, 'Error: unknown user %r' % target) return - utils._msg(irc, target, text) + if not text: + utils.msg(irc, source, "Error: can't send an empty message!") + return + utils.msg(irc, target, text, notice=True) -@proto.add_cmd +@utils.add_cmd def debug(irc, source, args): - utils._msg(irc, source, 'Debug info printed to console.') + utils.msg(irc, source, 'Debug info printed to console.') print(irc.users) print(irc.servers) + +@utils.add_cmd +def status(irc, source, args): + identified = irc.users[source].identified + if identified: + utils.msg(irc, source, 'You are identified as %s.' % identified) + else: + utils.msg(irc, source, 'You are not identified as anyone.') + +@utils.add_cmd +def identify(irc, source, args): + try: + username, password = args[0], args[1] + except IndexError: + utils.msg(irc, source, 'Error: not enough arguments.') + return + if username.lower() == conf['login']['user'].lower() and password == conf['login']['password']: + realuser = conf['login']['user'] + irc.users[source].identified = realuser + utils.msg(irc, source, 'Successfully logged in as %s.' % realuser) + else: + utils.msg(irc, source, 'Incorrect credentials.') + +def listcommands(irc, source, args): + cmds = list(utils.bot_commands.keys()) + cmds.sort() + utils.msg(irc, source, 'Available commands include: %s' % ', '.join(cmds)) +utils.add_cmd(listcommands, 'list') diff --git a/plugins/hello.py b/plugins/hello.py index 1dec4e3..411ef10 100644 --- a/plugins/hello.py +++ b/plugins/hello.py @@ -1,7 +1,7 @@ import sys, os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -import proto +import utils -@proto.add_cmd +@utils.add_cmd def hello(irc, source, args): - proto._sendFromUser(irc, 'PRIVMSG %s :hello!' % source) + utils.msg(irc, source, 'hello!') diff --git a/proto.py b/proto.py index 98d6234..a3ffc56 100644 --- a/proto.py +++ b/proto.py @@ -3,10 +3,7 @@ import time import sys from utils import * from copy import copy - -global bot_commands -# This should be a mapping of command names to functions -bot_commands = {} +import traceback class IrcUser(): def __init__(self, nick, ts, uid, ident='null', host='null', @@ -21,6 +18,8 @@ class IrcUser(): self.ip = ip self.realname = realname + self.identified = False + def __repr__(self): return repr(self.__dict__) @@ -48,12 +47,12 @@ def _nicktoUid(irc, nick): if v.nick == nick: return k -def introduceUser(irc, nick, user, host): +def spawnClient(irc, nick, user, host, *args): uid = next_uid(irc.sid) _sendFromServer(irc, "UID {uid} {ts} {nick} {host} {host} {user} 0.0.0.0 {ts} +o +" " :PyLink Client".format(ts=int(time.time()), host=host, nick=nick, user=user, uid=uid)) - irc.users[uid] = IrcUser(nick, ts, uid, ident, host, realname, realhost, ip) + irc.users[uid] = IrcUser(nick, ts, uid, ident, host, *args) irc.servers[irc.sid].users.append(uid) def connect(irc): @@ -96,15 +95,22 @@ def handle_privmsg(irc, source, command, args): prefix = irc.conf['bot']['prefix'] if args[0] == irc.pseudoclient.uid: cmd_args = args[1].split(' ') - cmd = cmd_args[0] + cmd = cmd_args[0].lower() try: cmd_args = cmd_args[1:] except IndexError: cmd_args = [] try: - bot_commands[cmd](irc, source, cmd_args) + func = bot_commands[cmd] except KeyError: - _sendFromUser(irc, 'PRIVMSG %s :unknown command %r' % (source, cmd)) + msg(irc, source, 'Unknown command %r.' % cmd) + return + try: + func(irc, source, cmd_args) + except Exception as e: + traceback.print_exc() + msg(irc, source, 'Uncaught exception in command %r: %s: %s' % (cmd, type(e).__name__, str(e))) + return def handle_error(irc, numeric, command, args): print('Received an ERROR, killing!') @@ -214,6 +220,3 @@ def handle_events(irc, data): func(irc, numeric, command, args) except KeyError: # unhandled event pass - -def add_cmd(func): - bot_commands[func.__name__.lower()] = func diff --git a/utils.py b/utils.py index c8e7eaf..8fdcd59 100644 --- a/utils.py +++ b/utils.py @@ -1,6 +1,10 @@ import string import proto +global bot_commands +# This should be a mapping of command names to functions +bot_commands = {} + # From http://www.inspircd.org/wiki/Modules/spanningtree/UUIDs.html chars = string.digits + string.ascii_uppercase iters = [iter(chars) for _ in range(6)] @@ -13,6 +17,12 @@ def next_uid(sid, level=-1): except StopIteration: return UID(level-1) -def _msg(irc, target, text, notice=True): +def msg(irc, target, text, notice=False): command = 'NOTICE' if notice else 'PRIVMSG' proto._sendFromUser(irc, '%s %s :%s' % (command, target, text)) + +def add_cmd(func, name=None): + if name is None: + name = func.__name__ + name = name.lower() + bot_commands[name] = func