Newer
Older
src / python / mybot / IRCClient.py
@Andreas Jaggi Andreas Jaggi on 4 Jun 2006 5 KB Changes:
#!/bin/python
# IRC client class.                                           vim:et:ts=4
# Adam Sampson <azz@gnu.org>

import sys, socket
from threading import Thread

def getnick(s):
    n = s.find("!")
    if n > -1:
        return s[:n]
    else:
        return s

def ircsplit(s, num):
    """Split a string of the form word1 word2 .. wordN :string."""
    l = s.split(" ", num)
    if len(l) < (num + 1):
        l.append(None)
    elif l[num][0] == ":":
        l[num] = l[num][1:]
    return l

class IRCClient(Thread):
    """A simple IRC client class. Subclass this to implement your own
    IRC applications."""

    def __init__(self, server, port):
        Thread.__init__(self)
        """Open a connection to an IRC server."""
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server = server
        self.socket.connect((self.server, port))
        self.fd = self.socket.makefile("r")
        self.open = 1
        self.my_nick = None

    def __del__(self):
        """Close the connection."""
        if self.open: self.quit()

    def send(self, string):
        """Send a string to the server."""
        self.handle_outgoing(string)
        self.socket.send(string + "\n")

    def recv(self):
        """Read a line from the server. Return None on EOF."""
        line = self.fd.readline()
        if line == "":
            return None
        else:
            s = line.strip()
            self.handle_incoming(s)
            return s

    def connect(self, nick, realname = "IRCClient", password = None):
        """Log in to the server."""
        if password: self.send("PASS :" + password)
        self.nick(nick)
        self.send("USER " + nick + " 0 * :" + realname)

    def nick(self, nick):
        self.send("NICK " + nick)
        self.my_nick = nick

    def kick(self, channel, nick, reason):
        if reason is None:
            self.send("KICK " + channel + " " + nick)
        else:
            self.send("KICK " + channel + " " + nick + " :" + reason)

    def topic(self, channel, topic):
        self.send("TOPIC " + channel + " :" + topic)

    def quit(self, reason = "Quit"):
        """Quit from the server."""
        self.send("QUIT :" + reason)
        self.socket.close()
        self.open = 0

    def tjoin(self):
        Thread.join(self)

    def join(self, channel, key = None):
        """Join a channel."""
        if key is None:
            self.send("JOIN " + channel)
        else:
            self.send("JOIN " + channel + " " + key)

    def usermode(self, channel, user, mode):
        """Change a user's modes on a channel."""
        self.send("MODE " + channel + " " + mode + " " + user)

    def op(self, channel, user): self.usermode(channel, user, "+o")
    def deop(self, channel, user): self.usermode(channel, user, "-o")
    def voice(self, channel, user): self.usermode(channel, user, "+v")
    def devoice(self, channel, user): self.usermode(channel, user, "-v")
        
    def say(self, to, text):
        """Send a message to a user or channel."""
        self.send("PRIVMSG " + to + " :" + text)

    def notice(self, to, text):
        self.send("NOTICE " + to + " :" + text)

    def mainloop(self):
        self.start()
        self.tjoin()

    def run(self):
        while 1:
            line = self.recv()
            if not line: break

            prefix = None
            if line[0] == ":" and len(line) > 1: (prefix, line) = line[1:].split(" ", 1)
            (command, params) = line.split(" ", 1)
           
            if command[0] >= '0' and command[0] <= '9':
                # Server reply
                code = int(command)
                self.handle_reply(prefix, code, params)
            elif command == "PING":
                self.send("PONG " + params)
            elif command == "NICK":
                l = ircsplit(params, 0)
                self.handle_nick(prefix, l[0])
            elif command == "MODE":
                self.handle_mode(prefix, params)
            elif command == "QUIT":
                l = ircsplit(params, 0)
                self.handle_quit(prefix, l[0])
            elif command == "JOIN":
                l = ircsplit(params, 0)
                self.handle_join(prefix, l[0])
            elif command == "PART":
                l = ircsplit(params, 1)
                self.handle_part(prefix, l[0], l[1])
            elif command == "TOPIC":
                l = ircsplit(params, 1) 
                self.handle_topic(prefix, l[0], l[1])
            elif command == "INVITE":
                l = ircsplit(params, 1)
                self.handle_invite(prefix, l[0], l[1])
            elif command == "KICK":
                l = ircsplit(params, 2)
                self.handle_kick(prefix, l[0], l[1], l[2])
            elif command == "PRIVMSG":
                l = ircsplit(params, 1)
                self.handle_say(prefix, l[0], l[1])
            elif command == "NOTICE":
                l = ircsplit(params, 1)
                self.handle_notice(prefix, l[0], l[1])
            else:
                self.handle_command(prefix, command, params)
                
    def getnick(self, s):
        return split(s, "!", 1)[0]

    def get_nick(self): return self.my_nick

    def handle_incoming(self, line): pass
    def handle_outgoing(self, line): pass
    def handle_nick(self, old, new): pass
    def handle_mode(self, nick, modes): pass
    def handle_quit(self, nick, reason): pass
    def handle_join(self, nick, channel): pass
    def handle_part(self, nick, channel, reason): pass
    def handle_topic(self, nick, channel, topic): pass
    def handle_invite(self, source, to, channel): pass
    def handle_kick(self, source, channel, to, reason): pass
    def handle_say(self, source, to, message): pass
    def handle_notice(self, source, to, message): pass
    def handle_unknown(self, prefix, command, params): pass
    def handle_reply(self, prefix, code, params): pass

class LogAllMixin:
    def handle_incoming(self, line):
        print >>sys.stderr, "< " + line

    def handle_outgoing(self, line):
        print >>sys.stderr, "> " + line