diff options
author | root <root@flap> | 2014-05-06 10:00:33 -0400 |
---|---|---|
committer | root <root@flap> | 2014-05-06 10:00:33 -0400 |
commit | 4d8016064edd5e5dc1d194ea5ec0fce4f07b8f2a (patch) | |
tree | d8ecba8651604e51d6f887449641ac627844ae63 /Reaktor | |
parent | f44c8529e6d04b557d93cc862599b956ed21f0de (diff) | |
parent | d0367082a5c1296cefed641b4eda736b29a3ad69 (diff) |
Merge branch 'master' of https://github.com/krebscode/painload
Diffstat (limited to 'Reaktor')
28 files changed, 506 insertions, 49 deletions
diff --git a/Reaktor/IRC/getconf.py b/Reaktor/IRC/getconf.py index f9cd4404..168c908c 100644 --- a/Reaktor/IRC/getconf.py +++ b/Reaktor/IRC/getconf.py @@ -9,14 +9,17 @@ import os def make_getconf(filename): - def getconf(prop): + def getconf(prop, default_value=None): prop_split = prop.split('.') string = '' config = load_config(filename) #imp.reload(config) tmp = config.__dict__ for pr in prop_split: - tmp = tmp[pr] + if pr in tmp: + tmp = tmp[pr] + else: + return default_value return tmp return getconf diff --git a/Reaktor/IRC/ircasy.py b/Reaktor/IRC/ircasy.py index 7821305f..9a7f44f3 100644 --- a/Reaktor/IRC/ircasy.py +++ b/Reaktor/IRC/ircasy.py @@ -22,10 +22,10 @@ class asybot(asychat): asychat.__init__(self) #logger magic self.log = logging.getLogger('asybot_' + nickname) - hdlr = logging.handlers.SysLogHandler(facility=logging.handlers.SysLogHandler.LOG_DAEMON) - formatter = logging.Formatter( '%(filename)s: %(levelname)s: %(message)s') - hdlr.setFormatter(formatter) - self.log.addHandler(hdlr) + #hdlr = logging.handlers.SysLogHandler(facility=logging.handlers.SysLogHandler.LOG_DAEMON) + #formatter = logging.Formatter( '%(filename)s: %(levelname)s: %(message)s') + #hdlr.setFormatter(formatter) + #self.log.addHandler(hdlr) logging.basicConfig(level = loglevel) self.nickname = nickname @@ -45,7 +45,7 @@ class asybot(asychat): else: self.hostname = nickname - self.retry = False + self.retry = True self.server = server self.port = port self.channels = channels @@ -85,7 +85,10 @@ class asybot(asychat): alarm(self.hammer_interval) def collect_incoming_data(self, data): - self.data += data.decode() + try: + self.data += data.decode() + except Exception as e: + print('error decoding message: ' + str(e)); def found_terminator(self): self.log.debug('<< %s' % self.data) @@ -107,13 +110,15 @@ class asybot(asychat): elif command == 'INVITE': self.on_invite(prefix, command, params, rest) + elif command == 'KICK': + self.on_kick(prefix, command, params, rest) + + elif command == 'JOIN': + self.on_join(prefix, command, params, rest) + elif command == '433': # ERR_NICKNAMEINUSE, retry with another name - _, nickname, int, _ = split('^.*[^0-9]([0-9]+)$', self.nickname) \ - if search('[0-9]$', self.nickname) \ - else ['', self.nickname, 0, ''] - self.nickname = nickname + str(int + 1) - self.handle_connect() + self.on_nickinuse(prefix, command, params, rest) elif command == '376': self.on_welcome(prefix, command, params, rest) @@ -158,11 +163,29 @@ class asybot(asychat): def ME(self, target, text): self.PRIVMSG(target, ('ACTION ' + text + '')) - def on_privmsg(self, prefix, command, params, rest): - pass - def on_welcome(self, prefix, command, params, rest): self.push('JOIN %s' % ','.join(self.channels)) + def on_kick(self, prefix, command, params, rest): + self.log.debug(params) + if params[-1] == self.nickname: + for chan in params[:-1]: + self.channels.remove(chan) + + def on_join(self, prefix, command, params, rest): + pass + + def on_privmsg(self, prefix, command, params, rest): + pass + def on_invite(self, prefix, command, params, rest): pass + + def on_nickinuse(self, prefix, command, params, rest): + regex = search('(\d+)$', self.nickname) + if regex: + theint = int(regex.group(0)) + self.nickname = self.nickname.strip(str(theint)) + str(theint + 1) + else: + self.nickname = self.nickname + '0' + self.handle_connect() diff --git a/Reaktor/IRC/reaktor.py b/Reaktor/IRC/reaktor.py index 990d47e5..f9f25e57 100644..100755 --- a/Reaktor/IRC/reaktor.py +++ b/Reaktor/IRC/reaktor.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import os from ircasy import asybot from asyncore import loop @@ -5,29 +6,53 @@ from translate_colors import translate_colors import shlex from re import split, search, match -config_filename = './config.py' +default_config = './config.py' from getconf import make_getconf -getconf = make_getconf(config_filename) +getconf = None import logging,logging.handlers log = logging.getLogger('asybot') -hdlr = logging.handlers.SysLogHandler(facility=logging.handlers.SysLogHandler.LOG_DAEMON) -formatter = logging.Formatter( '%(filename)s: %(levelname)s: %(message)s') -hdlr.setFormatter(formatter) -log.addHandler(hdlr) -logging.basicConfig(level = logging.DEBUG if getconf('debug') else logging.INFO) +#hdlr = logging.handlers.SysLogHandler(address='/dev/log', facility=logging.handlers.SysLogHandler.LOG_DAEMON) +#formatter = logging.Formatter( '%(filename)s: %(levelname)s: %(message)s') +#hdlr.setFormatter(formatter) +#log.addHandler(hdlr) + class Reaktor(asybot): - def __init__(self): + def __init__(self,config=default_config): + self.config = config + log.info("using config file %s"%(config)) asybot.__init__(self, getconf('irc_server'), getconf('irc_port'), getconf('irc_nickname'), getconf('irc_channels'), hammer_interval=getconf('irc_hammer_interval'), alarm_timeout=getconf('irc_alarm_timeout'), kill_timeout=getconf('irc_kill_timeout')) + def is_admin(self,prefix): + try: + with open(getconf('auth_file')) as f: + for line in f: + if line.strip() == prefix: + return True + except Exception as e: + log.info(e) + return False + + def on_join(self, prefix, command, params, rest): + for command in getconf('on_join', []): + self.execute_command(command, None, prefix, params) + def on_privmsg(self, prefix, command, params, rest): for command in getconf('commands'): y = match(command['pattern'], rest) if y: - self.execute_command(command, y, prefix, params) - break + if not self.is_admin(prefix): + self.PRIVMSG(params,'unauthorized!') + else: + return self.execute_command(command, y, prefix, params) + + for command in getconf('public_commands'): + y = match(command['pattern'], rest) + if y: + return self.execute_command(command, y, prefix, params) + def execute_command(self, command, match, prefix, target): from os.path import realpath, dirname, join @@ -37,16 +62,33 @@ class Reaktor(asybot): #TODO: allow only commands below ./commands/ exe = join(dirname(realpath(dirname(__file__))), command['argv'][0]) myargv = [exe] + command['argv'][1:] - if match.groupdict().get('args',None): - myargv += shlex.split(match.groupdict()['args']) + try: + if match and match.groupdict().get('args', None): + myargv += shlex.split(match.groupdict()['args']) + except: + log.info("cannot parse args!") - env = {} + cwd = getconf('workdir') + if not os.access(cwd,os.W_OK): + log.error("Workdir '%s' is not Writable! Falling back to root dir"%cwd) + cwd = "/" + + env = command.get('env', {}) + env['_prefix'] = prefix env['_from'] = prefix.split('!', 1)[0] - env['config_filename'] = os.path.abspath(config_filename) + + log.debug('self:' +self.nickname) + # when receiving /query, answer to the user, not to self + if self.nickname in target: + target.remove(self.nickname) + target.append(env['_from']) + log.debug('target:' +str(target)) + start = time() try: - p = popen(myargv, bufsize=1, stdout=PIPE, stderr=PIPE, env=env) - except (OSError, Exception) as error: + print(myargv) + p = popen(myargv, bufsize=1, stdout=PIPE, stderr=PIPE, env=env, cwd=cwd) + except Exception as error: self.ME(target, 'brain damaged') log.error('OSError@%s: %s' % (myargv, error)) return @@ -67,5 +109,9 @@ class Reaktor(asybot): self.ME(target, 'mimimi') if __name__ == "__main__": - Reaktor() + import sys + conf = sys.argv[1] if len(sys.argv) == 2 else default_config + getconf = make_getconf(conf) + logging.basicConfig(level = logging.DEBUG if getconf('debug') else logging.INFO) + Reaktor(conf) loop() diff --git a/Reaktor/auth.lst b/Reaktor/auth.lst new file mode 100755 index 00000000..8b137891 --- /dev/null +++ b/Reaktor/auth.lst @@ -0,0 +1 @@ + diff --git a/Reaktor/commands/caps b/Reaktor/commands/caps index c47319f5..ac8cc66d 100755 --- a/Reaktor/commands/caps +++ b/Reaktor/commands/caps @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#! /usr/bin/env python3 import imp import os @@ -9,4 +9,5 @@ def load_config(filename): return imp.load_module(modname, file, pathname, description) config = load_config(os.environ['config_filename']) -print(' '.join(filter(None,[ x.get('capname',None) for x in config.commands]))) +print('Private: '+' '.join(filter(None,[ x.get('capname',None) for x in config.commands]))) +print('Public: '+' '.join(filter(None,[ x.get('capname',None) for x in config.public_commands]))) diff --git a/Reaktor/commands/identify b/Reaktor/commands/identify new file mode 100755 index 00000000..c2fb2c58 --- /dev/null +++ b/Reaktor/commands/identify @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import imp +import os,sys + +def load_config(filename): + dirname = os.path.dirname(filename) + modname, ext = os.path.splitext(os.path.basename(filename)) + file, pathname, description = imp.find_module(modname, [ dirname ]) + return imp.load_module(modname, file, pathname, description) + +config = load_config(os.environ['config_filename']) + +with open(config.admin_file) as f: + for line in f: + nick,secret = line.split() + if sys.argv[1] == secret: + print("identified you as %s!"%nick) + with open(config.auth_file,'a+') as g: + g.write(os.environ['_prefix'] +"\n") + sys.exit(0) + +print("unable to identify you, sorry") diff --git a/Reaktor/commands/tell-on_join b/Reaktor/commands/tell-on_join new file mode 100755 index 00000000..2dbff41a --- /dev/null +++ b/Reaktor/commands/tell-on_join @@ -0,0 +1,19 @@ +#! /bin/sh +set -euf + +# require flock from util-linux +if test "${FLOCK-}" != "$state_file"; then + exec env FLOCK="$state_file" flock "$state_file" "$0" "$@" +fi + +to="$_from" + +# print messages +sed -n '/^'"$to"' /{ + s/^\([^ ]\+\) \([^ ]\+\) <\([^>]\+\)> \(.*\)/\1: \4 2-- \2, \3/p +}' "$state_file" + +# delete messages +sed -i '/^'"$to"' /{ + d +}' "$state_file" diff --git a/Reaktor/commands/tell-on_privmsg b/Reaktor/commands/tell-on_privmsg new file mode 100755 index 00000000..5d0aff41 --- /dev/null +++ b/Reaktor/commands/tell-on_privmsg @@ -0,0 +1,17 @@ +#! /bin/sh +set -euf + +# require flock from util-linux +if test "${FLOCK-}" != "$state_file"; then + exec env FLOCK="$state_file" flock "$state_file" "$0" "$@" +fi + +from="$_prefix" +to="$1"; shift +msg="$*" +date=$(date) + +# TODO tell now, if already joined +printf '%s %s <%s> %s\n' "$to" "$from" "$date" "$msg" >> "$state_file" + +echo 'Consider it noted.' # that's what lambdabot says... diff --git a/Reaktor/commands/visit-page b/Reaktor/commands/visit-page new file mode 120000 index 00000000..8723336b --- /dev/null +++ b/Reaktor/commands/visit-page @@ -0,0 +1 @@ +../repos/view-website/runner.sh
\ No newline at end of file diff --git a/Reaktor/commands/whatweb b/Reaktor/commands/whatweb index afe20360..68f8aa38 100755 --- a/Reaktor/commands/whatweb +++ b/Reaktor/commands/whatweb @@ -4,4 +4,4 @@ here=$(dirname `readlink -f $0`) whatweb_bin="$here/../repos/whatweb/whatweb" [ ! -e "$whatweb_bin" ] && echo "!! Whatweb app does not exist" && exit 1 [ -z "${1:-}" ] && echo "!! no host given" && exit 1 -exec $whatweb_bin -a 3 "$1" 2>&1 +exec $whatweb_bin --user-agent="Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0" -a 3 "$1" 2>&1 diff --git a/Reaktor/config.py b/Reaktor/config.py index 2dd6ac2f..b1158271 100644 --- a/Reaktor/config.py +++ b/Reaktor/config.py @@ -1,37 +1,82 @@ +from os.path import abspath, expanduser +import re -debug = True +debug = False -# CAVEAT name should not contains regex magic name = 'crabmanner' +#workdir = expanduser('~') + '/state' +workdir = '/home/reaktor/state' + irc_alarm_timeout = 300 irc_hammer_interval = 10 irc_kill_timeout = 360 irc_nickname = name irc_server = 'irc.freenode.org' irc_port = 6667 +irc_restart_timeout = 5 irc_channels = [ '#krebs' ] +admin_file=workdir+'/admin.lst' +auth_file=workdir+'/auth.lst' + +config_filename = abspath(__file__) + +# me is used, so name cannot kill our patterns below +me = '\\b' + re.escape(name) + '\\b' +me_or_us = '(?:' + me + '|\\*)' -def default_command(cmd): +def default_command(cap, cmd=None, env=None): + if not env: env = {} + if cmd == None: cmd=cap return { - 'capname': cmd, - 'pattern': '^(?:' + name + '|\\*):\\s*' + cmd + '\\s*(?:\\s+(?P<args>.*))?$', - 'argv': [ 'commands/' + cmd ] } + 'capname': cap, + 'pattern': '^' + me_or_us + ':\\s*' + cap + '\\s*(?:\\s+(?P<args>.*))?$', + 'argv': [ 'commands/' + cmd ], + 'env': env + } -commands = [ - default_command('caps'), +def simple_command(cap, cmd=None, env={}): + if cmd == None: cmd=cap + return { + 'capname': cap, + 'pattern': '^' + cap + '\\s*(?:\\s+(?P<args>.*))?$', + 'argv' : [ 'commands/' + cmd ], + 'env': env + } + +public_commands = [ + default_command('caps', env={ + 'config_filename': config_filename + }), default_command('hello'), - default_command('reload'), default_command('badcommand'), default_command('rev'), default_command('uptime'), default_command('nocommand'), + default_command('tell', cmd='tell-on_privmsg', env={ + 'state_file': workdir + '/tell.txt' + }), # command not found - { 'pattern': '^(?:' + name + '|\\*):.*', + { 'pattern': '^' + me_or_us + ':.*', 'argv': [ 'commands/respond','You are made of stupid!'] }, # "highlight" - { 'pattern': '.*\\b' + name + '\\b.*', - 'argv': [ 'commands/say', 'I\'m famous' ] } + { 'pattern': '.*' + me + '.*', + 'argv': [ 'commands/say', 'I\'m famous' ] }, + # identify via direct connect + simple_command('identify', env={ + 'config_filename': config_filename + }) +] +commands = [ + default_command('reload') +] + +on_join = [ + { + 'capname': 'tell', + 'argv': [ 'commands/tell-on_join' ], + 'env': { 'state_file': workdir + '/tell.txt' } + } ] diff --git a/Reaktor/startup/conf.d/reaktor b/Reaktor/etc/conf.d/reaktor index a4f3f8e1..a4f3f8e1 100644 --- a/Reaktor/startup/conf.d/reaktor +++ b/Reaktor/etc/conf.d/reaktor diff --git a/Reaktor/startup/init.d/reaktor-debian b/Reaktor/etc/init.d/reaktor-debian index a94384f4..a94384f4 100755 --- a/Reaktor/startup/init.d/reaktor-debian +++ b/Reaktor/etc/init.d/reaktor-debian diff --git a/Reaktor/startup/supervisor/Reaktor.conf b/Reaktor/etc/supervisor/Reaktor.conf index 497066e9..497066e9 100644 --- a/Reaktor/startup/supervisor/Reaktor.conf +++ b/Reaktor/etc/supervisor/Reaktor.conf diff --git a/Reaktor/etc/systemd/system/Reaktor.service b/Reaktor/etc/systemd/system/Reaktor.service new file mode 100644 index 00000000..6bb3e550 --- /dev/null +++ b/Reaktor/etc/systemd/system/Reaktor.service @@ -0,0 +1,14 @@ +[Unit] +Description=Reaktor for user %i +After=network.target nss-lookup.target + +[Service] +Type=normal +#TODO - make reaktor path variable +User=reaktor +ExecStart=/krebs/painload/Reaktor/index +Restart=always +RestartSec=3 + +[Install] +WantedBy=multi-user.target diff --git a/Reaktor/index b/Reaktor/index index ac647ca3..fc59cd73 100755 --- a/Reaktor/index +++ b/Reaktor/index @@ -4,4 +4,4 @@ set -euf # cd //Reaktor cd $(dirname $(readlink -f $0)) -exec IRC/index +exec IRC/index "$@" diff --git a/Reaktor/repos/view-website b/Reaktor/repos/view-website new file mode 160000 +Subproject a3892837aabd5d95e997c0fd2526096f685669f diff --git a/Reaktor/repos/whatweb b/Reaktor/repos/whatweb -Subproject 0918a0d9b75df77f9c3e9eb360b6b22824582a2 +Subproject 362145cf80ccd82d4c32e15b37eeff745e0ba66 diff --git a/Reaktor/titlebot/commands/clear b/Reaktor/titlebot/commands/clear new file mode 100755 index 00000000..e3558194 --- /dev/null +++ b/Reaktor/titlebot/commands/clear @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +import json +from os import environ +import sys +import os +# krebs polling +import poll + +f = 'suggestions.json' +title=" ".join(sys.argv[1:]) +db = poll.save_db(f,[]) +print("cleared database") diff --git a/Reaktor/titlebot/commands/down b/Reaktor/titlebot/commands/down new file mode 100755 index 00000000..8964382d --- /dev/null +++ b/Reaktor/titlebot/commands/down @@ -0,0 +1,2 @@ +#!/bin/sh +echo "not implemented" diff --git a/Reaktor/titlebot/commands/help b/Reaktor/titlebot/commands/help new file mode 100755 index 00000000..f04e43b7 --- /dev/null +++ b/Reaktor/titlebot/commands/help @@ -0,0 +1,11 @@ +#!/bin/sh +cat <<EOF +BGT Title Poll Bot: + .new TITLE - suggest a new title + .list <(age|votes)> - list all suggestions + .highest <NUM> - lists the NUM highest voted suggestions + .up NUM (NUM ...) - upvote one or more suggestions from .list + .undo NUM (NUM ...) - undo an upvote + .clear - clear the poll (auth required) +EOF + diff --git a/Reaktor/titlebot/commands/highest b/Reaktor/titlebot/commands/highest new file mode 100755 index 00000000..d0408ac0 --- /dev/null +++ b/Reaktor/titlebot/commands/highest @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import json +from os import environ +import sys +import os +import poll + +f = 'suggestions.json' +title=" ".join(sys.argv[1:]) +db = poll.load_db(f) +# only print the last N values (default 1) +limit = int(sys.argv[1]) if len(sys.argv) > 1 else 1 +num = 0 +last_vote = 9001 +# stolen from http://stackoverflow.com/questions/9647202/ordinal-numbers-replacement +suffixes = ["th", "st", "nd", "rd", ] + ["th"] * 16 + +for entry in poll.sort_by_votes(db): + # if two entries have the same number of upvotes, do not increment the rank + current_vote = sum(entry['votes'].values()) + if current_vote < last_vote: + num = num + 1 + last_vote = current_vote + # exit if we are above the limit + if num > limit: + sys.exit(0) + + suffixed_num = str(num) + suffixes[num % 100] + print("%s: '%s' (%d votes)" % + (suffixed_num,entry['title'],sum(entry['votes'].values()))) diff --git a/Reaktor/titlebot/commands/list b/Reaktor/titlebot/commands/list new file mode 100755 index 00000000..cee4b8a8 --- /dev/null +++ b/Reaktor/titlebot/commands/list @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +import json +from os import environ +import sys +import os +import poll + +f = 'suggestions.json' +title=" ".join(sys.argv[1:]) +db = poll.load_db(f) +if len(sys.argv) > 1 and ("-h" in sys.argv[1] or "usage" == sys.argv[1]): + print("""usage: list <(age|votes)> + sort by age or by votes (default: age) +""") + sys.exit(0) + +if len(sys.argv) > 1 and ("votes" in sys.argv[1]): + use = poll.sort_by_votes(db) +elif len(sys.argv) > 1 and ("age" in sys.argv[1]) or len(sys.argv) == 1: + use = db +else: + print("unknown sorting method") + sys.exit(1) + +for entry in use: + print("#%d %s (votes: %d)" % + (db.index(entry),entry['title'],sum(entry['votes'].values()))) diff --git a/Reaktor/titlebot/commands/new b/Reaktor/titlebot/commands/new new file mode 100755 index 00000000..7246a2b2 --- /dev/null +++ b/Reaktor/titlebot/commands/new @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +import json +from os import environ +import sys +import os +# krebs polling +import poll + +f = 'suggestions.json' +title=" ".join(sys.argv[1:]) +db = poll.load_db(f) + +suggester = environ['_from'] +if not poll.title_in_db(title,db): + db.append( { 'by': suggester, + 'votes':{},'title': title}) + print("Thank you for your suggestion '%s'!"%environ["_from"]) + print("To vote type '.up %d'"%(len(db)-1)) +poll.save_db(f,db) diff --git a/Reaktor/titlebot/commands/poll.py b/Reaktor/titlebot/commands/poll.py new file mode 100644 index 00000000..595ab269 --- /dev/null +++ b/Reaktor/titlebot/commands/poll.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +import json +def load_db(f): + try: + with open(f) as fl: + return json.load(fl) + except: + #default db is [] + return [] + +def title_in_db(t,d): + for index,entry in enumerate(d): + if t == entry['title']: + print("Title is already in list.") + print("To vote for this type '.up %d'" %index) + return True + return False +def save_db(f,db): + with open(f,"w") as x: + json.dump(db,x) + +def sort_by_votes(db): + return sorted(db,key=lambda entry:sum(entry['votes'].values()),reverse=True) diff --git a/Reaktor/titlebot/commands/undo b/Reaktor/titlebot/commands/undo new file mode 100755 index 00000000..a66de67f --- /dev/null +++ b/Reaktor/titlebot/commands/undo @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +import json +from os import environ +import sys +import os +# krebs polling +import poll + +f = 'suggestions.json' +db = poll.load_db(f) +votes = [] +try: + votes = sys.argv[1:] +except: + print("""usage: undo number (...) + undos vote of one or more entries based on .list""") + sys.exit(1) +voter = environ['_prefix'] +voter_name = environ['_from'] +for vote in votes: + try: + vote = int(vote) + if not voter in db[vote]['votes']: + print("%s, you never voted for '%s'!"%(voter_name,db[vote]['title'])) + else: + del(db[vote]['votes'][voter] ) + print("%s undid vote for '%s'" %(voter_name,db[vote]['title'] )) + except: + print("%s undo voting for #%d failed" %(voter_name,vote)) + +poll.save_db(f,db) diff --git a/Reaktor/titlebot/commands/up b/Reaktor/titlebot/commands/up new file mode 100755 index 00000000..0a48bdb0 --- /dev/null +++ b/Reaktor/titlebot/commands/up @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +import json +from os import environ +import sys +import os +# krebs polling +import poll + +f = 'suggestions.json' +db = poll.load_db(f) +votes = [] +votes = sys.argv[1:] +if not votes: + print("""usage: up number (...) + upvotes one or more entries based on .list""") + sys.exit(1) + +voter = environ['_prefix'] +voter_name =environ['_from'] +for vote in votes: + try: + vote = int(vote) + if vote < 0: + raise Exception() + if voter in db[vote]['votes']: + print("%s, you already have voted for '%s'"%(voter_name,db[vote]['title']) ) + else: + db[vote]['votes'][voter] = 1 + print("%s voted for '%s'"%(voter_name,db[vote]['title'])) + except: + print("%s, voting for #%s failed" %(voter_name,vote)) + +poll.save_db(f,db) diff --git a/Reaktor/titlebot/titlebot.py b/Reaktor/titlebot/titlebot.py new file mode 100644 index 00000000..c1eac3b0 --- /dev/null +++ b/Reaktor/titlebot/titlebot.py @@ -0,0 +1,77 @@ +from os import environ,mkdir +from os.path import abspath, expanduser +import re +debug = False + +# CAVEAT name should not contains regex magic +name = 'bgt_titlebot' + +workdir = '/tmp/state' + +try: + mkdir(workdir) +except: pass + +irc_alarm_timeout = 300 +irc_hammer_interval = 10 +irc_kill_timeout = 360 +irc_nickname = name +irc_server = 'irc.freenode.org' +irc_port = 6667 +irc_restart_timeout = 5 +irc_channels = [ + '#binaergewitter' +] +admin_file=workdir+'/admin.lst' +auth_file=workdir+'/auth.lst' + +config_filename = abspath(__file__) + +try: + with open(admin_file,"x"): pass +except: pass + +# me is used, so name cannot kill our patterns below +me = '\\b' + re.escape(name) + '\\b' +me_or_us = '(?:' + me + '|\\*)' + +def default_command(cmd, env=None): + if not env: env = {} + return { + 'capname': cmd, + 'pattern': '^' + me_or_us + ':\\s*' + cmd + '\\s*(?:\\s+(?P<args>.*))?$', + 'argv': [ 'commands/' + cmd ], + 'env': env + } +def titlebot_cmd(cmd): + return { + 'capname': cmd, + 'pattern': '^\\.' + cmd + '\\s*(?:\\s+(?P<args>.*))?$', + 'argv': [ 'titlebot/commands/' + cmd ] } + +public_commands = [ + default_command('caps', env={ + 'config_filename': config_filename + }), + default_command('hello'), + default_command('badcommand'), + default_command('rev'), + default_command('uptime'), + default_command('nocommand'), + titlebot_cmd('list'), + titlebot_cmd('help'), + titlebot_cmd('highest'), + titlebot_cmd('up'), + titlebot_cmd('new'), + titlebot_cmd('undo'), + titlebot_cmd('down'), + # identify via direct connect + { 'capname': 'identify', + 'pattern': '^identify' + '\\s*(?:\\s+(?P<args>.*))?$', + 'argv' : [ 'commands/identify' ]} +] +commands = [ + default_command('reload'), + titlebot_cmd('clear') +] + |