# Yes, this source code is terrible. # It's just something I've put together to test the server # before I write a *real* client. import sys, socket, ssl, threading, struct from PyQt5 import QtCore, QtGui, QtWidgets PRESET_COLOURS = [ QtGui.QColor(255,255,255), # COL_IRC_WHITE = 0, QtGui.QColor( 0, 0, 0), # COL_IRC_BLACK = 1, QtGui.QColor( 0, 0,128), # COL_IRC_BLUE = 2, QtGui.QColor( 0,128, 0), # COL_IRC_GREEN = 3, QtGui.QColor(255, 0, 0), # COL_IRC_RED = 4, QtGui.QColor(128, 0, 0), # COL_IRC_BROWN = 5, QtGui.QColor(128, 0,128), # COL_IRC_PURPLE = 6, QtGui.QColor(128,128, 0), # COL_IRC_ORANGE = 7, QtGui.QColor(255,255, 0), # COL_IRC_YELLOW = 8, QtGui.QColor( 0,255, 0), # COL_IRC_LIME = 9, QtGui.QColor( 0,128,128), # COL_IRC_TEAL = 10, QtGui.QColor( 0,255,255), # COL_IRC_CYAN = 11, QtGui.QColor( 0, 0,255), # COL_IRC_LIGHT_BLUE = 12, QtGui.QColor(255, 0,255), # COL_IRC_PINK = 13, QtGui.QColor(128,128,128), # COL_IRC_GREY = 14, QtGui.QColor(192,192,192), # COL_IRC_LIGHT_GREY = 15, QtGui.QColor( 0, 0, 0), # COL_DEFAULT_FG = 16, QtGui.QColor(255,255,255), # COL_DEFAULT_BG = 17, QtGui.QColor(102, 0,204), # COL_ACTION = 18, QtGui.QColor( 0,153, 0), # COL_JOIN = 19, QtGui.QColor(102, 0, 0), # COL_PART = 20, QtGui.QColor(102, 0, 0), # COL_QUIT = 21, QtGui.QColor(102, 0, 0), # COL_KICK = 22, QtGui.QColor( 51,102,153), # COL_CHANNEL_NOTICE = 23, ] protocolVer = 1 sock = None authed = False sessionKey = b'\0'*16 nextID = 1 lastReceivedPacketID = 0 packetCache = [] packetLock = threading.Lock() u32 = struct.Struct(' bufsize: break type, reserved, size = struct.unpack_from(' bufsize: break pos += 8 with packetLock: if ((type & 0x8000) == 0): pid, lastReceivedByServer = struct.unpack_from('= 0x20: build += char else: cursor.insertText(build, fmt) build = '' if c == 1: fmt.setFontWeight(QtGui.QFont.Bold) elif c == 2: fmt.setFontWeight(QtGui.QFont.Normal) elif c == 3: fmt.setFontItalic(True) elif c == 4: fmt.setFontItalic(False) elif c == 5: fmt.setFontUnderline(True) elif c == 6: fmt.setFontUnderline(False) elif (c >= 0x10 and c <= 0x1F): layer = c & 3 isBG = (True if ((c & 4) == 4) else False) isEnd = (True if ((c & 8) == 8) else False) col = None if not isEnd and (pos + 1) < l: bit1 = ord(msg[pos + 1]) col = None if (bit1 & 1) == 1: col = PRESET_COLOURS[bit1 >> 1] pos += 1 elif (pos + 3) < l: bit2 = ord(msg[pos + 2]) bit3 = ord(msg[pos + 3]) pos += 3 col = QtGui.QColor(bit1,bit2,bit3) if isBG: array = background else: array = foreground array[layer] = col maxcol = None for check in array: if check is not None: maxcol = check if isBG: if maxcol: fmt.setBackground(QtGui.QBrush(maxcol)) else: fmt.clearBackground() else: if maxcol: fmt.setForeground(QtGui.QBrush(maxcol)) else: fmt.clearForeground() pos += 1 cursor.insertText(build, fmt) cursor.insertText('\n') if isAtEnd: self.output.setTextCursor(cursor) class ChannelTab(WindowTab): class UserEntry: def __init__(self, nick, prefix, modes, listwidget): self.nick = nick self.prefix = prefix self.modes = modes self.item = QtWidgets.QListWidgetItem('', listwidget) self.syncItemText() def syncItemText(self): if self.prefix == 0: self.item.setText(self.nick) else: self.item.setText(chr(self.prefix) + self.nick) def __init__(self, parent=None): WindowTab.__init__(self, parent) self.topicLabel = QtWidgets.QLabel(self) self.topicLabel.setWordWrap(True) self.userList = QtWidgets.QListWidget(self) self.users = {} def makeLayout(self): sublayout = QtWidgets.QVBoxLayout() sublayout.addWidget(self.topicLabel) sublayout.addWidget(self.output) sublayout.addWidget(self.input) layout = QtWidgets.QHBoxLayout(self) layout.addLayout(sublayout) layout.addWidget(self.userList) def readJunk(self, pdata, pos): userCount = u32.unpack_from(pdata, pos)[0] pos += 4 users = {} for i in range(userCount): #prefix = pdata[pos] #pos += 1 nicklen = u32.unpack_from(pdata, pos)[0] pos += 4 nick = pdata[pos:pos+nicklen].decode('utf-8', 'replace') pos += nicklen modes = u32.unpack_from(pdata, pos)[0] pos += 4 prefix = pdata[pos] pos += 1 users[nick] = self.UserEntry(nick, prefix, modes, self.userList) self.users = users topiclen = u32.unpack_from(pdata, pos)[0] pos += 4 self.topic = pdata[pos:pos+topiclen].decode('utf-8', 'replace') pos += topiclen self.topicLabel.setText(self.topic) return pos def addUsers(self, pdata): userCount = u32.unpack_from(pdata, 4)[0] pos = 8 for i in range(userCount): nicklen = u32.unpack_from(pdata, pos)[0] pos += 4 nick = pdata[pos:pos+nicklen].decode('utf-8', 'replace') pos += nicklen modes = u32.unpack_from(pdata, pos)[0] pos += 4 prefix = pdata[pos] pos += 1 self.users[nick] = self.UserEntry(nick, prefix, modes, self.userList) def removeUsers(self, pdata): userCount = u32.unpack_from(pdata, 4)[0] pos = 8 if userCount == 0: self.users = {} self.userList.clear() else: for i in range(userCount): nicklen = u32.unpack_from(pdata, pos)[0] pos += 4 nick = pdata[pos:pos+nicklen].decode('utf-8', 'replace') pos += nicklen print('Removing [%s]' % repr(nick)) uo = self.users[nick] self.userList.takeItem(self.userList.row(uo.item)) del self.users[nick] def renameUser(self, pdata): pos = 4 nicklen = u32.unpack_from(pdata, pos)[0] pos += 4 fromnick = pdata[pos:pos+nicklen].decode('utf-8', 'replace') pos += nicklen nicklen = u32.unpack_from(pdata, pos)[0] pos += 4 tonick = pdata[pos:pos+nicklen].decode('utf-8', 'replace') uo = self.users[fromnick] del self.users[fromnick] self.users[tonick] = uo uo.nick = tonick uo.syncItemText() def changeUserMode(self, pdata): pos = 4 nicklen = u32.unpack_from(pdata, pos)[0] pos += 4 nick = pdata[pos:pos+nicklen].decode('utf-8', 'replace') pos += nicklen modes, prefix = struct.unpack_from('