From 381bbd7e521f56fdb61e86ce9fc039e6f3b7cf91 Mon Sep 17 00:00:00 2001 From: Daniel Washburn Date: Wed, 17 Apr 2013 14:09:54 -0400 Subject: Initial commit --- PyRC.py | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 PyRC.py diff --git a/PyRC.py b/PyRC.py new file mode 100644 index 0000000..3957b24 --- /dev/null +++ b/PyRC.py @@ -0,0 +1,237 @@ +"""A module to connect to and interact with an Internet Relay Chat server. +""" + +import socket +import sys +import string +import select + +class client: + def __init__(self, (host, port, hostpass)): + try: + self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.s.setblocking(0) + except socket.error, msg: + self.s = None + if self.s is None: + print 'Could not open socket.' + sys.exit(1) + + self.host = host + self.port = port + self.hostpass = hostpass + self.send_buf = '' + self.recv_buf = '' + + def connect(self, (nick, ident, realname)): + """connect((nick, ident, realname)) + + Connects to the specified host.""" + try: + self.s.connect((self.host, self.port)) + except socket.error, msg: + if (msg[0] == 115): + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not connect to %s %s" % (self.host, self.port) + sys.exit(1) + + connected = False + while not connected: + try: + if self.hostpass: + self.s.send('PASS %s\r\n' % self.hostpass) + self.s.send('NICK %s\r\n' % nick) + # TODO: try alternate nicknames if the first is taken, or just fail. + self.s.send('USER %s %s %s :%s\r\n' % (nick, socket.gethostname(), self.host, realname)) + connected = True + except socket.error, msg: + if msg[0] == 11 or msg[0] == 115: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not connect to %s %s" % (self.host, self.port) + sys.exit(1) + + def quit(self, reason = ''): + """quit([reason]) -> string + + Disconnects from host and returns final server messages.""" + + connected = True + while connected: + try: + if reason: + self.s.send('QUIT :%s\r\n' % reason) + connected = False + else: + self.s.send('QUIT :PyRC. http://www.pyrc.org\r\n') + connected = False + except socket.error, msg: + if msg[0] == 11: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not send to %s %s" % (self.host, self.port) + sys.exit(1) + + def join(self, channel, key = ''): + """join(channel[, key]) + + Joins specified channel, optionally using a channel key.""" + try: + self.s.send('JOIN %s %s\r\n' % (channel, key)) + except socket.error, msg: + if msg[0] == 11: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not send to %s %s" % (self.host, self.port) + sys.exit(1) + + def part(self, channel): + """part(channel) + + Leaves specified channel.""" + try: + self.s.send('PART %s\r\n' % channel) + except socket.error, msg: + if msg[0] == 11: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not send to %s %s" % (self.host, self.port) + sys.exit(1) + + def message(self, dest, message): + """message(dest, message) + + Sends message to specified destination. May be channel or user.""" + try: + self.s.send('PRIVMSG %s :%s\r\n' % (dest, message)) + except socket.error, msg: + if msg[0] == 11: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not send to %s %s" % (self.host, self.port) + sys.exit(1) + + def notice(self, dest, message): + """notice(dest, message) + + Sends notice to specified destination. May be channel or user.""" + try: + self.s.send('NOTICE %s :%s\r\n' % (dest, message)) + except socket.error, msg: + if msg[0] == 11: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not send to %s %s" % (self.host, self.port) + sys.exit(1) + + def invite(self, dest, channel): + """invite(dest, channel) + + Invites user to the specified channel.""" + try: + self.s.send('INVITE %s %s\r\n' % (dest, channel)) + except socket.error, msg: + if msg[0] == 11: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not send to %s %s" % (self.host, self.port) + sys.exit(1) + + def nick(self, nickname): + """nick(nickname) + + Changes nickname to the specified nickname.""" + try: + self.s.send('NICK %s\r\n' % nickname) + except socket.error, msg: + if msg[0] == 11: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not send to %s %s" % (self.host, self.port) + sys.exit(1) + + def pong(self, dest): + """pong(dest, message) + + Sends a pong to specified destination.""" + try: + self.s.send('PONG %s\r\n' % dest) + except socket.error, msg: + if msg[0] == 11: + pass + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not send to %s %s" % (self.host, self.port) + sys.exit(1) + + def main_loop(self): + """main_loop() + + Returns an array of dictionary objects, with keys 'sender', + 'type', 'destination', and 'message'.""" + tempbuff = '' + try: + while 1: + tempbuff += self.s.recv(512) + except socket.error, msg: + if msg[0] == 11: + self.recv_buf += tempbuff + else: + self.s.close() + self.s = None + if self.s is None: + print "Could not recieve from %s %s" % (self.host, self.port) + sys.exit(1) + + while self.recv_buf: + msgs = [] + temp = self.recv_buf.split('\n') + self.recv_buf = temp.pop() + for line in temp: + line = line.strip() + line = line.split(' ') + if line[0] == 'PING': + self.pong(line[1]) + elif line[0] == 'ERROR': + msgs.append({'sender': None, 'type': line[0], 'destination': None, 'message': string.join(line[1:]).lstrip(':')}) + self.s.close() + else: + if (line[0][0] == ':'): + # if there is a sender (usually) + # [ sender, action, destination, message ] + msgs.append({'sender': line[0].lstrip(':'), 'type': line[1], 'destination':line[2], 'message': string.join(line[3:]).lstrip(':')}) + else: + #if no sender + # [ '', action, destination, message ] + msgs.append({'sender': None, 'type': line[0], 'destination': line[1], 'message': string.join(line[2:]).lstrip(':')}) + return msgs -- cgit v1.2.2