A CDoT Python IRC Bot

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()

Sending An SSH Key To Multiple SSH Hosts

The script below will first create an SSH public/private key pair on the current, main host. It will then get your username and prompt for your password allowing the root user to add your account to the destination servers. Note: you must have a root login on each host. The ping statement is used to check to see if the host is up so we don’t waste time. This script will then wait on stdin (via cat with no arguments) and write the ssh key-file (via the piped data) to the temp directory. It will then add the username, set the password, create a ssh directory and move the transferred key file to it. At the end, it will then give ownership to the specified username.

#!/bin/bash

ssh-keygen

u=`whoami`
read -s -p "Password: " pass

for x in {1..7}-{1..5}
do
	ping -c 1 -W 1 $x > /dev/null 2>&1
	if [ $? -eq 0 ]
	then
		tempkeyf='cat > /tmp/authorized_keys'
		makeuser='useradd '$u
		makepass='printf "'$pass'" | passwd --stdin '$u
		makesshd='mkdir /home/'$u'/.ssh'
		copykeyf='mv /tmp/authorized_keys /home/'$u'/.ssh/'
		ownevery='chown -R '$u' /home/'$u'/.ssh'
		cat ~/.ssh/id_rsa.pub | ssh root@$x "$tempkeyf ; $makeuser ; $makepass ; $makesshd ; $copykeyf ; $ownevery"
	fi
done

First post!

Just created a new wordpress account for my blog while working for Seneca@York CDoT department. I will be working on compiling software packages for Fedora on the ARM architecture. This should be fun! If I come across any interesting scripting/coding/programming challenges, I will open-source it here or on the wiki if necessary.