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 |
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): |
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 |