Advertisement
Guest User

Untitled

a guest
May 29th, 2017
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.11 KB | None | 0 0
  1. import socket
  2. import threading
  3. import time
  4.  
  5. class SendMessages(threading.Thread):
  6.    
  7.     '''
  8.    This thread sends the messages, it is asynchron because it should not
  9.    send more then a certain amount of messages per second so the BOT does not get kicked
  10.    from the IRC-Server because of the flood protection. Use the IrcBot class to create a BOT
  11.    not this one!
  12.    '''
  13.    
  14.     def setsocket(self, socket, mtint):
  15.        
  16.         '''
  17.        Setting an socket for the communication
  18.        '''
  19.        
  20.         self.socket = socket
  21.         self.mtint = mtint
  22.         self.stop = False
  23.    
  24.     def send(self, message):
  25.        
  26.         '''
  27.        Send a message
  28.        '''
  29.        
  30.         self.socket.send(message)
  31.         time.sleep(self.mtint)
  32.    
  33.     def nowait(self, message):
  34.        
  35.         '''
  36.        Send a message and ignoring the waiting (e.g. responding for pings)
  37.        '''
  38.        
  39.         self.socket.send(message)
  40.  
  41. class IrcBot(threading.Thread):
  42.    
  43.     '''
  44.    The IrcBot-Class
  45.    This provides an simple and easy to use kit for developing your own Irc-Bot in very short time!
  46.    Here is how to use it:
  47.    Create any arbitrary function. (We will call it foo) That takes an argument let us say "bar" and returns "Foobar!".
  48.    This is what the code could look like:
  49.    import ircbot
  50.    ircbot.IrcBot()
  51.    ircbot.addfunction(foo, "foo")
  52.    ircbot.run()
  53.    In Irc someone could privmsg the Bot like so:
  54.    /query <NameOfTheBot> foo
  55.    <NameOfTheBot> Foobar!
  56.    '''
  57.     def __init__(self,
  58.                 address=("irc.quakenet.org", 6669), # Address of the IRC-Server
  59.                 name="PyIBot", # Name of the BOT (this is what you'll see on the server)
  60.                 user="PyIBot", # Username of the BOT
  61.                 host="PythonServer", # Hostname of the BOT
  62.                 realname="Python IRC BOT", # Realname of the BOT (this one _can_ contain spaces!)
  63.                 adminpw="test", # You can add certain commands using the admin=True parameter so they need the password
  64.                 prefix="!pybot", # Prefix for the commands of the BOT
  65.                 inchannel=True, # Responds to messages send in an channel (using the prefix)
  66.                 inpriv=True, # Responds to private messages (no prefix)
  67.                 errormessage="Im sorry but an error occured! ( %s )", # Gives you the error in the brackets
  68.                 maxtimeinterval=0.5, # Time between two messages (seconds)
  69.                 asynchron=False,  # If True the bot is initialized as a thread
  70.                 ):
  71.        
  72.         '''
  73.        This initializes the BOT (if asynchron=True it also initializes the BOT as a Thread)
  74.        '''
  75.        
  76.         if asynchron: threading.Thread.__init__(self)
  77.         self.address = address
  78.         self.name = name
  79.         self.user = user
  80.         self.host = host
  81.         self.realname = realname
  82.         self.adminpw = adminpw
  83.         self.prefix = prefix
  84.         self.inchannel = inchannel
  85.         self.inpriv = inpriv
  86.         self.errormessage = errormessage
  87.         self.maxtimeinterval = maxtimeinterval
  88.         self.mine = False
  89.         self.connected = True
  90.         self.registered = False
  91.         self.filter = None
  92.         self.result = None
  93.         self.functions = dict()
  94.    
  95.     def run(self):
  96.        
  97.         '''
  98.        This function starts the bot. (use the start function and the asynchron parameter in the __init__ function for multi threading)
  99.        '''
  100.        
  101.         server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  102.         server.connect(self.address)
  103.         buffer = ''
  104.         self.sender = SendMessages()
  105.         self.sender.setsocket(server, self.maxtimeinterval)
  106.         self.socket = server
  107.         while self.connected:
  108.             if not self.mine: #this thread should not do anything while the get method is running
  109.                 data = server.recv(4096) #fix me: could be lower
  110.                 if data == '': self.connected = False
  111.                 else:
  112.                     if not self.registered:
  113.                         self.sender.nowait('NICK %s\n\r' % (self.name))
  114.                         self.sender.nowait('USER %s %s %s :%s\n\r' % (self.user, self.host, self.host, self.realname))
  115.                         self.registered = True
  116.                     events, buffer = self.parse_data(data, buffer) #buffers the data and gives me the events
  117.                     for e in events: self.handle(e) #handles the data
  118.         self.sender.kill()
  119.    
  120.     def quit(self, reason="QUIT"):
  121.        
  122.         '''
  123.        Quits from the IRC-Server with a given reason that is displayed to all users in the same channel
  124.        '''
  125.        
  126.         self.sender.nowait("QUIT :%s\n\r" % reason)
  127.         self.connected = False
  128.        
  129.     def parse_data(self, data, buffer):
  130.        
  131.         '''
  132.        This parses the data and returns events to the main thread
  133.        '''
  134.    
  135.         data = buffer + data
  136.         events = data.split('\n')
  137.         buffer = events.pop()
  138.         return (events, buffer)
  139.    
  140.     def addfunction(self,
  141.                 funcname, # Name of the function e.g. "add", use the name "__global__" so it get's called every time
  142.                 function, # The function itself
  143.                 useprefix=True, # Use the prefix given via the prefix parameter in the __init__ function
  144.                 admin=False, # Only allow people to use it if they have the admin password
  145.                 reply="notice", # How to reply ( use channel, privmsg, notice or None )
  146.                 errorhandling=True, # True: respond with the errormessage; False: don't respond; None: raise Exception
  147.                 givename=False, # When True: your function will get the name of the caller as last argument
  148.                 ):
  149.        
  150.         '''
  151.        This creates a new function for the BOT.
  152.        '''
  153.        
  154.         self.functions[funcname] = (function, useprefix, admin, reply, errorhandling, givename)
  155.        
  156.     def partdata(self, data):
  157.        
  158.         '''
  159.         From a raw IRC-String you get the following list:
  160.         ('name', 'message', 'destination' )
  161.         '''
  162.        
  163.         return (data.split("!")[0][1:], ":".join(data.lstrip(":").split(":")[1:]), data.lstrip(":").split(":")[0].split()[-1])
  164.    
  165.     def partvars(self, data):
  166.        
  167.         '''
  168.         This takes a string like: "Hello World" 3 7 "Bla blub"
  169.         and produces a list like:
  170.         ["Hello World", "3", "7", "Bla blub"]
  171.         Note: all entries of the list are strings!
  172.         '''
  173.    
  174.         exp = data.replace('"', '"\xFE') #Kind of messy... i know :D
  175.         exp = exp.split('"') #Split's the list in "'s because we will take something covered in " as one argument
  176.         for i in range(len(exp)):
  177.             try:
  178.                 if exp[i].startswith("\xFE ") and exp[i - 1].startswith("\xFE"):
  179.                     exp[i] = exp[i][1:]
  180.                 elif exp[i] == "\xFE" or exp[i] == "\xFE\n":
  181.                     del exp[i]
  182.             except: pass
  183.         out = list()
  184.         for part in exp:
  185.             #Creating the final list (removing the \xFE's we added before
  186.             if part.startswith("\xFE"):
  187.                 out.append(part[1:].strip())
  188.             else:
  189.                 for a in part.split():
  190.                     out.append(a.strip())
  191.         return out
  192.    
  193.     def output(self, message, name, reply="notice"):
  194.        
  195.         '''
  196.         Handles the output to a certain person (or channel)
  197.         The reply type declares the way of contacting the person like sending an notice or a private message
  198.         '''
  199.        
  200.         self.sender.send("%s %s :%s\n\r" % (reply.capitalize(), name, message))
  201.    
  202.     def raw(self, command, nowait=False):  
  203.        
  204.         '''
  205.         Execute a raw IRC command,
  206.         please note: you will have to add \n\r to the end of the message or most servers
  207.         will ignore your message!
  208.         '''
  209.        
  210.         print command
  211.         if nowait: self.sender.nowait(command)
  212.         else: self.sender.send(command)
  213.    
  214.     def get(self, filter):
  215.        
  216.         '''
  217.        When called this function returnes the first string that contains "filter" within the next 2 seconds
  218.        This is achieved by sending the input "through" this function and if it doesnt match the filter
  219.        the input is redirected to the original handle function that does what ever it should do with it.
  220.        Note: the string that has been filtered out is not beeing handled any more!
  221.        '''
  222.        
  223.         self.mine = True
  224.         start = time.time()
  225.         data = None
  226.         while True:
  227.             data = self.socket.recv(1024)
  228.             if filter in data or time.time() - start > 2:
  229.                 break
  230.             else:
  231.                 self.handle(data)
  232.         self.mine = False
  233.         return data
  234.    
  235.     def handle(self, data):
  236.        
  237.         '''
  238.        This function is the heart of the BOT: it handles (almost) every data that is beeing send to it by the IRC-Server.
  239.        '''
  240.        
  241.         data = data.rstrip('\r')
  242.         print data # So you can see what's going on
  243.         if "PING :" in data: #PING :[Some random stuff] has to be replied with PONG :[The same random stuff]
  244.             self.sender.nowait("PONG :" + data.split(":")[1] + "\n\r")
  245.         else:
  246.             name, data, dest = self.partdata(data) # Makes the whole thing easier too handle
  247.             data = self.partvars(data) # We want some clear variables, to allow one variable containing spaces you can surround it with "
  248.             prefix, adminpw, private, error, admin = False, False, False, False, True
  249.             try:
  250.                 if dest == self.name:
  251.                     if self.inpriv:
  252.                         private = True
  253.                     else:
  254.                         error = "Private error" # The function got called in a private message though the private mode is turned off
  255.                 elif not self.inchannel:
  256.                         error = "Channel Error" # The function got called in a channel though the channel mode is turned off
  257.                 if data[0] == self.prefix:
  258.                     data = data[1:]
  259.                     prefix = True
  260.                 elif private:
  261.                     prefix = True
  262.                 if data[-1] == self.adminpw:
  263.                     data = data[:-1]
  264.                     adminpw = True
  265.                 (function, useprefix, admin, reply, errorhandling, givename) = self.functions[data[0]] # Getting the variables when the function was added
  266.                 if useprefix and not prefix:
  267.                     error = "Prefix Error" # This function requires the BOT-prefix but got called without
  268.                 elif admin and not adminpw and not error:
  269.                     self.output("You don't have the rights to use this function!", name)
  270.                     error = "Admin Error" # This function can only be called by an administrator but someone who isn't called it
  271.             except StandardError, errormessage: error = errormessage
  272.             if not error:
  273.                 data = data[1:]
  274.                 if givename:
  275.                     data.append(name)
  276.                 if reply == "channel" and dest != self.name:
  277.                         reply = "privmsg" # Channel mode is basically privmsg mode but
  278.                         name = dest # We have to switch name with destination
  279.                 elif reply == "channel": # If reply is channel but the command got called private
  280.                         reply = "privmsg" # Just switch channel with private
  281.                 if errorhandling:
  282.                     try: self.output(function(*data), name, reply=reply) # Actually calling the function
  283.                     except StandardError, errorcode:
  284.                         if "%s" in self.errormessage and reply:
  285.                             self.output(self.errormessage % errorcode, name, reply=reply)
  286.                         elif reply:
  287.                             self.output(self.errormessage, name, reply=reply)
  288.                 elif errorhandling == None:
  289.                     self.output(function(*data), name, reply=reply) # Calling the function with NO errorhandling at all: this can break your programm
  290.             else:
  291.                 try:
  292.                     (function, useprefix, admin, reply, errorhandling, givename) = self.functions["__global__"] # __global__ get's called when nothing else is getting called
  293.                     if (adminpw or not admin) and self.name not in name and (prefix or not useprefix):
  294.                         if reply == "channel" and dest != self.name: # Channel swaping (look up)
  295.                             reply = "privmsg"
  296.                             name = dest
  297.                         elif reply == "channel":
  298.                             reply = "privmsg"
  299.                         self.output(function(*data), name, reply=reply) # Calling the global function (always error handling)
  300.                 except: pass
  301.             print error # Debugging purposes
  302.            
  303. if __name__ == "__main__":
  304.    
  305.     foo = lambda bar: "Foobar!"
  306.     mybot = IrcBot()
  307.     mybot.addfunction("foo", foo)
  308.     mybot.run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement