This bot's IRC companion sits in the cvn-wp-en channel and uses this account to edit {{Wdefcon}} on request made in the channel.
Detailed instructions: tools:~misza13/cgi-bin/wdefconbot.py
Archived approval of the bot is available at Wikipedia:Bots/Requests for approvals/Archive4#User:WdefconBot
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.
#!/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('{{subst:User:MiszaBot/Wdefcon template|level=' +
edit.group(1)+'|info='+edit.group(2)+' —IRC user \'\''+nick+
'\'\' ~~~~~|noinclude1=<noinclude>|noinclude2=</noinclude>}}')
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=<situation description>')
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()