Network/IRC/IrcWidget.py

changeset 2241
030924019d88
parent 2240
11445430c553
child 2243
c0323a43d966
equal deleted inserted replaced
2240:11445430c553 2241:030924019d88
11 import logging 11 import logging
12 12
13 from PyQt4.QtCore import pyqtSlot, Qt, QByteArray, QTimer 13 from PyQt4.QtCore import pyqtSlot, Qt, QByteArray, QTimer
14 from PyQt4.QtGui import QWidget, QToolButton, QLabel 14 from PyQt4.QtGui import QWidget, QToolButton, QLabel
15 from PyQt4.QtNetwork import QTcpSocket, QAbstractSocket 15 from PyQt4.QtNetwork import QTcpSocket, QAbstractSocket
16 try:
17 from PyQt4.QtNetwork import QSslSocket, QSslError # __IGNORE_EXCEPTION__ __IGNORE_WARNING__
18 SSL_AVAILABLE = True
19 except ImportError:
20 SSL_AVAILABLE = False
16 21
17 from E5Gui import E5MessageBox 22 from E5Gui import E5MessageBox
18 23
19 from .Ui_IrcWidget import Ui_IrcWidget 24 from .Ui_IrcWidget import Ui_IrcWidget
20 25
28 33
29 class IrcWidget(QWidget, Ui_IrcWidget): 34 class IrcWidget(QWidget, Ui_IrcWidget):
30 """ 35 """
31 Class implementing the IRC window. 36 Class implementing the IRC window.
32 """ 37 """
38 ServerDisconnected = 1
39 ServerConnected = 2
40 ServerConnecting = 3
41
33 def __init__(self, parent=None): 42 def __init__(self, parent=None):
34 """ 43 """
35 Constructor 44 Constructor
36 45
37 @param parent reference to the parent widget (QWidget) 46 @param parent reference to the parent widget (QWidget)
64 self.__nickIndex = -1 73 self.__nickIndex = -1
65 self.__nickName = "" 74 self.__nickName = ""
66 self.__server = None 75 self.__server = None
67 self.__registering = False 76 self.__registering = False
68 77
78 self.__connectionState = IrcWidget.ServerDisconnected
79 self.__sslErrorLock = False
80
69 self.__buffer = "" 81 self.__buffer = ""
70 self.__userPrefix = {} 82 self.__userPrefix = {}
71 83
72 # create TCP socket 84 self.__socket = None
73 self.__socket = QTcpSocket(self)
74 self.__socket.hostFound.connect(self.__hostFound)
75 self.__socket.connected.connect(self.__hostConnected)
76 self.__socket.disconnected.connect(self.__hostDisconnected)
77 self.__socket.readyRead.connect(self.__readyRead)
78 self.__socket.error.connect(self.__tcpError)
79 85
80 self.__patterns = [ 86 self.__patterns = [
81 # :foo.bar.net COMMAND some message 87 # :foo.bar.net COMMAND some message
82 (re.compile(r""":([^ ]+)\s+([A-Z]+)\s+(.+)"""), self.__handleNamedMessage), 88 (re.compile(r""":([^ ]+)\s+([A-Z]+)\s+(.+)"""), self.__handleNamedMessage),
83 # :foo.bar.net 123 * :info 89 # :foo.bar.net 123 * :info
141 self.__identityName = network.getIdentityName() 147 self.__identityName = network.getIdentityName()
142 identity = self.__ircNetworkManager.getIdentity(self.__identityName) 148 identity = self.__ircNetworkManager.getIdentity(self.__identityName)
143 self.__userName = identity.getIdent() 149 self.__userName = identity.getIdent()
144 self.__quitMessage = identity.getQuitMessage() 150 self.__quitMessage = identity.getQuitMessage()
145 if self.__server: 151 if self.__server:
146 self.networkWidget.addServerMessage(self.trUtf8("Info"), 152 useSSL = self.__server.useSSL()
147 self.trUtf8("Looking for server {0} (port {1})...").format( 153 if useSSL and not SSL_AVAILABLE:
148 self.__server.getName(), self.__server.getPort())) 154 E5MessageBox.critical(self,
149 self.__socket.connectToHost(self.__server.getName(), 155 self.trUtf8("SSL Connection"),
150 self.__server.getPort()) 156 self.trUtf8("""An encrypted connection to the IRC network"""
157 """ was requested but SSL is not available."""
158 """ Please change the server configuration."""))
159 return
160
161 if useSSL:
162 # create SSL socket
163 self.__socket = QSslSocket(self)
164 self.__socket.encrypted.connect(self.__hostConnected)
165 self.__socket.sslErrors.connect(self.__sslErrors)
166 else:
167 # create TCP socket
168 self.__socket = QTcpSocket(self)
169 self.__socket.connected.connect(self.__hostConnected)
170 self.__socket.hostFound.connect(self.__hostFound)
171 self.__socket.disconnected.connect(self.__hostDisconnected)
172 self.__socket.readyRead.connect(self.__readyRead)
173 self.__socket.error.connect(self.__tcpError)
174
175 self.__connectionState = IrcWidget.ServerConnecting
176 if useSSL:
177 self.networkWidget.addServerMessage(self.trUtf8("Info"),
178 self.trUtf8("Looking for server {0} (port {1}) using"
179 " an SSL encrypted connection...").format(
180 self.__server.getName(), self.__server.getPort()))
181 self.__socket.connectToHostEncrypted(self.__server.getName(),
182 self.__server.getPort())
183 else:
184 self.networkWidget.addServerMessage(self.trUtf8("Info"),
185 self.trUtf8("Looking for server {0} (port {1})...").format(
186 self.__server.getName(), self.__server.getPort()))
187 self.__socket.connectToHost(self.__server.getName(),
188 self.__server.getPort())
151 else: 189 else:
152 ok = E5MessageBox.yesNo(self, 190 ok = E5MessageBox.yesNo(self,
153 self.trUtf8("Disconnect from Server"), 191 self.trUtf8("Disconnect from Server"),
154 self.trUtf8("""<p>Do you really want to disconnect from""" 192 self.trUtf8("""<p>Do you really want to disconnect from"""
155 """ <b>{0}</b>?</p><p>All channels will be closed.</p>""")\ 193 """ <b>{0}</b>?</p><p>All channels will be closed.</p>""")\
162 channel = self.__channelList.pop() 200 channel = self.__channelList.pop()
163 self.channelsWidget.removeTab(self.channelsWidget.indexOf(channel)) 201 self.channelsWidget.removeTab(self.channelsWidget.indexOf(channel))
164 channel.deleteLater() 202 channel.deleteLater()
165 channel = None 203 channel = None
166 self.__send("QUIT :" + self.__quitMessage) 204 self.__send("QUIT :" + self.__quitMessage)
167 self.__socket.close() 205 self.__socket and self.__socket.close()
168 self.__userName = "" 206 self.__userName = ""
169 self.__identityName = "" 207 self.__identityName = ""
170 self.__quitMessage = "" 208 self.__quitMessage = ""
171 209
172 def __editNetwork(self, name): 210 def __editNetwork(self, name):
265 """ 303 """
266 Private slot to send data to the IRC server. 304 Private slot to send data to the IRC server.
267 305
268 @param data data to be sent (string) 306 @param data data to be sent (string)
269 """ 307 """
270 self.__socket.write(QByteArray("{0}\r\n".format(data).encode("utf-8"))) 308 if self.__socket:
309 self.__socket.write(QByteArray("{0}\r\n".format(data).encode("utf-8")))
271 310
272 def __hostFound(self): 311 def __hostFound(self):
273 """ 312 """
274 Private slot to indicate the host was found. 313 Private slot to indicate the host was found.
275 """ 314 """
315 self.networkWidget.setConnected(False) 354 self.networkWidget.setConnected(False)
316 self.__server = None 355 self.__server = None
317 self.__nickName = "" 356 self.__nickName = ""
318 self.__nickIndex = -1 357 self.__nickIndex = -1
319 self.__channelTypePrefixes = "" 358 self.__channelTypePrefixes = ""
359
360 self.__socket.deleteLater()
361 self.__socket = None
362
363 self.__connectionState = IrcWidget.ServerDisconnected
364 self.__sslErrorLock = False
320 365
321 def __readyRead(self): 366 def __readyRead(self):
322 """ 367 """
323 Private slot to read data from the socket. 368 Private slot to read data from the socket.
324 """ 369 """
496 541
497 self.networkWidget.addServerMessage(msgType, message) 542 self.networkWidget.addServerMessage(msgType, message)
498 543
499 if code == 1: 544 if code == 1:
500 # register with services after the welcome message 545 # register with services after the welcome message
546 self.__connectionState = IrcWidget.ServerConnected
501 self.__registerWithServices() 547 self.__registerWithServices()
502 QTimer.singleShot(1000, self.__autoJoinChannels) 548 QTimer.singleShot(1000, self.__autoJoinChannels)
503 elif code == 5: 549 elif code == 5:
504 # extract the user privilege prefixes 550 # extract the user privilege prefixes
505 # ... PREFIX=(ov)@+ ... 551 # ... PREFIX=(ov)@+ ...
541 @param error error code reported by the socket 587 @param error error code reported by the socket
542 (QAbstractSocket.SocketError) 588 (QAbstractSocket.SocketError)
543 """ 589 """
544 if error == QAbstractSocket.RemoteHostClosedError: 590 if error == QAbstractSocket.RemoteHostClosedError:
545 # ignore this one, it's a disconnect 591 # ignore this one, it's a disconnect
546 pass 592 if self.__sslErrorLock:
593 self.networkWidget.addErrorMessage(self.trUtf8("SSL Error"),
594 self.trUtf8("""Connection to server {0} (port {1}) lost while"""
595 """ waiting for user response to an SSL error.""").format(
596 self.__server.getName(), self.__server.getPort()))
597 self.__connectionState = IrcWidget.ServerDisconnected
547 elif error == QAbstractSocket.HostNotFoundError: 598 elif error == QAbstractSocket.HostNotFoundError:
548 self.networkWidget.addErrorMessage(self.trUtf8("Socket Error"), 599 self.networkWidget.addErrorMessage(self.trUtf8("Socket Error"),
549 self.trUtf8("The host was not found. Please check the host name" 600 self.trUtf8("The host was not found. Please check the host name"
550 " and port settings.")) 601 " and port settings."))
551 elif error == QAbstractSocket.ConnectionRefusedError: 602 elif error == QAbstractSocket.ConnectionRefusedError:
554 " host name and port settings.")) 605 " host name and port settings."))
555 else: 606 else:
556 self.networkWidget.addErrorMessage(self.trUtf8("Socket Error"), 607 self.networkWidget.addErrorMessage(self.trUtf8("Socket Error"),
557 self.trUtf8("The following network error occurred:<br/>{0}").format( 608 self.trUtf8("The following network error occurred:<br/>{0}").format(
558 self.__socket.errorString())) 609 self.__socket.errorString()))
610
611 def __sslErrors(self, errors):
612 """
613 Private slot to handle SSL errors.
614
615 @param errors list of SSL errors (list of QSslError)
616 """
617 errorString = ""
618 if errors:
619 self.__sslErrorLock = True
620 errorStrings = []
621 for err in errors:
622 errorStrings.append(err.errorString())
623 errorString = '.<br/>'.join(errorStrings)
624 ret = E5MessageBox.yesNo(self,
625 self.trUtf8("SSL Errors"),
626 self.trUtf8("""<p>SSL Errors:</p>"""
627 """<p>{0}</p>"""
628 """<p>Do you want to ignore these errors?</p>""")\
629 .format(errorString),
630 icon=E5MessageBox.Warning)
631 self.__sslErrorLock = False
632 else:
633 ret = True
634 if ret:
635 self.networkWidget.addErrorMessage(self.trUtf8("SSL Error"),
636 self.trUtf8("""The SSL certificate for the server {0} (port {1})"""
637 """ failed the authenticity check.""").format(
638 self.__server.getName(), self.__server.getPort()))
639 if self.__connectionState == IrcWidget.ServerConnecting:
640 self.__socket.ignoreSslErrors()
641 else:
642 self.networkWidget.addErrorMessage(self.trUtf8("SSL Error"),
643 self.trUtf8("""Could not connect to {0} (port {1}) using an SSL"""
644 """ encrypted connection. Either the server does not"""
645 """ support SSL (did you use the correct port?) or"""
646 """ you rejected the certificate.<br/>{2}""").format(
647 self.__server.getName(), self.__server.getPort(), errorString))
648 self.__socket.close()
559 649
560 def __setUserPrivilegePrefix(self, prefix1, prefix2): 650 def __setUserPrivilegePrefix(self, prefix1, prefix2):
561 """ 651 """
562 Private method to set the user privilege prefix. 652 Private method to set the user privilege prefix.
563 653

eric ide

mercurial