Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import socket
- import threading
- import time
- class SendMessages(threading.Thread):
- '''
- This thread sends the messages, it is asynchron because it should not
- send more then a certain amount of messages per second so the BOT does not get kicked
- from the IRC-Server because of the flood protection. Use the IrcBot class to create a BOT
- not this one!
- '''
- def setsocket(self, socket, mtint):
- '''
- Setting an socket for the communication
- '''
- self.socket = socket
- self.mtint = mtint
- self.stop = False
- def send(self, message):
- '''
- Send a message
- '''
- self.socket.send(message)
- time.sleep(self.mtint)
- def nowait(self, message):
- '''
- Send a message and ignoring the waiting (e.g. responding for pings)
- '''
- self.socket.send(message)
- class IrcBot(threading.Thread):
- '''
- The IrcBot-Class
- This provides an simple and easy to use kit for developing your own Irc-Bot in very short time!
- Here is how to use it:
- Create any arbitrary function. (We will call it foo) That takes an argument let us say "bar" and returns "Foobar!".
- This is what the code could look like:
- import ircbot
- ircbot.IrcBot()
- ircbot.addfunction(foo, "foo")
- ircbot.run()
- In Irc someone could privmsg the Bot like so:
- /query <NameOfTheBot> foo
- <NameOfTheBot> Foobar!
- '''
- def __init__(self,
- address=("irc.quakenet.org", 6669), # Address of the IRC-Server
- name="PyIBot", # Name of the BOT (this is what you'll see on the server)
- user="PyIBot", # Username of the BOT
- host="PythonServer", # Hostname of the BOT
- realname="Python IRC BOT", # Realname of the BOT (this one _can_ contain spaces!)
- adminpw="test", # You can add certain commands using the admin=True parameter so they need the password
- prefix="!pybot", # Prefix for the commands of the BOT
- inchannel=True, # Responds to messages send in an channel (using the prefix)
- inpriv=True, # Responds to private messages (no prefix)
- errormessage="Im sorry but an error occured! ( %s )", # Gives you the error in the brackets
- maxtimeinterval=0.5, # Time between two messages (seconds)
- asynchron=False, # If True the bot is initialized as a thread
- ):
- '''
- This initializes the BOT (if asynchron=True it also initializes the BOT as a Thread)
- '''
- if asynchron: threading.Thread.__init__(self)
- self.address = address
- self.name = name
- self.user = user
- self.host = host
- self.realname = realname
- self.adminpw = adminpw
- self.prefix = prefix
- self.inchannel = inchannel
- self.inpriv = inpriv
- self.errormessage = errormessage
- self.maxtimeinterval = maxtimeinterval
- self.mine = False
- self.connected = True
- self.registered = False
- self.filter = None
- self.result = None
- self.functions = dict()
- def run(self):
- '''
- This function starts the bot. (use the start function and the asynchron parameter in the __init__ function for multi threading)
- '''
- server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- server.connect(self.address)
- buffer = ''
- self.sender = SendMessages()
- self.sender.setsocket(server, self.maxtimeinterval)
- self.socket = server
- while self.connected:
- if not self.mine: #this thread should not do anything while the get method is running
- data = server.recv(4096) #fix me: could be lower
- if data == '': self.connected = False
- else:
- if not self.registered:
- self.sender.nowait('NICK %s\n\r' % (self.name))
- self.sender.nowait('USER %s %s %s :%s\n\r' % (self.user, self.host, self.host, self.realname))
- self.registered = True
- events, buffer = self.parse_data(data, buffer) #buffers the data and gives me the events
- for e in events: self.handle(e) #handles the data
- self.sender.kill()
- def quit(self, reason="QUIT"):
- '''
- Quits from the IRC-Server with a given reason that is displayed to all users in the same channel
- '''
- self.sender.nowait("QUIT :%s\n\r" % reason)
- self.connected = False
- def parse_data(self, data, buffer):
- '''
- This parses the data and returns events to the main thread
- '''
- data = buffer + data
- events = data.split('\n')
- buffer = events.pop()
- return (events, buffer)
- def addfunction(self,
- funcname, # Name of the function e.g. "add", use the name "__global__" so it get's called every time
- function, # The function itself
- useprefix=True, # Use the prefix given via the prefix parameter in the __init__ function
- admin=False, # Only allow people to use it if they have the admin password
- reply="notice", # How to reply ( use channel, privmsg, notice or None )
- errorhandling=True, # True: respond with the errormessage; False: don't respond; None: raise Exception
- givename=False, # When True: your function will get the name of the caller as last argument
- ):
- '''
- This creates a new function for the BOT.
- '''
- self.functions[funcname] = (function, useprefix, admin, reply, errorhandling, givename)
- def partdata(self, data):
- '''
- From a raw IRC-String you get the following list:
- ('name', 'message', 'destination' )
- '''
- return (data.split("!")[0][1:], ":".join(data.lstrip(":").split(":")[1:]), data.lstrip(":").split(":")[0].split()[-1])
- def partvars(self, data):
- '''
- This takes a string like: "Hello World" 3 7 "Bla blub"
- and produces a list like:
- ["Hello World", "3", "7", "Bla blub"]
- Note: all entries of the list are strings!
- '''
- exp = data.replace('"', '"\xFE') #Kind of messy... i know :D
- exp = exp.split('"') #Split's the list in "'s because we will take something covered in " as one argument
- for i in range(len(exp)):
- try:
- if exp[i].startswith("\xFE ") and exp[i - 1].startswith("\xFE"):
- exp[i] = exp[i][1:]
- elif exp[i] == "\xFE" or exp[i] == "\xFE\n":
- del exp[i]
- except: pass
- out = list()
- for part in exp:
- #Creating the final list (removing the \xFE's we added before
- if part.startswith("\xFE"):
- out.append(part[1:].strip())
- else:
- for a in part.split():
- out.append(a.strip())
- return out
- def output(self, message, name, reply="notice"):
- '''
- Handles the output to a certain person (or channel)
- The reply type declares the way of contacting the person like sending an notice or a private message
- '''
- self.sender.send("%s %s :%s\n\r" % (reply.capitalize(), name, message))
- def raw(self, command, nowait=False):
- '''
- Execute a raw IRC command,
- please note: you will have to add \n\r to the end of the message or most servers
- will ignore your message!
- '''
- print command
- if nowait: self.sender.nowait(command)
- else: self.sender.send(command)
- def get(self, filter):
- '''
- When called this function returnes the first string that contains "filter" within the next 2 seconds
- This is achieved by sending the input "through" this function and if it doesnt match the filter
- the input is redirected to the original handle function that does what ever it should do with it.
- Note: the string that has been filtered out is not beeing handled any more!
- '''
- self.mine = True
- start = time.time()
- data = None
- while True:
- data = self.socket.recv(1024)
- if filter in data or time.time() - start > 2:
- break
- else:
- self.handle(data)
- self.mine = False
- return data
- def handle(self, data):
- '''
- This function is the heart of the BOT: it handles (almost) every data that is beeing send to it by the IRC-Server.
- '''
- data = data.rstrip('\r')
- print data # So you can see what's going on
- if "PING :" in data: #PING :[Some random stuff] has to be replied with PONG :[The same random stuff]
- self.sender.nowait("PONG :" + data.split(":")[1] + "\n\r")
- else:
- name, data, dest = self.partdata(data) # Makes the whole thing easier too handle
- data = self.partvars(data) # We want some clear variables, to allow one variable containing spaces you can surround it with "
- prefix, adminpw, private, error, admin = False, False, False, False, True
- try:
- if dest == self.name:
- if self.inpriv:
- private = True
- else:
- error = "Private error" # The function got called in a private message though the private mode is turned off
- elif not self.inchannel:
- error = "Channel Error" # The function got called in a channel though the channel mode is turned off
- if data[0] == self.prefix:
- data = data[1:]
- prefix = True
- elif private:
- prefix = True
- if data[-1] == self.adminpw:
- data = data[:-1]
- adminpw = True
- (function, useprefix, admin, reply, errorhandling, givename) = self.functions[data[0]] # Getting the variables when the function was added
- if useprefix and not prefix:
- error = "Prefix Error" # This function requires the BOT-prefix but got called without
- elif admin and not adminpw and not error:
- self.output("You don't have the rights to use this function!", name)
- error = "Admin Error" # This function can only be called by an administrator but someone who isn't called it
- except StandardError, errormessage: error = errormessage
- if not error:
- data = data[1:]
- if givename:
- data.append(name)
- if reply == "channel" and dest != self.name:
- reply = "privmsg" # Channel mode is basically privmsg mode but
- name = dest # We have to switch name with destination
- elif reply == "channel": # If reply is channel but the command got called private
- reply = "privmsg" # Just switch channel with private
- if errorhandling:
- try: self.output(function(*data), name, reply=reply) # Actually calling the function
- except StandardError, errorcode:
- if "%s" in self.errormessage and reply:
- self.output(self.errormessage % errorcode, name, reply=reply)
- elif reply:
- self.output(self.errormessage, name, reply=reply)
- elif errorhandling == None:
- self.output(function(*data), name, reply=reply) # Calling the function with NO errorhandling at all: this can break your programm
- else:
- try:
- (function, useprefix, admin, reply, errorhandling, givename) = self.functions["__global__"] # __global__ get's called when nothing else is getting called
- if (adminpw or not admin) and self.name not in name and (prefix or not useprefix):
- if reply == "channel" and dest != self.name: # Channel swaping (look up)
- reply = "privmsg"
- name = dest
- elif reply == "channel":
- reply = "privmsg"
- self.output(function(*data), name, reply=reply) # Calling the global function (always error handling)
- except: pass
- print error # Debugging purposes
- if __name__ == "__main__":
- foo = lambda bar: "Foobar!"
- mybot = IrcBot()
- mybot.addfunction("foo", foo)
- mybot.run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement