Network/IRC/IrcWidget.py

Sun, 09 Dec 2012 16:18:17 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 09 Dec 2012 16:18:17 +0100
changeset 2255
3e728bfc178c
parent 2253
7ba2af1ff785
child 2256
d07e2e6f3c56
permissions
-rw-r--r--

Added a specialized line edit for entering IRC messages, which supports a non-persistent edit history.
Improved the "private IRC chat" support.

# -*- coding: utf-8 -*-

# Copyright (c) 2012 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the IRC window.
"""

import re
import logging

from PyQt4.QtCore import pyqtSlot, Qt, QByteArray, QTimer
from PyQt4.QtGui import QWidget, QToolButton, QLabel
from PyQt4.QtNetwork import QTcpSocket, QAbstractSocket
try:
    from PyQt4.QtNetwork import QSslSocket, QSslError   # __IGNORE_EXCEPTION__ __IGNORE_WARNING__
    SSL_AVAILABLE = True
except ImportError:
    SSL_AVAILABLE = False

from E5Gui import E5MessageBox

from .Ui_IrcWidget import Ui_IrcWidget

from .IrcNetworkManager import IrcNetworkManager
from .IrcChannelWidget import IrcChannelWidget
from .IrcNetworkListDialog import IrcNetworkListDialog

import Preferences
import UI.PixmapCache


class IrcWidget(QWidget, Ui_IrcWidget):
    """
    Class implementing the IRC window.
    """
    ServerDisconnected = 1
    ServerConnected = 2
    ServerConnecting = 3
    
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        super().__init__(parent)
        self.setupUi(self)
        
        self.__ircNetworkManager = IrcNetworkManager(self)
        
        self.__leaveButton = QToolButton(self)
        self.__leaveButton.setIcon(UI.PixmapCache.getIcon("ircCloseChannel.png"))
        self.__leaveButton.setToolTip(self.trUtf8("Press to leave the current channel"))
        self.__leaveButton.clicked[()].connect(self.__leaveChannel)
        self.__leaveButton.setEnabled(False)
        self.channelsWidget.setCornerWidget(self.__leaveButton, Qt.BottomRightCorner)
        self.channelsWidget.setTabsClosable(False)
        
        self.__channelList = []
        self.__channelTypePrefixes = ""
        self.__userName = ""
        self.__identityName = ""
        self.__quitMessage = ""
        self.__nickIndex = -1
        self.__nickName = ""
        self.__server = None
        self.__registering = False
        
        self.__connectionState = IrcWidget.ServerDisconnected
        self.__sslErrorLock = False
        
        self.__buffer = ""
        self.__userPrefix = {}
        
        self.__socket = None
        
        self.__patterns = [
            # :foo_!n=foo@foohost.bar.net PRIVMSG bar_ :some long message
            (re.compile(r":([^!]+)!([^ ]+)\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__query),
            # :foo.bar.net COMMAND some message
            (re.compile(r""":([^ ]+)\s+([A-Z]+)\s+(.+)"""), self.__handleNamedMessage),
            # :foo.bar.net 123 * :info
            (re.compile(r""":([^ ]+)\s+(\d{3})\s+(.+)"""), self.__handleNumericMessage),
            # PING :ping message
            (re.compile(r"""PING\s+:(.*)"""), self.__ping),
        ]
        self.__prefixRe = re.compile(r""".*\sPREFIX=\((.*)\)([^ ]+).*""")
        self.__chanTypesRe = re.compile(r""".*\sCHANTYPES=([^ ]+).*""")
        
        ircPic = UI.PixmapCache.getPixmap("irc128.png")
        self.__emptyLabel = QLabel()
        self.__emptyLabel.setPixmap(ircPic)
        self.__emptyLabel.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
        self.channelsWidget.addTab(self.__emptyLabel, "")
        
        # all initialized, do connections now
        self.__ircNetworkManager.dataChanged.connect(self.__networkDataChanged)
        self.networkWidget.initialize(self.__ircNetworkManager)
        self.networkWidget.connectNetwork.connect(self.__connectNetwork)
        self.networkWidget.editNetwork.connect(self.__editNetwork)
        self.networkWidget.joinChannel.connect(self.__joinChannel)
        self.networkWidget.nickChanged.connect(self.__changeNick)
        self.networkWidget.sendData.connect(self.__send)
        self.networkWidget.away.connect(self.__away)
    
    def shutdown(self):
        """
        Public method to shut down the widget.
        
        @return flag indicating successful shutdown (boolean)
        """
        if self.__server:
            ok = E5MessageBox.yesNo(self,
                self.trUtf8("Disconnect from Server"),
                self.trUtf8("""<p>Do you really want to disconnect from"""
                            """ <b>{0}</b>?</p><p>All channels will be closed.</p>""")\
                    .format(self.__server.getName()))
            if ok:
                self.__socket.blockSignals(True)
                
                self.__send("QUIT :" + self.__quitMessage)
                self.__socket.close()
                self.__socket.deleteLater()
        else:
            ok = True
        
        if ok:
            self.__ircNetworkManager.close()
        return ok
    
    def autoConnect(self):
        """
        Public method to initiate the IRC auto connection.
        """
        self.networkWidget.autoConnect()

    def __connectNetwork(self, name, connect):
        """
        Private slot to connect to or disconnect from the given network.
        
        @param name name of the network to connect to (string)
        @param connect flag indicating to connect (boolean)
        """
        if connect:
            network = self.__ircNetworkManager.getNetwork(name)
            if network:
                self.__server = network.getServer()
                self.__identityName = network.getIdentityName()
                identity = self.__ircNetworkManager.getIdentity(self.__identityName)
                self.__userName = identity.getIdent()
                self.__quitMessage = identity.getQuitMessage()
                if self.__server:
                    useSSL = self.__server.useSSL()
                    if useSSL and not SSL_AVAILABLE:
                        E5MessageBox.critical(self,
                            self.trUtf8("SSL Connection"),
                            self.trUtf8("""An encrypted connection to the IRC network"""
                                        """ was requested but SSL is not available."""
                                        """ Please change the server configuration."""))
                        return
                    
                    if useSSL:
                        # create SSL socket
                        self.__socket = QSslSocket(self)
                        self.__socket.encrypted.connect(self.__hostConnected)
                        self.__socket.sslErrors.connect(self.__sslErrors)
                    else:
                        # create TCP socket
                        self.__socket = QTcpSocket(self)
                        self.__socket.connected.connect(self.__hostConnected)
                    self.__socket.hostFound.connect(self.__hostFound)
                    self.__socket.disconnected.connect(self.__hostDisconnected)
                    self.__socket.readyRead.connect(self.__readyRead)
                    self.__socket.error.connect(self.__tcpError)
                    
                    self.__connectionState = IrcWidget.ServerConnecting
                    if useSSL:
                        self.networkWidget.addServerMessage(self.trUtf8("Info"),
                            self.trUtf8("Looking for server {0} (port {1}) using"
                                        " an SSL encrypted connection...").format(
                                self.__server.getName(), self.__server.getPort()))
                        self.__socket.connectToHostEncrypted(self.__server.getName(),
                                                             self.__server.getPort())
                    else:
                        self.networkWidget.addServerMessage(self.trUtf8("Info"),
                            self.trUtf8("Looking for server {0} (port {1})...").format(
                                self.__server.getName(), self.__server.getPort()))
                        self.__socket.connectToHost(self.__server.getName(),
                                                    self.__server.getPort())
        else:
            ok = E5MessageBox.yesNo(self,
                self.trUtf8("Disconnect from Server"),
                self.trUtf8("""<p>Do you really want to disconnect from"""
                            """ <b>{0}</b>?</p><p>All channels will be closed.</p>""")\
                    .format(self.__server.getName()))
            if ok:
                self.networkWidget.addServerMessage(self.trUtf8("Info"),
                    self.trUtf8("Disconnecting from server {0}...").format(
                        self.__server.getName()))
                while self.__channelList:
                    channel = self.__channelList.pop()
                    self.channelsWidget.removeTab(self.channelsWidget.indexOf(channel))
                    channel.deleteLater()
                    channel = None
                self.__send("QUIT :" + self.__quitMessage)
                self.__socket and self.__socket.close()
                self.__userName = ""
                self.__identityName = ""
                self.__quitMessage = ""
    
    def __editNetwork(self, name):
        """
        Private slot to edit the network configuration.
        
        @param name name of the network to edit (string)
        """
        dlg = IrcNetworkListDialog(self.__ircNetworkManager, self)
        dlg.exec_()
    
    def __networkDataChanged(self):
        """
        Private slot handling changes of the network and identity definitions.
        """
        identity = self.__ircNetworkManager.getIdentity(self.__identityName)
        if identity:
            partMsg = identity.getPartMessage()
            for channel in self.__channelList:
                channel.setPartMessage(partMsg)
    
    def __joinChannel(self, name, key=""):
        """
        Private slot to join a channel.
        
        @param name name of the channel (string)
        @param key key of the channel (string)
        """
        # step 1: check, if this channel is already joined
        for channel in self.__channelList:
            if channel.name() == name:
                return
        
        channel = IrcChannelWidget(self)
        channel.setName(name)
        channel.setUserName(self.__nickName)
        identity = self.__ircNetworkManager.getIdentity(self.__identityName)
        channel.setPartMessage(identity.getPartMessage())
        channel.setUserPrivilegePrefix(self.__userPrefix)
        channel.initAutoWho()
        
        channel.sendData.connect(self.__send)
        channel.channelClosed.connect(self.__closeChannel)
        channel.openPrivateChat.connect(self.__openPrivate)
        
        self.channelsWidget.addTab(channel, name)
        self.__channelList.append(channel)
        self.channelsWidget.setCurrentWidget(channel)
        
        joinCommand = ["JOIN", name]
        if key:
            joinCommand.append(key)
        self.__send(" ".join(joinCommand))
        self.__send("MODE " + name)
        
        emptyIndex = self.channelsWidget.indexOf(self.__emptyLabel)
        if emptyIndex > -1:
            self.channelsWidget.removeTab(emptyIndex)
            self.__leaveButton.setEnabled(True)
        self.channelsWidget.setTabsClosable(True)
    
    def __query(self, match):
        """
        Private method to handle a new private connection.
        
        @param reference to the match object
        @return flag indicating, if the message was handled (boolean)
        """
        # group(1)   sender user name
        # group(2)   sender user@host
        # group(3)   target nick
        # group(4)   message
        self.__openPrivate(match.group(1))
        # the above call sets the new channel as the current widget
        channel = self.channelsWidget.currentWidget()
        channel.addMessage(match.group(1), match.group(4))
        channel.setPrivateInfo("{0} - {1}".format(match.group(1), match.group(2)))
        
        return True
    
    @pyqtSlot(str)
    def __openPrivate(self, name):
        """
        Private slot to open a private chat with the given user.
        
        @param name name of the user (string)
        """
        channel = IrcChannelWidget(self)
        channel.setName(self.__nickName)
        channel.setUserName(self.__nickName)
        identity = self.__ircNetworkManager.getIdentity(self.__identityName)
        channel.setPartMessage(identity.getPartMessage())
        channel.setUserPrivilegePrefix(self.__userPrefix)
        channel.setPrivate(True, name)
        channel.addUsers([name, self.__nickName])
        
        channel.sendData.connect(self.__send)
        channel.channelClosed.connect(self.__closeChannel)
        
        self.channelsWidget.addTab(channel, name)
        self.__channelList.append(channel)
        self.channelsWidget.setCurrentWidget(channel)
    
    @pyqtSlot()
    def __leaveChannel(self):
        """
        Private slot to leave a channel and close the associated tab.
        """
        channel = self.channelsWidget.currentWidget()
        channel.requestLeave()
    
    def __closeChannel(self, name):
        """
        Private slot handling the closing of a channel.
        
        @param name name of the closed channel (string) 
        """
        for channel in self.__channelList:
            if channel.name() == name:
                self.channelsWidget.removeTab(self.channelsWidget.indexOf(channel))
                self.__channelList.remove(channel)
                channel.deleteLater()
        
        if self.channelsWidget.count() == 0:
            self.channelsWidget.addTab(self.__emptyLabel, "")
            self.__leaveButton.setEnabled(False)
            self.channelsWidget.setTabsClosable(False)
    
    @pyqtSlot(int)
    def on_channelsWidget_tabCloseRequested(self, index):
        """
        Private slot to close a channel by pressing the close button of
        the channels widget.
        
        @param index index of the tab to be closed (integer)
        """
        channel = self.channelsWidget.widget(index)
        channel.requestLeave()
    
    def __send(self, data):
        """
        Private slot to send data to the IRC server.
        
        @param data data to be sent (string)
        """
        if self.__socket:
            self.__socket.write(QByteArray("{0}\r\n".format(data).encode("utf-8")))
    
    def __hostFound(self):
        """
        Private slot to indicate the host was found.
        """
        self.networkWidget.addServerMessage(self.trUtf8("Info"),
            self.trUtf8("Server found,connecting..."))
    
    def __hostConnected(self):
        """
        Private slot to log in to the server after the connection was established.
        """
        self.networkWidget.addServerMessage(self.trUtf8("Info"),
            self.trUtf8("Connected,logging in..."))
        self.networkWidget.setConnected(True)
        
        self.__registering = True
        serverPassword = self.__server.getPassword()
        if serverPassword:
            self.__send("PASS " + serverPassword)
        nick = self.networkWidget.getNickname()
        if not nick:
            self.__nickIndex = 0
            try:
                nick = self.__ircNetworkManager.getIdentity(self.__identityName)\
                    .getNickNames()[self.__nickIndex]
            except IndexError:
                nick = ""
        if not nick:
            nick = self.__userName
        self.__nickName = nick
        self.networkWidget.setNickName(nick)
        realName = self.__ircNetworkManager.getIdentity(self.__identityName).getRealName()
        if not realName:
            realName = "eric IDE chat"
        self.__send("NICK " + nick)
        self.__send("USER " + self.__userName + " 0 * :" + realName)
    
    def __hostDisconnected(self):
        """
        Private slot to indicate the host was disconnected.
        """
        self.networkWidget.addServerMessage(self.trUtf8("Info"),
            self.trUtf8("Server disconnected."))
        self.networkWidget.setRegistered(False)
        self.networkWidget.setConnected(False)
        self.__server = None
        self.__nickName = ""
        self.__nickIndex = -1
        self.__channelTypePrefixes = ""
        
        self.__socket.deleteLater()
        self.__socket = None
        
        self.__connectionState = IrcWidget.ServerDisconnected
        self.__sslErrorLock = False
    
    def __readyRead(self):
        """
        Private slot to read data from the socket.
        """
        self.__buffer += str(self.__socket.readAll(),
                Preferences.getSystem("IOEncoding"),
                'replace')
        if self.__buffer.endswith("\r\n"):
            for line in self.__buffer.splitlines():
                line = line.strip()
                if line:
                    logging.debug("<IRC> " + line)
                    handled = False
                    # step 1: give channels a chance to handle the message
                    for channel in self.__channelList:
                        handled = channel.handleMessage(line)
                        if handled:
                            break
                    else:
                        # step 2: try to process the message ourselves
                        for patternRe, patternFunc in self.__patterns:
                            match = patternRe.match(line)
                            if match is not None:
                                if patternFunc(match):
                                    break
                        else:
                            # Oops, the message wasn't handled
                            self.networkWidget.addErrorMessage(
                                self.trUtf8("Message Error"),
                                self.trUtf8("Unknown message received from server:"
                                            "<br/>{0}").format(line))
            
            self.__updateUsersCount()
            self.__buffer = ""
    
    def __handleNamedMessage(self, match):
        """
        Private method to handle a server message containing a message name.
        
        @param reference to the match object
        @return flag indicating, if the message was handled (boolean)
        """
        name = match.group(2)
        if name == "NOTICE":
            try:
                msg = match.group(3).split(":", 1)[1]
            except IndexError:
                msg = match.group(3)
            if "!" in match.group(1):
                name = match.group(1).split("!", 1)[0]
                msg = "-{0}- {1}".format(name, msg)
            self.networkWidget.addServerMessage(self.trUtf8("Notice"), msg)
            return True
        elif name == "MODE":
            self.__registering = False
            if ":" in match.group(3):
                # :detlev_ MODE detlev_ :+i
                name, modes = match.group(3).split(" :")
                sourceNick = match.group(1)
                if not self.__isChannelName(name):
                    if name == self.__nickName:
                        if sourceNick == self.__nickName:
                            msg = self.trUtf8(
                                "You have set your personal modes to <b>[{0}]</b>")\
                                .format(modes)
                        else:
                            msg = self.trUtf8(
                                "{0} has changed your personal modes to <b>[{1}]</b>")\
                                .format(sourceNick, modes)
                        self.networkWidget.addServerMessage(
                            self.trUtf8("Mode"), msg, filterMsg=False)
                        return True
        elif name == "PART":
            nick = match.group(1).split("!", 1)[0]
            if nick == self.__nickName:
                channel = match.group(3).split(None, 1)[0]
                self.networkWidget.addMessage(
                    self.trUtf8("You have left channel {0}.").format(channel))
                return True
        elif name == "QUIT":
            # don't do anything with it here
            return True
        elif name == "NICK":
            # :foo_!n=foo@foohost.bar.net NICK :newnick
            oldNick = match.group(1).split("!", 1)[0]
            newNick = match.group(3).split(":", 1)[1]
            if oldNick == self.__nickName:
                self.networkWidget.addMessage(
                    self.trUtf8("You are now known as {0}.").format(newNick))
                self.__nickName = newNick
                self.networkWidget.setNickName(newNick)
            else:
                self.networkWidget.addMessage(
                    self.trUtf8("User {0} is now known as {1}.").format(
                    oldNick, newNick))
            return True
        elif name == "ERROR":
            self.networkWidget.addErrorMessage(
                self.trUtf8("Server Error"), match.group(3).split(":", 1)[1])
            return True
        
        return False
    
    def __handleNumericMessage(self, match):
        """
        Private method to handle a server message containing a numeric code.
        
        @param reference to the match object
        @return flag indicating, if the message was handled (boolean)
        """
        code = int(match.group(2))
        if code < 400:
            return self.__handleServerReply(code, match.group(1), match.group(3))
        else:
            return self.__handleServerError(code, match.group(1), match.group(3))
    
    def __handleServerError(self, code, server, message):
        """
        Private slot to handle a server error reply.
        
        @param code numerical code sent by the server (integer)
        @param server name of the server (string)
        @param message message sent by the server (string)
        @return flag indicating, if the message was handled (boolean)
        """
        if code == 433:
            if self.__registering:
                self.__handleNickInUseLogin()
            else:
                self.__handleNickInUse()
        else:
            self.networkWidget.addServerMessage(self.trUtf8("Error"), message)
        
        return True
    
    def __handleServerReply(self, code, server, message):
        """
        Private slot to handle a server reply.
        
        @param code numerical code sent by the server (integer)
        @param server name of the server (string)
        @param message message sent by the server (string)
        @return flag indicating, if the message was handled (boolean)
        """
        # determine message type
        if code in [1, 2, 3, 4]:
            msgType = self.trUtf8("Welcome")
        elif code == 5:
            msgType = self.trUtf8("Support")
        elif code in [250, 251, 252, 253, 254, 255, 265, 266]:
            msgType = self.trUtf8("User")
        elif code in [372, 375, 376]:
            msgType = self.trUtf8("MOTD")
        elif code in [305, 306]:
            msgType = self.trUtf8("Away")
        else:
            msgType = self.trUtf8("Info ({0})").format(code)
        
        # special treatment for some messages
        if code == 375:
            message = self.trUtf8("Message of the day")
        elif code == 376:
            message = self.trUtf8("End of message of the day")
        elif code == 4:
            parts = message.strip().split()
            message = self.trUtf8("Server {0} (Version {1}), User-Modes: {2},"
                " Channel-Modes: {3}").format(parts[1], parts[2], parts[3], parts[4])
        elif code == 265:
            parts = message.strip().split()
            message = self.trUtf8("Current users on {0}: {1}, max. {2}").format(
                server, parts[1], parts[2])
        elif code == 266:
            parts = message.strip().split()
            message = self.trUtf8("Current users on the network: {0}, max. {1}").format(
                parts[1], parts[2])
        elif code == 305:
            message = self.trUtf8("You are no longer marked as being away.")
        elif code == 306:
            message = self.trUtf8("You have been marked as being away.")
        else:
            first, message = message.split(None, 1)
            if message.startswith(":"):
                message = message[1:]
            else:
                message = message.replace(":", "", 1)
        
        self.networkWidget.addServerMessage(msgType, message)
        
        if code == 1:
            # register with services after the welcome message
            self.__connectionState = IrcWidget.ServerConnected
            self.__registerWithServices()
            self.networkWidget.setRegistered(True)
            QTimer.singleShot(1000, self.__autoJoinChannels)
        elif code == 5:
            # extract the user privilege prefixes
            # ... PREFIX=(ov)@+ ...
            m = self.__prefixRe.match(message)
            if m:
                self.__setUserPrivilegePrefix(m.group(1), m.group(2))
            # extract the channel type prefixes
            # ... CHANTYPES=# ...
            m = self.__chanTypesRe.match(message)
            if m:
                self.__setChannelTypePrefixes(m.group(1))
        
        return True
    
    def __registerWithServices(self):
        """
        Private method to register to services.
        """
        identity = self.__ircNetworkManager.getIdentity(self.__identityName)
        service = identity.getServiceName()
        password = identity.getPassword()
        if service and password:
            self.__send("PRIVMSG " + service + " :identify " + password)
    
    def __autoJoinChannels(self):
        """
        Private slot to join channels automatically once a server got connected.
        """
        for channel in self.networkWidget.getNetworkChannels():
            if channel.autoJoin():
                name = channel.getName()
                key = channel.getKey()
                self.__joinChannel(name, key)
    
    def __tcpError(self, error):
        """
        Private slot to handle errors reported by the TCP socket.
        
        @param error error code reported by the socket
            (QAbstractSocket.SocketError)
        """
        if error == QAbstractSocket.RemoteHostClosedError:
            # ignore this one, it's a disconnect
            if self.__sslErrorLock:
                self.networkWidget.addErrorMessage(self.trUtf8("SSL Error"),
                    self.trUtf8("""Connection to server {0} (port {1}) lost while"""
                                """ waiting for user response to an SSL error.""").format(
                    self.__server.getName(), self.__server.getPort()))
                self.__connectionState = IrcWidget.ServerDisconnected
        elif error == QAbstractSocket.HostNotFoundError:
            self.networkWidget.addErrorMessage(self.trUtf8("Socket Error"),
                self.trUtf8("The host was not found. Please check the host name"
                            " and port settings."))
        elif error == QAbstractSocket.ConnectionRefusedError:
            self.networkWidget.addErrorMessage(self.trUtf8("Socket Error"),
                self.trUtf8("The connection was refused by the peer. Please check the"
                            " host name and port settings."))
        else:
            self.networkWidget.addErrorMessage(self.trUtf8("Socket Error"),
                self.trUtf8("The following network error occurred:<br/>{0}").format(
                self.__socket.errorString()))
    
    def __sslErrors(self, errors):
        """
        Private slot to handle SSL errors.
        
        @param errors list of SSL errors (list of QSslError)
        """
        errorString = ""
        if errors:
            self.__sslErrorLock = True
            errorStrings = []
            for err in errors:
                errorStrings.append(err.errorString())
            errorString = '.<br/>'.join(errorStrings)
            ret = E5MessageBox.yesNo(self,
                self.trUtf8("SSL Errors"),
                self.trUtf8("""<p>SSL Errors:</p>"""
                            """<p>{0}</p>"""
                            """<p>Do you want to ignore these errors?</p>""")\
                    .format(errorString),
                icon=E5MessageBox.Warning)
            self.__sslErrorLock = False
        else:
            ret = True
        if ret:
            self.networkWidget.addErrorMessage(self.trUtf8("SSL Error"),
                self.trUtf8("""The SSL certificate for the server {0} (port {1})"""
                            """ failed the authenticity check.""").format(
                self.__server.getName(), self.__server.getPort()))
            if self.__connectionState == IrcWidget.ServerConnecting:
                self.__socket.ignoreSslErrors()
        else:
            self.networkWidget.addErrorMessage(self.trUtf8("SSL Error"),
                self.trUtf8("""Could not connect to {0} (port {1}) using an SSL"""
                            """ encrypted connection. Either the server does not"""
                            """ support SSL (did you use the correct port?) or"""
                            """ you rejected the certificate.<br/>{2}""").format(
                self.__server.getName(), self.__server.getPort(), errorString))
            self.__socket.close()
    
    def __setUserPrivilegePrefix(self, prefix1, prefix2):
        """
        Private method to set the user privilege prefix.
        
        @param prefix1 first part of the prefix (string)
        @param prefix2 indictors the first part gets mapped to (string)
        """
        # PREFIX=(ov)@+
        # o = @ -> @ircbot , channel operator
        # v = + -> +userName , voice operator
        for i in range(len(prefix1)):
            self.__userPrefix["+" + prefix1[i]] = prefix2[i]
            self.__userPrefix["-" + prefix1[i]] = ""
    
    def __ping(self, match):
        """
        Private method to handle a PING message.
        
        @param reference to the match object
        @return flag indicating, if the message was handled (boolean)
        """
        self.__send("PONG " + match.group(1))
        return True
    
    def __updateUsersCount(self):
        """
        Private method to update the users count on the channel tabs.
        """
        for channel in self.__channelList:
            index = self.channelsWidget.indexOf(channel)
            self.channelsWidget.setTabText(index,
                self.trUtf8("{0} ({1})", "channel name, users count").format(
                channel.name(), channel.getUsersCount()))
    
    def __handleNickInUseLogin(self):
        """
        Private method to handle a 443 server error at login.
        """
        self.__nickIndex += 1
        try:
            nick = self.__ircNetworkManager.getIdentity(self.__identityName)\
                .getNickNames()[self.__nickIndex]
            self.__nickName = nick
        except IndexError:
            self.networkWidget.addServerMessage(self.trUtf8("Critical"),
                self.trUtf8("No nickname acceptable to the server configured"
                            " for <b>{0}</b>. Disconnecting...").format(self.__userName))
            self.__connectNetwork("", False)
            self.__nickName = ""
            self.__nickIndex = -1
            return
        
        self.networkWidget.setNickName(nick)
        self.__send("NICK " + nick)
    
    def __handleNickInUse(self):
        """
        Private method to handle a 443 server error.
        """
        self.networkWidget.addServerMessage(self.trUtf8("Critical"),
            self.trUtf8("The given nickname is already in use."))
    
    def __changeNick(self, nick):
        """
        Private slot to use a new nick name.
        
        @param nick nick name to use (str)
        """
        self.__send("NICK " + nick)
    
    def __setChannelTypePrefixes(self, prefixes):
        """
        Private method to set the channel type prefixes.
        
        @param prefixes channel prefix characters (string)
        """
        self.__channelTypePrefixes = prefixes
    
    def __isChannelName(self, name):
        """
        Private method to check, if the given name is a channel name.
        
        @return flag indicating a channel name (boolean)
        """
        if not name:
            return False
        
        if self.__channelTypePrefixes:
            return name[0] in self.__channelTypePrefixes
        else:
            return name[0] in "#&"
    
    def __away(self, isAway):
        """
        Private slot handling the change of the away state.
        
        @param isAway flag indicating the current away state (boolean)
        """
        if isAway and self.__identityName:
            identity = self.__ircNetworkManager.getIdentity(self.__identityName)
            if identity.rememberAwayPosition():
                for channel in self.__channelList:
                    channel.setMarkerLine()

eric ide

mercurial