Below is a basic IRC bot written in python which grabs the builder bot statuses from the arm.koji website and sends a message to a channel if the enable or ready statuses change to “no”. The lbot.py code is a shared python library/module and various python bot scripts can use this module to achieve different tasks for IRC messaging/action.
Edit: Last updated on June 30, 2011
lbot.py
import os
import re
import signal
import select
import socket
import sys
import time
import urllib
def formtime():
currsecs = time.localtime()
return time.strftime("%H:%M:%S", currsecs)
def fakehand(s, f):
pass
def readurls(urlnlist=[], filename="lbot.txt"):
waittime = (5 * 60)
while (1):
outpstri = ""
for urlnitem in urlnlist:
signal.signal(signal.SIGALRM, fakehand)
signal.alarm(waittime / 2)
try:
uobjdata = urllib.urlopen(urlnitem)
tempstri = uobjdata.read()
print("fetched [%d] bytes from [%s]" % (len(tempstri), urlnitem))
except:
outpstri = ""
break
outpstri += tempstri
signal.alarm(0)
if (outpstri):
fileobjc = open("/tmp/%s" % (filename), "w")
fileobjc.write(outpstri)
fileobjc.close()
time.sleep(waittime)
sockline_s = {}
def sockline(sockpref, sockobjc):
global sockline_s
if (not sockpref in sockline_s.keys()):
sockline_s[sockpref] = ""
timeread = 0.25
chekstri = sockline_s[sockpref].find("\n")
while (chekstri == -1):
(readlist, sendlist, errolist) = select.select([sockobjc], [], [], timeread)
if (sockobjc in readlist):
tempread = sockobjc.recv(1024)
if (len(tempread) == 0):
print("socket error...")
sys.exit(0)
sockline_s[sockpref] += tempread
chekstri = sockline_s[sockpref].find("\n")
else:
break
chekstri += 1
reslstri = sockline_s[sockpref][:chekstri]
sockline_s[sockpref] = sockline_s[sockpref][chekstri:]
if ((len(reslstri) > 0) and (sockpref != "")):
outpstri = ("%s %s [RECV] %s" % (formtime(), sockpref, reslstri.strip()))
print(outpstri)
return reslstri
sockobjc = None
def socksend(sockpref, sendstri):
global sockobjc
tempstri = sendstri.strip()
if ((len(tempstri) > 0) and (sockpref != "")):
outpstri = ("%s %s [SEND] %s" % (formtime(), sockpref, tempstri))
print(outpstri)
sockobjc.send(sendstri + "\r\n")
sendtime = 0
sendwait = 1
sockpref = "IRC"
sendlist = []
def waitsend(sendstri=""):
global sockobjc
global sendtime
global sendwait
global sockpref
global sendlist
if (sendstri != ""):
sendlist.append(sendstri)
if (len(sendlist) > 0):
prestime = time.time()
difftime = (prestime - sendtime)
if (difftime >= sendwait):
socksend(sockpref, sendlist[0])
sendlist.pop(0)
sendtime = prestime
nickname = ""
chanblst = []
def ircbinit(nickstri, chanlist):
global sockobjc
global sockpref
global nickname
global chanblst
hostname = "irc.freenode.net"
hostport = 6667
idenname = "alex"
fillname = "bob"
realname = "charlie"
nickname = nickstri
chanblst = chanlist
sockobjc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockobjc.connect((hostname, hostport))
socksend(sockpref, "NICK %s" % (nickname))
socksend(sockpref, "USER %s %s %s :%s" % (idenname, hostname, fillname, realname))
jointime = 0
joinwait = (5 * 60)
def ircbmain(pastdata, presdata):
global sockpref
global sockobjc
global nickname
global chanblst
global jointime
global joinwait
# check for a valid socket object first
if (sockobjc == None):
print("null error...")
return -1
# set some shared method vars
prestime = time.time()
# read a line from the socket object and exit if error
readdata = sockline(sockpref, sockobjc)
waitsend()
if (type(readdata) == type(-1)):
sockobjc.close()
print("socket error...")
return -2
readdata = readdata.strip()
# if server ping the send pong back
chekstri = readdata.find("PING :")
if (chekstri == 0):
chekstri = readdata.find(":")
sendstri = ("PONG %s" % (readdata[chekstri:]))
socksend(sockpref, sendstri)
readdata = ""
# delay send the join channel commands if connect or time
chekstri = readdata.find("001 %s" % (nickname))
difftime = (prestime - jointime)
if ((chekstri != -1) or ((jointime != 0) and (difftime > joinwait))):
for channame in chanblst:
sendstri = ("JOIN %s" % (channame))
waitsend(sendstri)
jointime = prestime
readdata = ""
# check to see if we successfuly joined at least one channel
regxobjc = re.match("^:?%s[^ ]* JOIN :.*" % (nickname), readdata)
if (regxobjc):
jointime = prestime
readdata = ""
# if we have not joined a channel yet then return
if ((jointime == 0) or (not pastdata) or (not presdata)):
return readdata
# if list size was requested then send the length of the list
regxobjc = re.match("^:?[^ ]* PRIVMSG ([^ ]*) :%s numb.*" % (nickname), readdata)
if (regxobjc):
sendstri = ("PRIVMSG %s :[#] %d" % (regxobjc.group(1), len(presdata)))
socksend(sockpref, sendstri)
# if a list tail was requested then send the specified number of items
regxobjc = re.match("^:?[^ ]* PRIVMSG ([^ ]*) :%s tail(.*)" % (nickname), readdata)
if (regxobjc):
try:
tailnumb = regxobjc.group(2).strip()
tailnumb = (-1 * int(tailnumb))
except:
tailnumb = -1
for presitem in presdata[tailnumb:]:
sendstri = ("PRIVMSG %s :[*] %s" % (regxobjc.group(1), presitem))
waitsend(sendstri)
# print out any list diffs
for presitem in presdata:
if (presitem in pastdata):
continue
for channame in chanblst:
sendstri = ("PRIVMSG %s :[+] %s" % (channame, presitem))
waitsend(sendstri)
return readdata
sbot.py
import os
import re
import sys
import time
import lbot
def fechfile(filename, urlnstri=""):
resllist = []
try:
fileobjc = file("/tmp/%s" % (filename))
readdata = fileobjc.read()
fileobjc.close()
except:
return resllist
readdata = readdata.replace("\t", "").replace("\r", "").replace("\n", "")
readdata = readdata.replace("<tr", "\n<tr")
readlist = readdata.split("\n")
for readitem in readlist:
regxobjc = re.match(".*<a href=\"hostinfo\?hostID=[0-9]*\">([^<]*cdot[^<]*)</a>.*<td>([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)</td>.*", readitem)
if (not regxobjc):
continue
hostname = regxobjc.group(1)
edthour = (int(regxobjc.group(5)) - 4)
edthour = str(edthour)
checkind = int(regxobjc.group(2) + regxobjc.group(3) + regxobjc.group(4) + regxobjc.group(5) + regxobjc.group(6))
timesecs = (time.time() + (4 * 60 * 60) - (30 * 60))
locltime = time.localtime(timesecs)
presdate = int(time.strftime("%Y%m%d%H%M", locltime))
if (checkind < presdate):
hoststri = ("[%s] last check-in [%s-%s-%s %s:%s:%s]" % (hostname, regxobjc.group(2), regxobjc.group(3), regxobjc.group(4), edthour, regxobjc.group(6), regxobjc.group(7)))
resllist.append(hoststri)
return resllist
def ircbmain():
if (len(sys.argv) < 4):
print("Usage: %s <nick> - <chan 0> ... <chan N>" % (sys.argv[0]))
sys.exit(0)
nickname = ""
chanlist = []
x = 1
l = len(sys.argv)
f = 0
while (x < l):
if (sys.argv[x] == "-"):
f += 1
elif (f == 0):
nickname = sys.argv[x]
elif (f == 1):
chanlist.append(sys.argv[x])
x += 1
p = os.fork()
if (p == 0):
templist = []
for x in range(0, 3):
templist.append("http://arm.koji.fedoraproject.org/koji/hosts?state=all&order=name&start=%d" % (x * 50))
lbot.readurls(urlnlist=templist, filename=nickname)
sys.exit(0)
pastdata = []
presdata = []
lbot.ircbinit(nickname, chanlist)
while (1):
tempdata = fechfile(nickname)
if (tempdata):
presdata = tempdata
if (not pastdata):
pastdata = presdata
ircdstri = lbot.ircbmain(pastdata, presdata)
if (type(ircdstri) == type(-1)):
break
if (presdata):
pastdata = presdata
ircbmain()