#!/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