User:WdefconBot

This bot's IRC companion sits in the #vandalism-en-wp channel and uses this account to edit Wdefcon on request made in the channel.

Archived approval of the bot is available at Bots/Requests for approvals/Archive4

Source
This is the bot's source code. It assumes that the file lies in the pywikipedia/ directory (an already logged-in pywikipedia framework is required to work) and is executed from there. To adjust the configuration, modify constants specified at the end of file.


 * 1) !/usr/bin/env python

import re, socket, time, wikipedia

class WdefconBot: def __init__(self): self.LASTLEVEL = '0' self.LASTEDITED = 0 self.LOGfile = open('defbotlog.txt', 'a+') self.site = wikipedia.getSite self.IRC = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

def log(self,nick,text): TIME = time.gmtime self.LOGfile.write("[%04d-%02d-%02d %02d:%02d.%02d] (%s) :%s\n" % (TIME[0:6] + (nick, text))) self.LOGfile.flush

def irc_conn(self,server,port): self.IRC.connect((server,port))

def login(self,nickname, password, username, realname, hostname='hostname', servername='server'): self.IRC.send("PASS %s\n" % password) self.IRC.send("USER %s %s %s :%s\n" % (username, hostname, servername, realname)) self.IRC.send("NICK %s\n" % nickname) self.nick = nickname

def join(self,channel): self.IRC.send("JOIN %s\n" % channel) self.channel = channel

def do_say(self,target,text): self.IRC.send("PRIVMSG %s :%s\n" % (target, text))

def do_ctcp(self,target,text): self.IRC.send("PRIVMSG %s :\001%s\001\n" % (target, text))

def user_access(self,hostmask): asteriskRE = re.compile('\*') for mask in ACCESSLIST.keys: maskRE = re.compile(asteriskRE.sub('.*?',mask)) if maskRE.match(hostmask): return ACCESSLIST[mask] return 0

def get_defcon(self): wdefcon = wikipedia.Page(self.site,"Template:Wdefcon") text = wdefcon.get p = text.find('\n|level=') if p == -1: return ("-1",""); p1 = text.find('\n|info=') p2 = text.find('\n|align=') if p1 == -1 or p2 == -1: return (text[p+8], "Unknown. Template damaged?") info = text[p1+7:p2] info = re.compile('\n||<.+?>').sub('',info) info = re.compile('\[\[[^\|]*\|(.*)\]\]').sub(r'\1',info)   info = re.compile('\[\[([^\|]*?)\]\]').sub(r'\1',info)    return (text[p+8],info)

def do_defcon_check(self,force): defcon = self.get_defcon if defcon[0] == self.LASTLEVEL and force == 0: return self.log("WdefconBot","Wdefcon level is %s and the description is: %s" % defcon) self.LASTLEVEL = defcon[0] if defcon[0] == -1: self.do_say(self.channel,"Error while retrieving level! Template vandalised?") else: self.do_say(self.channel,"The current WikiDefcon level is %s and the description is: %s" % defcon)

def main_loop(self): try: while True: buffer = self.IRC.recv(1024) if buffer == '': break msg = buffer.split

if msg[0] == "PING": self.IRC.send("PONG %s\n" % msg[1])

if msg[1] == 'PRIVMSG' and msg[2].lower == NICKNAME.lower and msg[3].find('VERSION') != -1: nick = msg[0][:msg[0].find("!")].lstrip(':') print "Replying to VERSION by %s..." % nick self.IRC.send('NOTICE %s :\001VERSION Misza\'s WdefconBot 2.0\001\n' % nick) if nick == 'freenode-connect': self.join(CHANNEL) continue

if msg[1] == 'PRIVMSG': self.log(msg[0].lstrip(':'),' '.join(msg[3:]).lstrip(':')) command = msg[3].lower.lstrip(':') if command == 'force': if self.user_access(msg[0]) >= 80: self.IRC.send(' '.join(msg[4:])+'\n') continue if command == 'say': if bot.user_access(msg[0]) >= 50: self.do_say(self.channel,' '.join(msg[4:])) continue if command == 'act': if bot.user_access(msg[0]) >= 50: self.do_ctcp(self.channel,'ACTION ' + ' '.join(msg[4:])) continue if command == 'msg': if bot.user_access(msg[0]) >= 60: self.do_say(msg[4],' '.join(msg[5:])) continue if command == 'ctcp': if bot.user_access(msg[0]) >= 60: self.do_ctcp(msg[4],' '.join(msg[5:])) continue if command == 'quit': if self.user_access(msg[0]) >= 0: self.IRC.send("PART %s :Bye!\n" % CHANNEL) self.IRC.send("QUIT\n") continue

if msg[1] == 'PRIVMSG' and msg[2] == CHANNEL: nick_name = msg[0][:msg[0].find("!")] nick = nick_name.lstrip(':') command = msg[3].lower.lstrip(':') params = ' '.join(msg[4:]) if command == '!wdefcon' and self.user_access(msg[0]) >= 0: self.log(msg[0].lstrip(':'),'!wdefcon '+params) if params == '': self.do_defcon_check(1) continue edit = re.match('edit level=([0-5]) info=(.*)',params) if edit: TIME = time.time if TIME - self.LASTEDITED < EDITINTERVAL*60: self.do_say(self.channel,nick +                   ': I have edited %0.1f minutes ago. I\'m disallowed to edit faster than once every %d minutes.' %                    ((TIME-self.LASTEDITED)/60, EDITINTERVAL)) continue self.LASTEDITED = TIME wdefcon = wikipedia.Page(self.site,TEMPLATEPAGE) wikipedia.setAction('Changing level to '+                 edit.group(1)+' on behalf of IRC user '+nick) wdefcon.put('') self.do_ctcp(self.channel,                 'ACTION has set the WikiDefcon level to %s and description to "%s"' % edit.groups) continue self.do_say(self.channel,nick+               ': Syntax for editing is: !wdefcon edit level=[0-5] info= ') continue

if re.match('\[\[User:.*?\]\].*?\[\[Template:Wdefcon\]\].*?".*"',' '.join(msg[3:])): self.do_defcon_check(0) continue

finally: self.LOGfile.close wikipedia.stopme

if __name__ == '__main__': SERVER      = 'irc.freenode.net' PORT        = 6667 NICKNAME    = 'WdefconBot2'              #Put your bot's nickname PASSWORD    = 'XXXXX'                    #Put your NickServ password here USERNAME    = 'defcon' REALNAME    = 'Misza\'s WdefconBot 2.0' CHANNEL     = '#vcn-tech'                #Channel to work in (needs a pgkbot clone to report changes) TEMPLATEPAGE = 'Template:Wdefcon'

ACCESSLIST = {                           #Add users' hostmasks and their access levels (100 being owner) '*!*@wikimedia/Misza13': 100 }                                    #Set a user's access negative to make the bot ignore him

EDITINTERVAL = 5                         #Minimal timespan (in minutes) between edits

bot = WdefconBot bot.irc_conn(SERVER,PORT) bot.login(NICKNAME,PASSWORD,USERNAME,REALNAME) bot.join(CHANNEL) bot.main_loop