# twisted imports
from twisted.words.protocols import irc
from twisted.internet import reactor, protocol
from twisted.python import log
# system imports
import time, sys
#other
import json
class MessageLogger:
"""
An independent logger class (because separation of application
and protocol logic is a good thing).
"""
def __init__(self, file):
self.file = file
def log(self, message):
"""Write a message to the file."""
timestamp = time.strftime("[%H:%M:%S]", time.localtime(time.time()))
self.file.write('%s %s\n' % (timestamp, message))
self.file.flush()
def close(self):
self.file.close()
class Karma:
"""
For all things internet points
"""
def __init__(self):
self.users = {} #A dictionary. Nickname and status (Really we just want to see if it has an r for registered)
self.userKarma = {} #A dictionary, nickname and points. Will have to cross-check with users to see if people are registered
def registered(self, target):
user = self.users.get(target)
if user == None:
return -1 #Does not exist
print(" DOES NOT EXIST " )
elif user.find('r')!=-1:
return 1 #Registered
print(" REGISTERED " )
else:
return 0 #Not registered or other
print(" NOT REGISTERED " )
def points(self, target, amt=None):
if(self.registered(target)!=1):
return -1
if(self.userKarma.get(target) == None): #user did not exist in the points database
self.userKarma[target] = 5
if(amt == None):
return self.userKarma.get(target)
else:
self.userKarma[target] = amt
if self.userKarma.get(target) < 0:
self.userKarma[target] = 0
return -2
class Bot(irc.IRCClient):
"""A logging IRC bot."""
nickname = "karma"
def connectionMade(self):
irc.IRCClient.connectionMade(self)
self.logger = MessageLogger(open(self.factory.filename, "a"))
self.logger.log("[connected at %s]" %
time.asctime(time.localtime(time.time())))
self.karma = Karma()
def connectionLost(self, reason):
irc.IRCClient.connectionLost(self, reason)
self.logger.log("[disconnected at %s]" %
time.asctime(time.localtime(time.time())))
self.logger.close()
# callbacks for events
def signedOn(self):
"""Called when bot has succesfully signed on to server."""
self.join(self.factory.channel)
def joined(self, channel):
"""This will get called when the bot joins the channel."""
self.logger.log("[I have joined %s]" % channel)
self.sendLine("WHO %s" % channel)
def privmsg(self, user, channel, msg):
"""This will get called when the bot receives a message."""
user = user.split('!', 1)[0]
self.logger.log("<%s> %s" % (user, msg))
args = msg.split( )
if args[0] == "!give" and len(args) >= 2:
self.sendLine("WHO %s" % channel)
if self.karma.registered(args[1]) and self.karma.registered(user) and self.karma.points(user) > 0:
self.karma.points(args[1], self.karma.points(args[1])+1)
self.karma.points(user, self.karma.points(user)-1)
self.msg( channel, "+1 TO %s FROM %s" % (args[1], user) )
if args[0] == "!karma":
if len(args) >= 2:
if self.karma.registered(args[1]):
self.msg( channel, "%s: %s's karma: %d" % (user, args[1], self.karma.points(args[1]) ) )
else:
if self.karma.registered(user):
self.msg( channel, "%s: Your karma: %d" % (user, self.karma.points(user)) )
# Check to see if they're sending me a private message
if channel == self.nickname:
msg = "It isn't nice to whisper! Play nice with the group."
self.msg(user, msg)
return
# Otherwise check to see if it is a message directed at me
if msg.startswith(self.nickname + ":"):
msg = "%s: !give <name> to give karma. !karma [name] to see someone's karma." % user
self.msg(channel, msg)
self.logger.log("<%s> %s" % (self.nickname, msg))
def action(self, user, channel, msg):
"""This will get called when the bot sees someone do an action."""
user = user.split('!', 1)[0]
self.logger.log("* %s %s" % (user, msg))
# irc callbacks
def irc_RPL_WHOREPLY(self, prefix, params):
#print(prefix)
self.karma.users[params[-3]] = params[-2] #2nd last is registered param, 3rd last is nickname
def irc_RPL_ENDOFWHO(self, prefix, params):
for keys,values in self.karma.users.iteritems():
print(keys)
print(values)
def irc_NICK(self, prefix, params):
"""Called when an IRC user changes their nickname."""
old_nick = prefix.split('!')[0]
new_nick = params[0]
self.logger.log("%s is now known as %s" % (old_nick, new_nick))
# For fun, override the method that determines how a nickname is changed on
# collisions. The default method appends an underscore.
def alterCollidedNick(self, nickname):
"""
Generate an altered version of a nickname that caused a collision in an
effort to create an unused related name for subsequent registration.
"""
return nickname + '^'
class BotFactory(protocol.ClientFactory):
"""A factory for Bots.
A new protocol instance will be created each time we connect to the server.
"""
def __init__(self):
self.channel = "#jacoders"
self.filename = "session.txt"
def buildProtocol(self, addr):
p = Bot()
p.factory = self
return p
def clientConnectionLost(self, connector, reason):
"""If we get disconnected, reconnect to server."""
connector.connect()
def clientConnectionFailed(self, connector, reason):
print "connection failed:", reason
reactor.stop()
if __name__ == '__main__':
# initialize logging
log.startLogging(sys.stdout)
# create factory protocol and application
f = BotFactory()
# connect factory to this host and port
reactor.connectTCP("irc.arloria.net", 6667, f)
# run bot
reactor.run()