@@ -1,92 +0,0 @@ | |||||
# -*- coding: utf-8 -*- | |||||
import string, re, subprocess | |||||
from config.irc_config import * | |||||
s, send, say, action, notice, join = None, None, None, None, None, None | |||||
def check_triggers(cmds, act, nick, ident, host, chan, msg = None): | |||||
global s, send, say, action, notice, join # set commands as globals so we can use them in other functions | |||||
s, send, say, action, notice, join = cmds # unpack commands | |||||
if act == "join": | |||||
pass | |||||
if act == "msg_private": | |||||
pass | |||||
if act == "msg_public": | |||||
pass | |||||
if act == "msg": | |||||
if msg == "!test": | |||||
cmd_test(nick, chan) | |||||
if msg.startswith("!git"): | |||||
cmd_git(nick, host, chan, msg) | |||||
def get_args(msg): # get command arguments | |||||
args = msg.strip().split(' ') # strip out extra whitespace and split the message into a list | |||||
while '' in args: # remove any empty arguments | |||||
args.remove('') | |||||
return args[1:] # remove the command itself | |||||
def cmd_test(nick, chan): # bot test | |||||
say(chan, "Hey \x02%s\x0F!" % nick) | |||||
def cmd_git(nick, host, chan, msg): # commands to interface with the bot's git repository | |||||
if host not in ADMINS: | |||||
say(chan, "\x02%s\x0F: you must be a bot admin to use this command." % nick) | |||||
return | |||||
args = get_args(msg) | |||||
if not args: | |||||
say(chan, "\x02%s\x0F: no arguments provided." % nick) | |||||
return | |||||
if args[0] == "help": # display all commands | |||||
cmds = ["\x0303branch\x0301 (show current branch)", "\x0303branches\x0301 (show all branches)", | |||||
"\x0303checkout\x0301 (switch branches)", "\x0303pull\x0301 (update current branch)"] | |||||
cmds = ', '.join(cmds) | |||||
say(chan, "\x02%s\x0F: sub-commands are: %s" % (nick, cmds)) | |||||
elif args[0] == "branch": # get our current branch | |||||
branch = subprocess.check_output(['git', 'name-rev', '--name-only', 'HEAD'], stderr=subprocess.STDOUT) # git name-rev --name-only HEAD | |||||
branch = branch[:-1] # strip newline | |||||
say(chan, "\x02%s\x0F: currently on branch \x0302%s\x0301." % (nick, branch)) | |||||
elif args[0] == "branches": # get list of branches | |||||
branches = subprocess.check_output(['git', 'branch'], stderr=subprocess.STDOUT) # git branch | |||||
branches = branches[:-1] # strip newline | |||||
branches = branches.replace('\n* ', ', ') # cleanup extraneous characters | |||||
branches = branches.replace('* ', ' ') | |||||
branches = branches.replace('\n ', ', ') | |||||
branches = branches.strip() | |||||
say(chan, "\x02%s\x0F: branches: \x0302%s\x0301." % (nick, branches)) | |||||
elif args[0] == "checkout": # switch branches | |||||
try: | |||||
branch = args[1] | |||||
except IndexError: # no branch name provided | |||||
say(chan, "\x02%s\x0F: switch to which branch?" % nick) | |||||
return | |||||
try: | |||||
result = subprocess.check_output(['git', 'checkout', branch], stderr=subprocess.STDOUT) # git checkout our_branch | |||||
if "Already on" in result: | |||||
say(chan, "\x02%s\x0F: already on \x0302%s\x0301!" % (nick, branch)) | |||||
else: | |||||
say(chan, "\x02%s\x0F: switched to branch \x0302%s\x0301." % (nick, branch)) | |||||
except subprocess.CalledProcessError: # git couldn't switch branches | |||||
say(chan, "\x02%s\x0F: branch \x0302%s\x0301 does not exist!" % (nick, branch)) | |||||
elif args[0] == "pull": # pull from remote repository | |||||
branch = subprocess.check_output(['git', 'name-rev', '--name-only', 'HEAD'], stderr=subprocess.STDOUT) # git name-rev --name-only HEAD | |||||
branch = branch[:-1] # strip newline | |||||
say(chan, "\x02%s\x0F: pulling from remote (currently on \x0302%s\x0301)..." % (nick, branch)) | |||||
result = subprocess.check_output(['git', 'pull']) # pull from remote | |||||
if "Already up-to-date." in result: | |||||
say(chan, "\x02%s\x0F: done; no new changes." % nick) | |||||
else: | |||||
say(chan, "\x02%s\x0F: done; new changes merged." % nick) | |||||
else: | |||||
say(chan, "\x02%s\x0F: unknown argument: \x0303%s\x0301." % (nick, args[0])) |
@@ -2,73 +2,62 @@ | |||||
## Imports | ## Imports | ||||
import socket, string, re | import socket, string, re | ||||
from actions import * | |||||
from config.irc_config import * | from config.irc_config import * | ||||
from config.secure_config import * | from config.secure_config import * | ||||
def send(msg): # send a message 'msg' to the server | |||||
s.send(msg + "\r\n") | |||||
print " %s" % msg | |||||
def say(target, msg): # send a private message 'msg' to 'target' | |||||
send("PRIVMSG %s :%s" % (target, msg)) | |||||
def action(target, msg): # send a message as an action | |||||
say(target,"%sACTION %s%s" % (chr(1), msg, chr(1))) | |||||
def notice(target, msg): # send a notice 'msg' to 'target' | |||||
send("NOTICE %s :%s" % (target, msg)) | |||||
def join(chan): # join channel 'chan' | |||||
send("JOIN %s" % chan) | |||||
cmds = (s, send, say, action, notice, join) # pack up commands | |||||
from irc import triggers | |||||
from irc.actions import * | |||||
from irc.data import * | |||||
def main(): | def main(): | ||||
readbuffer = str() | |||||
data = [s, send, say, notice, join] | |||||
read_buffer = str() | |||||
while 1: | while 1: | ||||
readbuffer = readbuffer + s.recv(1024) | |||||
temp = string.split(readbuffer, "\n") | |||||
readbuffer = temp.pop() | |||||
read_buffer = read_buffer + actions.sock.recv(1024) | |||||
temp = string.split(read_buffer, "\n") | |||||
read_buffer = temp.pop() | |||||
for line in temp: | for line in temp: | ||||
line2 = string.split(string.rstrip(line)) | |||||
line = string.split(string.rstrip(line)) | |||||
data = Data() | |||||
if line2[1] == "JOIN": | |||||
nick, ident, host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line2[0])[0] | |||||
chan = line2[2][1:] | |||||
if line[1] == "JOIN": | |||||
data.nick, data.ident, data.host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||||
data.chan = line[2][1:] | |||||
check_triggers(cmds, "join", nick, ident, host, chan) # check if there's anything we can respond to, and if so, respond | |||||
triggers.check(actions, data, "join") # check if there's anything we can respond to, and if so, respond | |||||
if line2[1] == "PRIVMSG": | |||||
nick, ident, host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line2[0])[0] | |||||
msg = ' '.join(line2[3:])[1:] | |||||
chan = line2[2] | |||||
if line[1] == "PRIVMSG": | |||||
data.nick, data.ident, data.host = re.findall(":(.*?)!(.*?)@(.*?)\Z", line[0])[0] | |||||
data.msg = ' '.join(line[3:])[1:] | |||||
data.chan = line[2] | |||||
if chan == NICK: # if line2[2] is us, this is a privmsg to us, so set 'chan' as the nick of the sender | |||||
chan = nick | |||||
check_triggers(cmds, "msg_private", nick, ident, host, chan, msg) # only respond if it's a private message | |||||
if data.chan == NICK: # this is a privmsg to us, so set 'chan' as the nick of the sender | |||||
data.chan = data.nick | |||||
triggers.check(actions, data, "msg_private") # only respond if it's a private message | |||||
else: | else: | ||||
check_triggers(cmds, "msg_public", nick, ident, host, chan, msg) # only respond if it's a public (channel) message | |||||
triggers.check(actions, data, "msg_public") # only respond if it's a public (channel) message | |||||
check_triggers(cmds, "msg", nick, ident, host, chan, msg) # check for general messages | |||||
triggers.check(actions, data, "msg") # check for general messages | |||||
if msg == "!restart": # hardcode the !restart command (we can't return from within actions.py) | |||||
if host in ADMINS: | |||||
if data.msg == "!restart": # hardcode the !restart command (we can't return from within actions.py) | |||||
if data.host in ADMINS: | |||||
return True | return True | ||||
if line2[0] == "PING": # If we are pinged, pong back to the server | |||||
send("PONG %s" % line2[1]) | |||||
if line[0] == "PING": # If we are pinged, pong back to the server | |||||
actions.send("PONG %s" % line[1]) | |||||
if line2[1] == "376": | |||||
if NS_AUTH: | |||||
say("NickServ", "IDENTIFY %s %s" % (NS_USER, NS_PASS)) | |||||
for this_chan in CHANS: # join all of our startup channels | |||||
join(this_chan) | |||||
if line[1] == "376": | |||||
if NS_AUTH: # if we're supposed to auth to nickserv, do that | |||||
actions.say("NickServ", "IDENTIFY %s %s" % (NS_USER, NS_PASS)) | |||||
for chan in CHANS: # join all of our startup channels | |||||
actions.join(chan) | |||||
if __name__ == "__main__": | if __name__ == "__main__": | ||||
s = socket.socket() | |||||
s.connect((HOST, PORT)) | |||||
send("NICK %s" % NICK) | |||||
send("USER %s %s bla :%s" % (IDENT, HOST, REALNAME)) | |||||
sock = socket.socket() | |||||
sock.connect((HOST, PORT)) | |||||
actions = Actions(sock) | |||||
actions.send("NICK %s" % NICK) | |||||
actions.send("USER %s %s bla :%s" % (IDENT, HOST, REALNAME)) | |||||
main() | main() |
@@ -0,0 +1,29 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Actions/commands to interface with IRC. | |||||
class Actions: | |||||
def __init__(self, sock): | |||||
"""actions/commands to interface with IRC""" | |||||
self.sock = sock | |||||
def send(self, msg): | |||||
"""send data to the server""" | |||||
self.sock.send(msg + "\r\n") | |||||
print " %s" % msg | |||||
def say(self, target, msg): | |||||
"""send a message""" | |||||
self.send("PRIVMSG %s :%s" % (target, msg)) | |||||
def action(self, target, msg): | |||||
"""send a message as an action""" | |||||
self.say(target,"%sACTION %s%s" % (chr(1), msg, chr(1))) | |||||
def notice(self, target, msg): | |||||
"""send a notice""" | |||||
self.send("NOTICE %s :%s" % (target, msg)) | |||||
def join(self, chan): | |||||
"""join a channel""" | |||||
self.send("JOIN %s" % chan) |
@@ -0,0 +1,12 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# A class to store data from an individual line received on IRC. | |||||
class Data: | |||||
def __init__(self): | |||||
"""store data from an individual line received on IRC""" | |||||
self.chan = None | |||||
self.nick = None | |||||
self.ident = None | |||||
self.host = None | |||||
self.msg = None |
@@ -0,0 +1,127 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Commands to interface with the bot's git repository. | |||||
import shlex, subprocess | |||||
from config.irc_config import * | |||||
actions, data = None, None | |||||
args = None | |||||
def call(a, d): | |||||
global actions, data | |||||
actions, data = a, d | |||||
if not check_user_is_admin(): | |||||
return | |||||
args = get_args() | |||||
if not check_has_args(): | |||||
return | |||||
if args[0] == "help": | |||||
do_help() | |||||
elif args[0] == "branch": | |||||
do_branch() | |||||
elif args[0] == "branches": | |||||
do_branches() | |||||
elif args[0] == "checkout": | |||||
do_checkout() | |||||
elif args[0] == "pull": | |||||
do_pull() | |||||
else: | |||||
unknown_arg() # they asked us to do something we don't know | |||||
def get_args(): | |||||
"""get command arguments""" | |||||
args = data.msg.strip().split(' ') # strip out extra whitespace and split the message into a list | |||||
while '' in args: # remove any empty arguments | |||||
args.remove('') | |||||
return args[1:] # remove the command itself | |||||
def check_user_is_admin(): | |||||
"""check if the user is a bot admin (and can use this command, as a result)""" | |||||
if data.host not in ADMINS: | |||||
actions.say(data.chan, "\x02%s\x0F: you must be a bot admin to use this command." % data.nick) | |||||
return False | |||||
return True | |||||
def check_has_args(): | |||||
"""check if they provided arguments along with the !git command""" | |||||
if not args: | |||||
actions.say(data.chan, "\x02%s\x0F: no arguments provided." % data.nick) | |||||
return False | |||||
return True | |||||
def exec_shell(command): | |||||
"""execute a shell command and get the output""" | |||||
command = shlex.split(command) | |||||
result = subprocess.check_output(command, stderr=subprocess.STDOUT) | |||||
return result | |||||
def do_help(): | |||||
"""display all commands""" | |||||
help = ["\x0303branch\x0301 (show current branch)", "\x0303branches\x0301 (show all branches)", | |||||
"\x0303checkout\x0301 (switch branches)", "\x0303pull\x0301 (update current branch)"] | |||||
help = ', '.join(help) | |||||
actions.say(data.chan, "\x02%s\x0F: sub-commands are: %s" % (data.nick, help)) | |||||
def do_branch(): | |||||
"""get our current branch""" | |||||
branch = exec_shell("git name-rev --name-only HEAD") | |||||
branch = branch[:-1] # strip newline | |||||
actions.say(data.chan, "\x02%s\x0F: currently on branch \x0302%s\x0301." % (data.nick, branch)) | |||||
def do_branches(): | |||||
"""get list of branches""" | |||||
branches = exec_shell("git branch") | |||||
branches = branches[:-1] # strip newline | |||||
branches = branches.replace('\n* ', ', ') # cleanup extraneous characters | |||||
branches = branches.replace('* ', ' ') | |||||
branches = branches.replace('\n ', ', ') | |||||
branches = branches.strip() | |||||
actions.say(data.chan, "\x02%s\x0F: branches: \x0302%s\x0301." % (data.nick, branches)) | |||||
def do_checkout(): | |||||
"""switch branches""" | |||||
try: | |||||
branch = args[1] | |||||
except IndexError: # no branch name provided | |||||
actions.say(chan, "\x02%s\x0F: switch to which branch?" % data.nick) | |||||
return | |||||
try: | |||||
result = exec_shell("git checkout %s" % branch) | |||||
if "Already on" in result: | |||||
actions.say(data.chan, "\x02%s\x0F: already on \x0302%s\x0301!" % (data.nick, branch)) | |||||
else: | |||||
actions.say(data.chan, "\x02%s\x0F: switched to branch \x0302%s\x0301." % (data.nick, branch)) | |||||
except subprocess.CalledProcessError: # git couldn't switch branches | |||||
actions.say(data.chan, "\x02%s\x0F: branch \x0302%s\x0301 does not exist!" % (data.nick, branch)) | |||||
def do_pull(): | |||||
"""pull from remote repository""" | |||||
branch = exec_shell("git name-rev --name-only HEAD") | |||||
branch = branch[:-1] # strip newline | |||||
actions.say(data.chan, "\x02%s\x0F: pulling from remote (currently on \x0302%s\x0301)..." % (data.nick, branch)) | |||||
result = exec_shell("git pull") | |||||
if "Already up-to-date." in result: | |||||
actions.say(data.chan, "\x02%s\x0F: done; no new changes." % data.nick) | |||||
else: | |||||
actions.say(data.chan, "\x02%s\x0F: done; new changes merged." % data.nick) | |||||
def unknown_arg(): | |||||
actions.say(data.chan, "\x02%s\x0F: unknown argument: \x0303%s\x0301." % (data.nick, args[0])) |
@@ -0,0 +1,20 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# A simple command to test the bot. | |||||
import random | |||||
actions, data = None, None | |||||
def call(a, d): | |||||
global actions, data | |||||
actions, data = a, d | |||||
choices = ("say_hi()", "say_sup()") | |||||
exec random.choice(choices) | |||||
def say_hi(): | |||||
actions.say(data.chan, "Hey \x02%s\x0F!" % data.nick) | |||||
def say_sup(): | |||||
actions.say(data.chan, "'sup \x02%s\x0F?" % data.nick) |
@@ -0,0 +1,21 @@ | |||||
# -*- coding: utf-8 -*- | |||||
# Check what events on IRC we can respond to. | |||||
from irc.commands import test, git | |||||
def check(actions, data, hook): | |||||
if hook == "join": | |||||
pass | |||||
if hook == "msg_private": | |||||
pass | |||||
if hook == "msg_public": | |||||
pass | |||||
if hook == "msg": | |||||
if data.msg == "!test": | |||||
test.call(actions, data) | |||||
if data.msg.startswith("!git"): | |||||
git.call(actions, data) |