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