pesterchum/irc.py

300 lines
12 KiB
Python

from PyQt4 import QtGui, QtCore
from twisted.internet.protocol import ClientFactory
from twisted.words.protocols.irc import IRCClient
from twisted.internet import reactor
import logging
import random
from dataobjs import Mood, PesterProfile
from generic import PesterList
logging.basicConfig(level=logging.INFO)
class PesterIRC(QtCore.QObject):
def __init__(self, config, window):
QtCore.QObject.__init__(self)
self.mainwindow = window
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()
def closeConnection(self):
#logging.info("---> Logging on...")
# self.cli.close()
pass
@QtCore.pyqtSlot(PesterProfile)
def getMood(self, *chums):
self.cli.getMood(*chums)
@QtCore.pyqtSlot(PesterList)
def getMoods(self, chums):
self.cli.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 space == -1:
space = CMD_LENGTH
a = l[0][0:space]
b = l[0][space:]
if len(b) > 0:
return [a] + splittext([b])
else:
return [a]
else:
return l
textl = splittext(textl)
for t in textl:
self.cli.msg(h, t)
@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()))
@QtCore.pyqtSlot(QtCore.QString)
def endConvo(self, handle):
h = unicode(handle)
self.cli.msg(h, "PESTERCHUM:CEASE")
@QtCore.pyqtSlot()
def updateProfile(self):
me = self.mainwindow.profile()
handle = me.handle
self.cli.setNick(handle)
self.updateMood()
@QtCore.pyqtSlot()
def updateMood(self):
me = self.mainwindow.profile()
self.cli.msg("#pesterchum", "MOOD >%d" % (me.mood.value()))
@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()))
@QtCore.pyqtSlot(QtCore.QString)
def blockedChum(self, handle):
h = unicode(handle)
self.cli.msg(h, "PESTERCHUM:BLOCK")
@QtCore.pyqtSlot(QtCore.QString)
def unblockedChum(self, handle):
h = unicode(handle)
self.cli.msg(h, "PESTERCHUM:UNBLOCK")
@QtCore.pyqtSlot(QtCore.QString)
def requestNames(self, channel):
c = unicode(channel)
self.cli.sendMessage("NAMES", c)
@QtCore.pyqtSlot()
def requestChannelList(self):
self.cli.sendMessage("LIST")
@QtCore.pyqtSlot(QtCore.QString)
def joinChannel(self, channel):
c = unicode(channel)
self.cli.join(c)
@QtCore.pyqtSlot(QtCore.QString)
def leftChannel(self, channel):
c = unicode(channel)
self.cli.leave(c)
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def kickUser(self, handle, channel):
c = unicode(channel)
h = unicode(handle)
self.cli.kick(h, c)
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString, QtCore.QString)
def setChannelMode(self, channel, mode, command):
c = unicode(channel)
m = unicode(mode).replace("+", "")
cmd = unicode(command)
if cmd == "":
cmd = None
self.cli.mode(c, True, m, cmd)
@QtCore.pyqtSlot()
def reconnectIRC(self):
pass
moodUpdated = QtCore.pyqtSignal(QtCore.QString, Mood)
colorUpdated = QtCore.pyqtSignal(QtCore.QString, QtGui.QColor)
messageReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString)
memoReceived = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString)
timeCommand = QtCore.pyqtSignal(QtCore.QString, QtCore.QString, QtCore.QString)
namesReceived = QtCore.pyqtSignal(QtCore.QString, PesterList)
channelListReceived = QtCore.pyqtSignal(PesterList)
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)
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
# silently ignore CTCP
if msg[0] == '\x01':
return
handle = nick[0:nick.find("!")]
logging.info("---> recv PRIVMSG %s :%s" % (handle, msg))
if chan == "#pesterchum":
# follow instructions
if msg[0:6] == "MOOD >":
try:
mood = Mood(int(msg[6:]))
except ValueError:
mood = Mood(0)
self.parent.moodUpdated.emit(handle, mood)
elif msg[0:7] == "GETMOOD":
mychumhandle = self.mainwindow.profile().handle
mymood = self.mainwindow.profile().mood.value()
if msg.find(mychumhandle, 8) != -1:
self.msg("#pesterchum", "MOOD >%d" % (mymood))
elif chan[0] == '#':
if msg[0:16] == "PESTERCHUM:TIME>":
self.parent.timeCommand.emit(chan, handle, msg[16:])
else:
self.parent.memoReceived.emit(chan, handle, msg)
else:
# private message
# silently ignore messages to yourself.
if handle == self.mainwindow.profile().handle:
return
if msg[0:7] == "COLOR >":
colors = msg[7:].split(",")
try:
colors = [int(d) for d in colors]
except ValueError:
colors = [0,0,0]
color = QtGui.QColor(*colors)
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))
newnick = "pesterClient%d" % (random.randint(100,999))
self.setNick(newnick)
self.parent.nickCollision.emit(nick, newnick)
def userQuit(self, nick, reason):
logging.info("---> recv QUIT %s %s" % (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))
# ok i shouldnt be overloading that but am lazy
def userLeft(self, nick, channel, reason="nanchos"):
logging.info("---> recv LEFT %s %s" % (nick, channel))
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))
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
self.parent.userPresentUpdate.emit(handle, channel, mode)
def userRenamed(self, oldnick, newnick):
logging.info("---> recv RENAME %s %s" % (oldnick, newnick))
newchum = PesterProfile(newnick, chumdb=self.mainwindow.chumdb)
self.parent.moodUpdated.emit(oldnick, Mood("offline"))
self.parent.userPresentUpdate.emit("%s:%s" % (oldnick, 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 = []
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()