diff --git a/TODO b/TODO
index 38c46ad..be2733d 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,4 @@
 Bugs:
-* memos need to test for max time
 * color swatch text doesnt disappear
 * X and _ buttons move around all crazy like
 
diff --git a/irc.py b/irc.py
index 1a87048..dc6ae08 100644
--- a/irc.py
+++ b/irc.py
@@ -1,9 +1,10 @@
 from PyQt4 import QtGui, QtCore
-from twisted.internet.protocol import ClientFactory
-from twisted.words.protocols.irc import IRCClient
-from twisted.internet import reactor
+from oyoyo.client import IRCClient
+from oyoyo.cmdhandler import DefaultCommandHandler
+from oyoyo import helpers
 import logging
 import random
+import socket
 
 from dataobjs import Mood, PesterProfile
 from generic import PesterList
@@ -17,32 +18,31 @@ class PesterIRC(QtCore.QObject):
         self.config = config
     def IRCConnect(self):
         server = self.config.server()
-        port = int(self.config.port())
-        nick = self.mainwindow.profile()
-        self.cli = PesterIRCFactory(nick, self)
-        logging.info("---> Logging on...")
-        reactor.connectTCP(server, port, self.cli)
-        reactor.run()
+        port = self.config.port()
+        self.cli = IRCClient(PesterHandler, host=server, port=int(port), nick=self.mainwindow.profile().handle, real_name='pcc30', blocking=True)
+        self.cli.command_handler.parent = self
+        self.cli.command_handler.mainwindow = self.mainwindow
+        self.conn = self.cli.connect()
+        self.brokenConnection = False
     def closeConnection(self):
-        #logging.info("---> Logging on...")
-        # self.cli.close()
-        pass
+        self.cli.close()
+    def setConnectionBroken(self, broken=True):
+        self.brokenConnection = True
     @QtCore.pyqtSlot(PesterProfile)
     def getMood(self, *chums):
-        self.cli.getMood(*chums)
+        self.cli.command_handler.getMood(*chums)
     @QtCore.pyqtSlot(PesterList)
     def getMoods(self, chums):
-        self.cli.getMood(*chums)
+        self.cli.command_handler.getMood(*chums)        
     @QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
     def sendMessage(self, text, handle):
         h = unicode(handle)
         textl = [unicode(text)]
-        CMD_LENGTH = 450
         def splittext(l):
-            if len(l[0]) > CMD_LENGTH:
-                space = l[0].rfind(" ", 0,CMD_LENGTH)
+            if len(l[0]) > 400:
+                space = l[0].rfind(" ", 0,400)
                 if space == -1:
-                    space = CMD_LENGTH
+                    space = 400
                 a = l[0][0:space]
                 b = l[0][space:]
                 if len(b) > 0:
@@ -52,72 +52,117 @@ class PesterIRC(QtCore.QObject):
             else:
                 return l
         textl = splittext(textl)
-        for t in textl:
-            self.cli.msg(h, t)
+        try:
+            for t in textl:
+                helpers.msg(self.cli, h, t)
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString, bool)
     def startConvo(self, handle, initiated):
         h = unicode(handle)
-        if initiated:
-            self.cli.msg(h, "PESTERCHUM:BEGIN")
-        self.cli.msg(h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
+        try:
+            if initiated:
+                helpers.msg(self.cli, h, "PESTERCHUM:BEGIN")
+            helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString)
     def endConvo(self, handle):
         h = unicode(handle)
-        self.cli.msg(h, "PESTERCHUM:CEASE")
+        try:
+            helpers.msg(self.cli, h, "PESTERCHUM:CEASE")
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot()
     def updateProfile(self):
         me = self.mainwindow.profile()
         handle = me.handle
-        self.cli.setNick(handle)
+        try:
+            helpers.nick(self.cli, handle)
+        except socket.error:
+            self.setConnectionBroken()
         self.updateMood()
     @QtCore.pyqtSlot()
     def updateMood(self):
         me = self.mainwindow.profile()
-        self.cli.msg("#pesterchum", "MOOD >%d" % (me.mood.value()))
+        try:
+            helpers.msg(self.cli, "#pesterchum", "MOOD >%d" % (me.mood.value()))
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot()
     def updateColor(self):
         me = self.mainwindow.profile()
         for h in self.mainwindow.convos.keys():
-            self.cli.msg(h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
+            try:
+                helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
+            except socket.error:
+                self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString)
     def blockedChum(self, handle):
         h = unicode(handle)
-        self.cli.msg(h, "PESTERCHUM:BLOCK")
+        try:
+            helpers.msg(self.cli, h, "PESTERCHUM:BLOCK")
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString)
     def unblockedChum(self, handle):
         h = unicode(handle)
-        self.cli.msg(h, "PESTERCHUM:UNBLOCK")
+        try:
+            helpers.msg(self.cli, h, "PESTERCHUM:UNBLOCK")
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString)
     def requestNames(self, channel):
         c = unicode(channel)
-        self.cli.sendMessage("NAMES", c)
+        try:
+            helpers.names(self.cli, c)
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot()
     def requestChannelList(self):
-        self.cli.sendMessage("LIST")
+        try:
+            helpers.channel_list(self.cli)
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString)
     def joinChannel(self, channel):
         c = unicode(channel)
-        self.cli.join(c)
+        try:
+            helpers.join(self.cli, c)
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString)
     def leftChannel(self, channel):
         c = unicode(channel)
-        self.cli.leave(c)
+        try:
+            helpers.part(self.cli, c)
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
     def kickUser(self, handle, channel):
         c = unicode(channel)
         h = unicode(handle)
-        self.cli.kick(h, c)
+        try:
+            helpers.kick(self.cli, h, c)
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString)
     def setChannelMode(self, channel, mode, command):
         c = unicode(channel)
-        m = unicode(mode).replace("+", "")
+        m = unicode(mode)
         cmd = unicode(command)
         if cmd == "":
             cmd = None
-        self.cli.mode(c, True, m, cmd)
+        try:
+            helpers.mode(self.cli, c, m, cmd)
+        except socket.error:
+            self.setConnectionBroken()
     @QtCore.pyqtSlot()
     def reconnectIRC(self):
-        pass
+        self.setConnectionBroken()
+
+    def updateIRC(self):
+        self.conn.next()
 
     moodUpdated = QtCore.pyqtSignal(QtCore.QString, Mood)
     colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor)
@@ -129,48 +174,10 @@ class PesterIRC(QtCore.QObject):
     nickCollision = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
     connected = QtCore.pyqtSignal()
     userPresentUpdate = QtCore.pyqtSignal(QtCore.QString, QtCore.QString,
-                                          QtCore.QString)
-
-
-class PesterIRCClient(IRCClient):
-    realname = "pcc30"
-    username = "pcc30"
-
-    def __init__(self, nick, qobj):
-        self.nickname = nick
-        self.parent = qobj
-        self.mainwindow = qobj.mainwindow
-        qobj.irc = self
-
-    def msg(self, user, message):
-        logging.info("---> send PRIVMSG %s %s" % (user, message))
-        IRCClient.msg(self, user, message)
-
-    def signedOn(self):
-        logging.info("---> recv WELCOME")
-        self.parent.connected.emit()
-        self.join("#pesterchum")
-        mychumhandle = self.mainwindow.profile().handle
-        mymood = self.mainwindow.profile().mood.value()
-        self.msg("#pesterchum", "MOOD >%d" % (mymood))
-        
-        chums = self.mainwindow.chumList.chums
-        self.getMood(*chums)
-
-    def getMood(self, *chums):
-        chumglub = "GETMOOD "
-        for c in chums:
-            chandle = c.handle
-            if len(chumglub+chandle) >= 350:
-                self.msg("#pesterchum", chumglub)
-                chumglub = "GETMOOD "
-            chumglub += chandle
-        if chumglub != "GETMOOD ":
-            self.msg("#pesterchum", chumglub)
+                                   QtCore.QString)
 
+class PesterHandler(DefaultCommandHandler):
     def privmsg(self, nick, chan, msg):
-        # do we still need this?
-        #msg = msg.decode("utf-8")
         # display msg, do other stuff
         if len(msg) == 0:
             return
@@ -178,7 +185,7 @@ class PesterIRCClient(IRCClient):
         if msg[0] == '\x01':
             return
         handle = nick[0:nick.find("!")]
-        logging.info("---> recv PRIVMSG %s :%s" % (handle, msg))
+        logging.info("---> recv \"PRIVMSG %s :%s\"" % (handle, msg))
         if chan == "#pesterchum":
             # follow instructions
             if msg[0:6] == "MOOD >":
@@ -191,7 +198,8 @@ class PesterIRCClient(IRCClient):
                 mychumhandle = self.mainwindow.profile().handle
                 mymood = self.mainwindow.profile().mood.value()
                 if msg.find(mychumhandle, 8) != -1:
-                    self.msg("#pesterchum", "MOOD >%d" % (mymood))
+                    helpers.msg(self.client, "#pesterchum", 
+                                "MOOD >%d" % (mymood))
         elif chan[0] == '#':
             if msg[0:16] == "PESTERCHUM:TIME>":
                 self.parent.timeCommand.emit(chan, handle, msg[16:])
@@ -212,88 +220,89 @@ class PesterIRCClient(IRCClient):
                 self.parent.colorUpdated.emit(handle, color)
             else:
                 self.parent.messageReceived.emit(handle, msg)
-    
-    def irc_ERR_NICKNAMEINUSE(self, prefix, params):
-        logging.info("---> recv NICKINUSE %s %s" % (prefix, params))
+
+
+    def welcome(self, server, nick, msg):
+        self.parent.connected.emit()
+        helpers.join(self.client, "#pesterchum")
+        mychumhandle = self.mainwindow.profile().handle
+        mymood = self.mainwindow.profile().mood.value()
+        helpers.msg(self.client, "#pesterchum", "MOOD >%d" % (mymood))
+
+        chums = self.mainwindow.chumList.chums
+        self.getMood(*chums)
+
+    def nicknameinuse(self, server, cmd, nick, msg):
         newnick = "pesterClient%d" % (random.randint(100,999))
-        self.setNick(newnick)
+        helpers.nick(self.client, newnick)
         self.parent.nickCollision.emit(nick, newnick)
-    def userQuit(self, nick, reason):
-        logging.info("---> recv QUIT %s %s" % (nick, reason))
+    def quit(self, nick, reason):
         handle = nick[0:nick.find("!")]
         self.parent.userPresentUpdate.emit(handle, "", "quit")
         self.parent.moodUpdated.emit(handle, Mood("offline"))
-    def userKicked(self, kickee, channel, kicker, msg):
-        logging.info("---> recv KICK %s %s %s %s" % (kickee, channel, kicker, msg))
-        self.parent.userPresentUpdate.emit(kickee, channel, "kick:%s" % (op))
+    def kick(self, opnick, channel, handle, op):
+        self.parent.userPresentUpdate.emit(handle, channel, "kick:%s" % (op))
         # ok i shouldnt be overloading that but am lazy
-    def userLeft(self, nick, channel, reason="nanchos"):
-        logging.info("---> recv LEFT %s %s" % (nick, channel))
+    def part(self, nick, channel, reason="nanchos"):
         handle = nick[0:nick.find("!")]
         self.parent.userPresentUpdate.emit(handle, channel, "left")
         if channel == "#pesterchum":
             self.parent.moodUpdated.emit(handle, Mood("offline"))
-    def userJoined(self, nick, channel):
-        logging.info("---> recv JOIN %s %s" % (nick, channel))
+    def join(self, nick, channel):
         handle = nick[0:nick.find("!")]
         self.parent.userPresentUpdate.emit(handle, channel, "join")
         if channel == "#pesterchum":
             self.parent.moodUpdated.emit(handle, Mood("chummy"))
-    def modeChannel(self, op, channel, set, modes, args):
-        logging.info("---> recv MODE %s %s %s %s %s" % (op, channel, set, modes, args))
-        if set:
-            modes += "+"
-        else:
-            modes += "-"
-        handle = ""
-        print args
+    def mode(self, op, channel, mode, handle=""):
         self.parent.userPresentUpdate.emit(handle, channel, mode)
-    def userRenamed(self, oldnick, newnick):
-        logging.info("---> recv RENAME %s %s" % (oldnick, newnick))
+    def nick(self, oldnick, newnick):
+        oldhandle = oldnick[0:oldnick.find("!")]
         newchum = PesterProfile(newnick, chumdb=self.mainwindow.chumdb)
-        self.parent.moodUpdated.emit(oldnick, Mood("offline"))
-        self.parent.userPresentUpdate.emit("%s:%s" % (oldnick, newnick), "", "nick")
+        self.parent.moodUpdated.emit(oldhandle, Mood("offline"))
+        self.parent.userPresentUpdate.emit("%s:%s" % (oldhandle, newnick), "", "nick")
         if newnick in self.mainwindow.chumList.chums:
             self.getMood(newchum)
-    def irc_RPL_NAMREPLY(self, prefix, params):
-        logging.info("---> recv NAMREPLY %s %s" % (prefix, params))
-        # namelist = names.split(" ")
-        # logging.info("---> recv \"NAMES %s: %d names\"" % (channel, len(namelist)))
-        # if not hasattr(self, 'channelnames'):
-        #     self.channelnames = {}
-        # if not self.channelnames.has_key(channel):
-        #     self.channelnames[channel] = []
-        # self.channelnames[channel].extend(namelist)
-    def irc_RPL_ENDOFNAMES(self, prefix, params):
-        logging.info("---> recv ENDOFNAMES %s %s" % (prefix, params))
-        # namelist = self.channelnames[channel]
-        # pl = PesterList(namelist)
-        # del self.channelnames[channel]
-        # self.parent.namesReceived.emit(channel, pl)
-    def irc_RPL_LISTSTART(self, prefix, params):
-        logging.info("---> recv LISTSTART %s %s" % (prefix, params))
-        # self.channel_list = []
-        # info = list(info)
-        # self.channel_field = info.index("Channel") # dunno if this is protocol
-    def irc_RPL_LIST(self, prefix, params):
-        logging.info("---> recv LIST %s %s" % (prefix, params))
-        # channel = info[self.channel_field]
-        # if channel not in self.channel_list and channel != "#pesterchum":
-        #     self.channel_list.append(channel)
-    def irc_RPL_LISTEND(self, prefix, params):
-        logging.info("---> recv LISTEND %s %s" % (prefix, params))
-        # pl = PesterList(self.channel_list)
-        # self.parent.channelListReceived.emit(pl)
-        # self.channel_list = []
+    def namreply(self, server, nick, op, channel, names):
+        namelist = names.split(" ")
+        logging.info("---> recv \"NAMES %s: %d names\"" % (channel, len(namelist)))
+        if not hasattr(self, 'channelnames'):
+            self.channelnames = {}
+        if not self.channelnames.has_key(channel):
+            self.channelnames[channel] = []
+        self.channelnames[channel].extend(namelist)
+    def endofnames(self, server, nick, channel, msg):
+        namelist = self.channelnames[channel]
+        pl = PesterList(namelist)
+        del self.channelnames[channel]
+        self.parent.namesReceived.emit(channel, pl)
+
+    def liststart(self, server, handle, *info):
+        self.channel_list = []
+        info = list(info)
+        self.channel_field = info.index("Channel") # dunno if this is protocol
+    def list(self, server, handle, *info):
+        channel = info[self.channel_field]
+        if channel not in self.channel_list and channel != "#pesterchum":
+            self.channel_list.append(channel)
+    def listend(self, server, handle, msg):
+        pl = PesterList(self.channel_list)
+        self.parent.channelListReceived.emit(pl)
+        self.channel_list = []
     
-class PesterIRCFactory(ClientFactory):
-    protocol = PesterIRCClient
-    
-    def __init__(self, nick, qobj):
-        self.irc = self.protocol(nick, qobj)
-    def buildProtocol(self, addr=None):
-        return self.irc
-    def clientConnectionLost(self, conn, reason):
-        conn.connect()
-    def clientConnectionFailed(self, conn, reason):
-        conn.connect()
+    def getMood(self, *chums):
+        chumglub = "GETMOOD "
+        for c in chums:
+            chandle = c.handle
+            if len(chumglub+chandle) >= 350:
+                try:
+                    helpers.msg(self.client, "#pesterchum", chumglub)
+                except socket.error:
+                    self.parent.setConnectionBroken()
+                chumglub = "GETMOOD "
+            chumglub += chandle
+        if chumglub != "GETMOOD ":
+            try:
+                helpers.msg(self.client, "#pesterchum", chumglub)
+            except socket.error:
+                self.parent.setConnectionBroken()
+            
diff --git a/irc.pyc b/irc.pyc
index a7a7116..301298b 100644
Binary files a/irc.pyc and b/irc.pyc differ
diff --git a/menus.py b/menus.py
index c6be3a1..e68aea9 100644
--- a/menus.py
+++ b/menus.py
@@ -649,6 +649,6 @@ class LoadingScreen(QtGui.QDialog):
 class AboutPesterchum(QtGui.QMessageBox):
     def __init__(self, parent=None):
         QtGui.QMessageBox.__init__(self, parent)
-        self.setText("P3ST3RCHUM V. 3.14 alpha 4")
+        self.setText("P3ST3RCHUM V. 3.1.4 alpha 4")
         self.setInformativeText("Programming by illuminatedwax (ghostDunk), art by Grimlive (aquaMarinist)")
         self.mainwindow = parent
diff --git a/menus.pyc b/menus.pyc
index 8a86c4c..23b319b 100644
Binary files a/menus.pyc and b/menus.pyc differ
diff --git a/oyoyo/client.py b/oyoyo/client.py
index fa60fa1..da5a716 100644
--- a/oyoyo/client.py
+++ b/oyoyo/client.py
@@ -29,8 +29,6 @@ from oyoyo.parse import *
 from oyoyo import helpers
 from oyoyo.cmdhandler import CommandError
 
-from datetime import *
-
 # Python < 3 compatibility
 if sys.version_info < (3,):
     class bytes(object):
@@ -127,7 +125,18 @@ class IRCClient:
 
         msg = bytes(" ", "ascii").join(bargs)
         logging.info('---> send "%s"' % msg)
-        self.socket.send(msg + bytes("\r\n", "ascii"))
+        try:
+            self.socket.send(msg + bytes("\r\n", "ascii"))
+        except socket.error, se:
+            try:  # a little dance of compatibility to get the errno
+                errno = e.errno
+            except AttributeError:
+                errno = e[0]                    
+            if not self.blocking and errno == 11:
+                print "O WELLS"
+                pass
+            else:
+                raise e
 
     def connect(self):
         """ initiates the connection to the server set in self.host:self.port 
@@ -157,16 +166,14 @@ class IRCClient:
             buffer = bytes()
             while not self._end:
                 try:
-                    #logfile.write("recv at %s\n" % datetime.now().strftime("%Y-%m-%d.%H.%M %S"))
                     buffer += self.socket.recv(1024)
-                    #logfile.write("recvd %s at %s\n" % (buffer, datetime.now().strftime("%Y-%m-%d.%H.%M %S")))
-                    #logfile.flush()
                 except socket.error, e:
                     try:  # a little dance of compatibility to get the errno
                         errno = e.errno
                     except AttributeError:
                         errno = e[0]                        
                     if not self.blocking and errno == 11:
+                        print "O WELLS"
                         pass
                     else:
                         raise e
diff --git a/oyoyo/client.pyc b/oyoyo/client.pyc
index f289bd0..9cc2422 100644
Binary files a/oyoyo/client.pyc and b/oyoyo/client.pyc differ
diff --git a/pesterchum.js b/pesterchum.js
index 185587d..aaa058c 100644
--- a/pesterchum.js
+++ b/pesterchum.js
@@ -1 +1 @@
-{"tabs": true, "soundon": true, "server": "irc.tymoon.eu", "chums": ["unknownTraveler", "tentacleTherapist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "adiosToreador", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium", "terminallyCapricious", "illuminatedWax", "aquaMarinist", "elegantDiversion", "moirailBunp", "uroborosUnbound", "androidTechnician", "midnightSparrow", "apocalypseArisen", "anguillaNuntia", "oilslickOrchid", "confusedTransient", "pretentiousFantasia", "aquaticMarinist", "lyricalKeraunoscopic", "counterRealist", "ectoBiologist", "percipientPedestrian", "asceticClinician", "doctectiveMiracles", "noSense", "obliviousCrafter", "ircMonster"], "defaultprofile": "testProfile", "block": []}
\ No newline at end of file
+{"tabs": true, "soundon": true, "server": "irc.tymoon.eu", "chums": ["unknownTraveler", "tentacleTherapist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "superGhost", "centaursTesticle", "arachnidsGrip", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "adiosToreador", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium", "terminallyCapricious", "illuminatedWax", "aquaMarinist", "elegantDiversion", "moirailBunp", "uroborosUnbound", "androidTechnician", "midnightSparrow", "apocalypseArisen", "anguillaNuntia", "oilslickOrchid", "confusedTransient", "pretentiousFantasia", "aquaticMarinist", "lyricalKeraunoscopic", "counterRealist", "ectoBiologist", "percipientPedestrian", "asceticClinician", "doctectiveMiracles", "noSense", "obliviousCrafter", "ircMonster"], "defaultprofile": "ghostDunk", "block": []}
\ No newline at end of file
diff --git a/pesterchum.py b/pesterchum.py
index c887918..f645fd5 100644
--- a/pesterchum.py
+++ b/pesterchum.py
@@ -21,6 +21,7 @@ from generic import PesterIcon, RightClickList, MultiTextDialog, PesterList
 from convo import PesterTabWindow, PesterText, PesterInput, PesterConvo
 from parsetools import convertTags, addTimeInitial
 from memos import PesterMemo, MemoTabWindow, TimeTracker
+from irc import PesterIRC
 
 class waitingMessageHolder(object):
     def __init__(self, mainwindow, **msgfuncs):
@@ -1656,6 +1657,26 @@ class PesterWindow(MovingWindow):
     closeSignal = QtCore.pyqtSignal()
     reconnectIRC = QtCore.pyqtSignal()
 
+class IRCThread(QtCore.QThread):
+    def __init__(self, ircobj):
+        QtCore.QThread.__init__(self)
+        self.irc = ircobj
+    def run(self):
+        irc = self.irc
+        irc.IRCConnect()
+        while 1:
+            if irc.brokenConnection:
+                irc.brokenConnection = False
+                self.restartIRC.emit()
+                irc.closeConnection()
+                irc.IRCConnect()
+            try:
+                irc.updateIRC()
+            except socket.error:
+                irc.setConnectionBroken()
+
+    restartIRC = QtCore.pyqtSignal()
+
 class PesterTray(QtGui.QSystemTrayIcon):
     def __init__(self, icon, mainwindow, parent):
         QtGui.QSystemTrayIcon.__init__(self, icon, parent)
@@ -1675,9 +1696,6 @@ class MainProgram(QtCore.QObject):
     def __init__(self):
         QtCore.QObject.__init__(self)
         self.app = QtGui.QApplication(sys.argv)
-        from qt4reactor import qt4reactor
-        qt4reactor.install()
-        from irc import PesterIRC
         if pygame.mixer:
             # we could set the frequency higher but i love how cheesy it sounds
             try:
@@ -1726,7 +1744,9 @@ class MainProgram(QtCore.QObject):
 
         self.irc = PesterIRC(self.widget.config, self.widget)
         self.connectWidgets(self.irc, self.widget)
-        self.irc.IRCConnect()
+        self.ircapp = IRCThread(self.irc)
+        self.connect(self.ircapp, QtCore.SIGNAL('restartIRC()'),
+                     self, QtCore.SLOT('restartIRC()'))
 
     def connectWidgets(self, irc, widget):
         irc.connect(widget, QtCore.SIGNAL('sendMessage(QString, QString)'),
@@ -1846,6 +1866,7 @@ class MainProgram(QtCore.QObject):
             sys.exit(0)
 
     def run(self):
+        self.ircapp.start()
         self.widget.loadingscreen = LoadingScreen(self.widget)
         self.connect(self.widget.loadingscreen, QtCore.SIGNAL('rejected()'),
                      self.widget, QtCore.SLOT('close()'))
diff --git a/qt4reactor/.gitignore b/qt4reactor/.gitignore
deleted file mode 100644
index e1fb410..0000000
--- a/qt4reactor/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-*.[oa]
-*~
-*.pyc
-*.pyo
-*.class
-.project
-.pydevproject
-*.cache
-_trial_temp
diff --git a/qt4reactor/LICENSE b/qt4reactor/LICENSE
deleted file mode 100644
index 5fc7ac7..0000000
--- a/qt4reactor/LICENSE
+++ /dev/null
@@ -1,57 +0,0 @@
-Copyright (c) 2001-2010
-Allen Short
-Andy Gayton
-Andrew Bennetts
-Antoine Pitrou
-Apple Computer, Inc.
-Benjamin Bruheim
-Bob Ippolito
-Canonical Limited
-Christopher Armstrong
-David Reid
-Donovan Preston
-Eric Mangold
-Eyal Lotem
-Itamar Shtull-Trauring
-James Knight
-Jason A. Mobarak
-Jean-Paul Calderone
-Jessica McKellar
-Jonathan Jacobs
-Jonathan Lange
-Jonathan D. Simms
-Jürgen Hermann
-Kevin Horn
-Kevin Turner
-Mary Gardiner
-Matthew Lefkowitz
-Massachusetts Institute of Technology
-Moshe Zadka
-Paul Swartz
-Pavel Pergamenshchik
-Ralph Meijer
-Sean Riley
-Software Freedom Conservancy
-Travis B. Hartwell
-Thijs Triemstra
-Thomas Herve
-Timothy Allen
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/qt4reactor/README b/qt4reactor/README
deleted file mode 100644
index e6b5fec..0000000
--- a/qt4reactor/README
+++ /dev/null
@@ -1,55 +0,0 @@
-Unpack this directory into your PYTHONPATH.
-
-test with:
-
-trial --reactor=qt4 twisted (or twisted.test or twisted.test.test_internet)
-
-= Contributors = 
-
-Many thanks to Darren Dale who provided the patch to fix the reactor for Qt4.4
-
-= Using the Qt4Reactor =
-
-In your own code, BEFORE you import the reactor...
-
-app = QApplication(sys.argv)
-import qt4reactor
-qt4reactor.install()
-
-= Gui =
-
-There is a way to run trial using a gui... in bin, there is a routine
-gtrial.  Put that in the same directory as trial and it pops up a
-trivial gui... hit the buton and it all runs the same... don't use the
---reactor option when calling gtrial... but all the other options
-appear to work.  This was just to make sure there wasn't anything
-strange with guis which there doesn't appear to be
-
-If you're writing a conventional Qt application and just want twisted
-as an addon, you can get that by calling reactor.runReturn() instead
-of run().  This call needs to occur after your installation of of the
-reactor and after QApplication.exec_() (or QCoreApplication.exec_()
-whichever you are using.
-
-reactor.run() will also work as expected in a typical twisted application
-
-more docs in qt4reactor.py
-
-Note that if a QApplication or QCoreApplication instance isn't
-constructed prior to calling reactor run, an internally owned
-QCoreApplication is created and destroyed. This won't work if you call
-runReturn instead of run unless you take responsibility for wacking
-QCoreApplication yourself...
-
-However, most users want this reactor to do gui stuff so this
-shouldn't be an issue.
-
-Performance impact of Qt has been reduced by minimizing use of
-signaling which is expensive.  186s for qt4reactor vs 180s for select
-for entire twisted trial suite.
-
--glenn
-
---
-Glenn H. Tarbox, PhD
-glenn@tarbox.org
diff --git a/qt4reactor/__init__.py b/qt4reactor/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/qt4reactor/bin/gtrial b/qt4reactor/bin/gtrial
deleted file mode 100755
index e0d899e..0000000
--- a/qt4reactor/bin/gtrial
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/python
-
-# Twisted, the Framework of Your Internet
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-
-
-### Twisted Preamble
-# This makes sure that users don't have to set up their environment
-# specially in order to run these programs from bin/.
-import sys, os, string
-if string.find(os.path.abspath(sys.argv[0]), os.sep+'Twisted') != -1:
-    sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir)))
-if hasattr(os, "getuid") and os.getuid() != 0:
-    sys.path.insert(0, os.curdir)
-### end of preamble
-
-# begin chdir armor
-sys.path[:] = map(os.path.abspath, sys.path)
-# end chdir armor
-
-from gtrial import run
-run()
diff --git a/qt4reactor/ghtTests/buttonStress.py b/qt4reactor/ghtTests/buttonStress.py
deleted file mode 100755
index 7b4ec54..0000000
--- a/qt4reactor/ghtTests/buttonStress.py
+++ /dev/null
@@ -1,57 +0,0 @@
-import sys
-from PySide import QtGui, QtScript
-from PySide.QtCore import QTimer, SIGNAL, QObject
-import qt4reactor
-
-app = QtGui.QApplication(sys.argv)
-qt4reactor.install()
-
-from twisted.internet import reactor, task
-from twisted.python import log
-log.startLogging(sys.stdout)
-
-class doNothing(QObject):
-    def __init__(self):
-        self.count = 0
-        self.looping=False
-        task.LoopingCall(self.printStat).start(1.0)
-        QObject.__init__(self)
-        
-    def doSomething(self):
-        if not self.looping: return
-        self.count += 1
-        reactor.callLater(0.003,self.doSomething)
-        
-    def buttonClick(self):
-        if self.looping: 
-            self.looping=False
-            log.msg('looping stopped....')
-        else: 
-            self.looping=True
-            self.doSomething()
-            log.msg('looping started....')
-        
-    def printStat(self):
-        log.msg(' c: ' + str(self.count) + 
-                ' st: ' + str(reactor._doSomethingCount))
-
-
-t=doNothing()
-
-engine = QtScript.QScriptEngine()
-
-button = QtGui.QPushButton()
-scriptButton = engine.newQObject(button)
-engine.globalObject().setProperty("button", scriptButton)
-
-app.connect(button, SIGNAL("clicked()"), t.buttonClick)
-
-engine.evaluate("button.text = 'Hello World!'")
-engine.evaluate("button.styleSheet = 'font-style: italic'")
-engine.evaluate("button.show()")
-
-reactor.runReturn()
-app.exec_()
-log.msg('fell off the bottom?...')
-
-
diff --git a/qt4reactor/ghtTests/fakeAppButtonStress.py b/qt4reactor/ghtTests/fakeAppButtonStress.py
deleted file mode 100755
index d5a2977..0000000
--- a/qt4reactor/ghtTests/fakeAppButtonStress.py
+++ /dev/null
@@ -1,51 +0,0 @@
-import sys
-from PySide import QtGui, QtScript
-from PySide.QtCore import QTimer, SIGNAL, QEventLoop
-import qt4reactor
-        
-app = QtGui.QApplication(sys.argv)
-
-qt4reactor.install()
-
-from twisted.internet import reactor, task
-
-class doNothing(object):
-    def __init__(self):
-        self.count = 0
-        self.running=False
-        task.LoopingCall(self.printStat).start(1.0)
-
-        
-    def buttonClick(self):
-        if self.running:
-            self.running=False
-            print 'CLICK: calling reactor stop...'
-            reactor.stop()
-            print 'reactor stop called....'
-        else:
-            self.running=True
-            print 'CLICK: entering run'
-            reactor.run()
-            print 'reactor run returned...'
-        
-    def printStat(self):
-        print 'tick...'
-
-t=doNothing()
-
-engine = QtScript.QScriptEngine()
-
-button = QtGui.QPushButton()
-scriptButton = engine.newQObject(button)
-engine.globalObject().setProperty("button", scriptButton)
-
-app.connect(button, SIGNAL("clicked()"), t.buttonClick)
-
-engine.evaluate("button.text = 'Hello World!'")
-engine.evaluate("button.styleSheet = 'font-style: italic'")
-engine.evaluate("button.show()")
-
-app.exec_()
-print 'fell off the bottom?...'
-
-
diff --git a/qt4reactor/ghtTests/ircClient.py b/qt4reactor/ghtTests/ircClient.py
deleted file mode 100644
index 9e6fdfb..0000000
--- a/qt4reactor/ghtTests/ircClient.py
+++ /dev/null
@@ -1,106 +0,0 @@
-from PySide.QtCore import *
-from PySide.QtGui import *
-import sys, qt4reactor
-
-app = QApplication(sys.argv)
-qt4reactor.install()
-
-from twisted.words.protocols import irc
-from twisted.internet import reactor, protocol
-from twisted.python import log
-
-import time, sys
-
-class IRCCore(irc.IRCClient):
-    nickname = 'dosdsdssd'
-    def connectionMade(self):
-        self.nickname = self.factory.window.nickName.text().encode('ascii')
-        self.factory.window.protocol = self
-        irc.IRCClient.connectionMade(self)
-        self.log('connected!!')
-    def connectionLost(self, reason):
-        self.log('disconnected... :( %s'%reason)
-    def signedOn(self):
-        chanName = self.factory.window.channelName.text().encode('ascii')
-        self.join(chanName)
-    def joined(self, channel):
-        self.log('joined %s'%channel)
-    def privmsg(self, user, channel, msg):
-        self.log('%s %s %s'%(user, channel, msg))
-    def action(self, user, channel, msg):
-        self.log('action: %s %s %s'%(user, channel, msg))
-    def log(self, str):
-        self.factory.window.view.addItem(str)
-
-class IRCCoreFactory(protocol.ClientFactory):
-    protocol = IRCCore
-    def __init__(self, window):
-        self.window = window
-    def clientConnectionLost(self, connector, reason):
-        # reconnect to server if lose connection
-        connector.connect()
-    def clientConnectionFailed(self, connector, reason):
-        print('connection failed! :(', reason)
-        reactor.stop()
-
-class MainWindow(QMainWindow):
-    def __init__(self):
-        super(MainWindow, self).__init__()
-        connectLayout = QHBoxLayout()
-        connectLayout.addWidget(QLabel('Server:'))
-        self.serverName = QLineEdit('irc.freenode.org')
-        connectLayout.addWidget(self.serverName)
-        connectLayout.addWidget(QLabel('Channel:'))
-        self.channelName = QLineEdit('#pangaea')
-        connectLayout.addWidget(self.channelName)
-        connectLayout.addWidget(QLabel('Nick:'))
-        self.nickName = QLineEdit('ceruleanwave9832')
-        connectLayout.addWidget(self.nickName)
-        self.connectButton = QPushButton('Connect!')
-        connectLayout.addWidget(self.connectButton)
-        self.connectButton.clicked.connect(self.connectIRC)
-
-        self.view = QListWidget()
-        self.entry = QLineEdit()
-        self.entry.returnPressed.connect(self.sendMessage)
-        irc = QWidget(self)
-        vbox = QVBoxLayout()
-        vbox.addLayout(connectLayout)
-        vbox.addWidget(self.view)
-        vbox.addWidget(self.entry)
-        irc.setLayout(vbox)
-        self.setCentralWidget(irc)
-        self.setWindowTitle('IRC')
-        self.setUnifiedTitleAndToolBarOnMac(True)
-        self.showMaximized()
-
-        self.protocol = None
-    def connectIRC(self):
-        self.connectButton.setDisabled(True)
-        self.channelName.setDisabled(True)
-        self.nickName.setDisabled(True)
-        self.serverName.setDisabled(True)
-        ircCoreFactory = IRCCoreFactory(self)
-        serverName = self.serverName.text().encode('ascii')
-        reactor.connectTCP(serverName, 6667, ircCoreFactory)
-        #reactor.runReturn()
-        #app.exit()
-        #app.exit()
-        reactor.run()
-    def sendMessage(self):
-        if self.protocol:
-            chanName = self.channelName.text().encode('ascii')
-            message = self.entry.text().encode('ascii')
-            self.protocol.msg(chanName, message)
-            self.view.addItem('%s <%s> %s'%(chanName, self.protocol.nickname, message))
-        else:
-            self.view.addItem('Not connected.')
-        self.entry.setText('')
-    def closeEvent(self, event):
-        print('Attempting to close the main window!')
-        reactor.stop()
-        event.accept()
-
-if __name__ == '__main__':
-    mainWin = MainWindow()
-    sys.exit(app.exec_())
diff --git a/qt4reactor/ghtTests/testIterate.py b/qt4reactor/ghtTests/testIterate.py
deleted file mode 100755
index 261155b..0000000
--- a/qt4reactor/ghtTests/testIterate.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import sys
-from PySide import QtGui, QtScript
-from PySide.QtCore import QTimer, SIGNAL
-import qt4reactor
-
-app = QtGui.QApplication(sys.argv)
-qt4reactor.install()
-
-from twisted.internet import reactor, task
-from twisted.python import log
-log.startLogging(sys.stdout)
-
-def testReactor():
-    print 'tick...'
-
-def buttonClick():
-    print 'click...'
-    reactor.iterate(5.0)
-    print 'click return'
-    
-engine = QtScript.QScriptEngine()
-
-button = QtGui.QPushButton()
-scriptButton = engine.newQObject(button)
-engine.globalObject().setProperty("button", scriptButton)
-
-app.connect(button, SIGNAL("clicked()"), buttonClick)
-
-engine.evaluate("button.text = 'Hello World!'")
-engine.evaluate("button.styleSheet = 'font-style: italic'")
-engine.evaluate("button.show()")
-
-task.LoopingCall(testReactor).start(1.0)
-reactor.run()
-log.msg('fell off the bottom?...')
-
-
diff --git a/qt4reactor/ghtTests/trivialscript.py b/qt4reactor/ghtTests/trivialscript.py
deleted file mode 100755
index 2c015cc..0000000
--- a/qt4reactor/ghtTests/trivialscript.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import sys
-
-from twisted.application import reactors
-import qt4reactor
-qt4reactor.install()
-#reactors.installReactor('qt4')
-
-from twisted.internet import reactor, task
-from twisted.python import log
-log.startLogging(sys.stdout)
- 
-def testReactor():
-    print 'tick...'
-
-def doit():
-    task.LoopingCall(testReactor).start(1.0)
-    reactor.callLater(15.0,reactor.stop)
-    
-reactor.callWhenRunning(doit)
-log.msg('calling reactor.run()')
-reactor.run()
-log.msg('fell off the bottom?...')
-
-#sys.exit(app.exec_())
-
diff --git a/qt4reactor/gtrial.py b/qt4reactor/gtrial.py
deleted file mode 100755
index 704a2f4..0000000
--- a/qt4reactor/gtrial.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import sys
-from PyQt4 import QtGui, QtScript
-from PyQt4.QtCore import QTimer, SIGNAL, QEventLoop
-import qt4reactor
-        
-app = QtGui.QApplication(sys.argv)
-
-qt4reactor.install()
-
-from twisted.internet import reactor, task
-
-class doNothing(object):
-    def __init__(self):
-        self.count = 0
-        self.running=False
-        
-    def buttonClick(self):
-        if not self.running:
-            from twisted.scripts import trial
-            trial.run()
-            
-def run():
-
-    t=doNothing()
-    
-    engine = QtScript.QScriptEngine()
-    
-    button = QtGui.QPushButton()
-    scriptButton = engine.newQObject(button)
-    engine.globalObject().setProperty("button", scriptButton)
-    
-    app.connect(button, SIGNAL("clicked()"), t.buttonClick)
-    
-    engine.evaluate("button.text = 'Do Twisted Gui Trial'")
-    engine.evaluate("button.styleSheet = 'font-style: italic'")
-    engine.evaluate("button.show()")
-    
-    app.exec_()
-    print 'fell off the bottom?...'
-
-
diff --git a/qt4reactor/qt4reactor.py b/qt4reactor/qt4reactor.py
deleted file mode 100644
index eff7e2e..0000000
--- a/qt4reactor/qt4reactor.py
+++ /dev/null
@@ -1,359 +0,0 @@
-# Copyright (c) 2001-2011 Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-
-"""
-This module provides support for Twisted to be driven by the Qt mainloop.
-
-In order to use this support, simply do the following::
-    |  app = QApplication(sys.argv) # your code to init Qt
-    |  import qt4reactor
-    |  qt4reactor.install()
-    
-alternatively:
-
-    |  from twisted.application import reactors
-    |  reactors.installReactor('qt4')
-
-Then use twisted.internet APIs as usual.  The other methods here are not
-intended to be called directly.
-
-If you don't instantiate a QApplication or QCoreApplication prior to
-installing the reactor, a QCoreApplication will be constructed
-by the reactor.  QCoreApplication does not require a GUI so trial testing
-can occur normally.
-
-Twisted can be initialized after QApplication.exec_() with a call to
-reactor.runReturn().  calling reactor.stop() will unhook twisted but
-leave your Qt application running
-
-API Stability: stable
-
-Maintainer: U{Glenn H Tarbox, PhD<mailto:glenn@tarbox.org>}
-
-Previous maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>}
-Original port to QT4: U{Gabe Rudy<mailto:rudy@goldenhelix.com>}
-Subsequent port by therve
-"""
-
-import sys
-import time
-from zope.interface import implements
-from twisted.internet.interfaces import IReactorFDSet
-from twisted.python import log, runtime
-from twisted.internet import posixbase
-from twisted.python.runtime import platformType, platform
-
-try:
-    from PyQt4.QtCore import QSocketNotifier, QObject, SIGNAL, QTimer, QCoreApplication
-    from PyQt4.QtCore import QEventLoop
-except ImportError:
-    from PySide.QtCore import QSocketNotifier, QObject, SIGNAL, QTimer, QCoreApplication
-    from PySide.QtCore import QEventLoop
-
-
-class TwistedSocketNotifier(QObject):
-    """
-    Connection between an fd event and reader/writer callbacks.
-    """
-
-    def __init__(self, parent, reactor, watcher, socketType):
-        QObject.__init__(self, parent)
-        self.reactor = reactor
-        self.watcher = watcher
-        fd = watcher.fileno()
-        self.notifier = QSocketNotifier(fd, socketType, parent)
-        self.notifier.setEnabled(True)
-        if socketType == QSocketNotifier.Read:
-            self.fn = self.read
-        else:
-            self.fn = self.write
-        QObject.connect(self.notifier, SIGNAL("activated(int)"), self.fn)
-
-
-    def shutdown(self):
-        self.notifier.setEnabled(False)
-        self.disconnect(self.notifier, SIGNAL("activated(int)"), self.fn)
-        self.fn = self.watcher = None
-        self.notifier.deleteLater()
-        self.deleteLater()
-
-
-    def read(self, fd):
-        if not self.watcher:
-            return
-        w = self.watcher
-        # doRead can cause self.shutdown to be called so keep a reference to self.watcher
-        def _read():
-            #Don't call me again, until the data has been read
-            self.notifier.setEnabled(False)
-            why = None
-            try:
-                why = w.doRead()
-                inRead = True
-            except:
-                inRead = False
-                log.err()
-                why = sys.exc_info()[1]
-            if why:
-                self.reactor._disconnectSelectable(w, why, inRead)
-            elif self.watcher:
-                self.notifier.setEnabled(True) # Re enable notification following sucessfull read
-            self.reactor._iterate(fromqt=True)
-        log.callWithLogger(w, _read)
-
-    def write(self, sock):
-        if not self.watcher:
-            return
-        w = self.watcher
-        def _write():
-            why = None
-            self.notifier.setEnabled(False)
-            
-            try:
-                why = w.doWrite()
-            except:
-                log.err()
-                why = sys.exc_info()[1]
-            if why:
-                self.reactor._disconnectSelectable(w, why, False)
-            elif self.watcher:
-                self.notifier.setEnabled(True)
-            self.reactor._iterate(fromqt=True)
-        log.callWithLogger(w, _write)
-
-
-
-class QtReactor(posixbase.PosixReactorBase):
-    implements(IReactorFDSet)
-
-    def __init__(self):
-        self._reads = {}
-        self._writes = {}
-        self._notifiers = {}
-        self._timer = QTimer()
-        self._timer.setSingleShot(True)
-        QObject.connect(self._timer, SIGNAL("timeout()"), self.iterate)
-
-        if QCoreApplication.startingUp():
-            # Application Object has not been started yet
-            self.qApp=QCoreApplication([])
-            self._ownApp=True
-        else:
-            self.qApp = QCoreApplication.instance()
-            self._ownApp=False
-        self._blockApp = None
-        posixbase.PosixReactorBase.__init__(self)
-
-
-    def _add(self, xer, primary, type):
-        """
-        Private method for adding a descriptor from the event loop.
-
-        It takes care of adding it if  new or modifying it if already added
-        for another state (read -> read/write for example).
-        """
-        if xer not in primary:
-            primary[xer] = TwistedSocketNotifier(None, self, xer, type)
-
-
-    def addReader(self, reader):
-        """
-        Add a FileDescriptor for notification of data available to read.
-        """
-        self._add(reader, self._reads, QSocketNotifier.Read)
-
-
-    def addWriter(self, writer):
-        """
-        Add a FileDescriptor for notification of data available to write.
-        """
-        self._add(writer, self._writes, QSocketNotifier.Write)
-
-
-    def _remove(self, xer, primary):
-        """
-        Private method for removing a descriptor from the event loop.
-
-        It does the inverse job of _add, and also add a check in case of the fd
-        has gone away.
-        """
-        if xer in primary:
-            notifier = primary.pop(xer)
-            notifier.shutdown()
-
-        
-    def removeReader(self, reader):
-        """
-        Remove a Selectable for notification of data available to read.
-        """
-        self._remove(reader, self._reads)
-
-
-    def removeWriter(self, writer):
-        """
-        Remove a Selectable for notification of data available to write.
-        """
-        self._remove(writer, self._writes)
-
-
-    def removeAll(self):
-        """
-        Remove all selectables, and return a list of them.
-        """
-        rv = self._removeAll(self._reads, self._writes)
-        return rv
-
-
-    def getReaders(self):
-        return self._reads.keys()
-
-
-    def getWriters(self):
-        return self._writes.keys()
-
-
-    def callLater(self,howlong, *args, **kargs):
-        rval = super(QtReactor,self).callLater(howlong, *args, **kargs)
-        self.reactorInvocation()
-        return rval
-
-
-    def reactorInvocation(self):
-        self._timer.stop()
-        self._timer.setInterval(0)
-        self._timer.start()
-        
-
-    def _iterate(self, delay=None, fromqt=False):
-        """See twisted.internet.interfaces.IReactorCore.iterate.
-        """
-        self.runUntilCurrent()
-        self.doIteration(delay, fromqt)
-
-    iterate = _iterate
-
-    def doIteration(self, delay=None, fromqt=False):
-        'This method is called by a Qt timer or by network activity on a file descriptor'
-        
-        if not self.running and self._blockApp:
-            self._blockApp.quit()
-        self._timer.stop()
-        delay = max(delay, 1)
-        if not fromqt:
-            self.qApp.processEvents(QEventLoop.AllEvents, delay * 1000)
-        if self.timeout() is None:
-            timeout = 0.1
-        elif self.timeout() == 0:
-            timeout = 0
-        else:
-            timeout = self.timeout()
-        self._timer.setInterval(timeout * 1000)
-        self._timer.start()
-
-
-    def runReturn(self, installSignalHandlers=True):
-        self.startRunning(installSignalHandlers=installSignalHandlers)
-        self.reactorInvocation()
-
-
-    def run(self, installSignalHandlers=True):
-        if self._ownApp:
-            self._blockApp = self.qApp
-        else:
-            self._blockApp = QEventLoop()
-        self.runReturn()
-        self._blockApp.exec_()
-
-
-class QtEventReactor(QtReactor):
-    def __init__(self, *args, **kwargs):
-        self._events = {}
-        super(QtEventReactor, self).__init__()
-
-        
-    def addEvent(self, event, fd, action):
-        """
-        Add a new win32 event to the event loop.
-        """
-        self._events[event] = (fd, action)
-
-
-    def removeEvent(self, event):
-        """
-        Remove an event.
-        """
-        if event in self._events:
-            del self._events[event]
-
-
-    def doEvents(self):
-        handles = self._events.keys()
-        if len(handles) > 0:
-            val = None
-            while val != WAIT_TIMEOUT:
-                val = MsgWaitForMultipleObjects(handles, 0, 0, QS_ALLINPUT | QS_ALLEVENTS)
-                if val >= WAIT_OBJECT_0 and val < WAIT_OBJECT_0 + len(handles):
-                    event_id = handles[val - WAIT_OBJECT_0]
-                    if event_id in self._events:
-                        fd, action = self._events[event_id]
-                        log.callWithLogger(fd, self._runAction, action, fd)
-                elif val == WAIT_TIMEOUT:
-                    pass
-                else:
-                    #print 'Got an unexpected return of %r' % val
-                    return
-
-
-    def _runAction(self, action, fd):
-        try:
-            closed = getattr(fd, action)()
-        except:
-            closed = sys.exc_info()[1]
-            log.deferr()
-
-        if closed:
-            self._disconnectSelectable(fd, closed, action == 'doRead')
-
-            
-    def timeout(self):
-        t = super(QtEventReactor, self).timeout()
-        return min(t, 0.01)
-
-
-    def iterate(self, delay=None):
-        """See twisted.internet.interfaces.IReactorCore.iterate.
-        """
-        self.runUntilCurrent()
-        self.doEvents()
-        self.doIteration(delay)
-
-
-def posixinstall():
-    """
-    Install the Qt reactor.
-    """
-    p = QtReactor()
-    from twisted.internet.main import installReactor
-    installReactor(p)
-
-
-def win32install():
-    """
-    Install the Qt reactor.
-    """
-    p = QtEventReactor()
-    from twisted.internet.main import installReactor
-    installReactor(p)
-
-
-if runtime.platform.getType() == 'win32':
-    from win32event import CreateEvent, MsgWaitForMultipleObjects
-    from win32event import WAIT_OBJECT_0, WAIT_TIMEOUT, QS_ALLINPUT, QS_ALLEVENTS
-    install = win32install
-else:
-    install = posixinstall
-
-
-__all__ = ["install"]
-
diff --git a/qt4reactor/twisted/plugins/qt4.py b/qt4reactor/twisted/plugins/qt4.py
deleted file mode 100644
index 0f380b5..0000000
--- a/qt4reactor/twisted/plugins/qt4.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
-# see LICENSE for details
-
-
-from twisted.application.reactors import Reactor
-
-qt4 = Reactor('qt4', 'qt4reactor', 'Qt4 integration reactor')
-qt4bad = Reactor('qt4bad', 'qt4reactor_bad', 'Qt4 broken reactor')
-