14 pass |
14 pass |
15 |
15 |
16 import re |
16 import re |
17 import logging |
17 import logging |
18 |
18 |
19 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QByteArray, QTimer |
19 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QByteArray, QTimer, \ |
|
20 QDateTime |
20 from PyQt5.QtWidgets import QWidget, QToolButton, QLabel, QTabWidget |
21 from PyQt5.QtWidgets import QWidget, QToolButton, QLabel, QTabWidget |
21 from PyQt5.QtNetwork import QTcpSocket, QAbstractSocket |
22 from PyQt5.QtNetwork import QTcpSocket, QAbstractSocket |
22 try: |
23 try: |
23 from PyQt5.QtNetwork import QSslSocket, QSslConfiguration |
24 from PyQt5.QtNetwork import QSslSocket, QSslConfiguration |
24 from E5Network.E5SslErrorHandler import E5SslErrorHandler |
25 from E5Network.E5SslErrorHandler import E5SslErrorHandler |
125 # all initialized, do connections now |
126 # all initialized, do connections now |
126 self.__ircNetworkManager.dataChanged.connect(self.__networkDataChanged) |
127 self.__ircNetworkManager.dataChanged.connect(self.__networkDataChanged) |
127 self.networkWidget.initialize(self.__ircNetworkManager) |
128 self.networkWidget.initialize(self.__ircNetworkManager) |
128 self.networkWidget.connectNetwork.connect(self.__connectNetwork) |
129 self.networkWidget.connectNetwork.connect(self.__connectNetwork) |
129 self.networkWidget.editNetwork.connect(self.__editNetwork) |
130 self.networkWidget.editNetwork.connect(self.__editNetwork) |
130 self.networkWidget.joinChannel.connect(self.__joinChannel) |
131 self.networkWidget.joinChannel.connect(self.joinChannel) |
131 self.networkWidget.nickChanged.connect(self.__changeNick) |
132 self.networkWidget.nickChanged.connect(self.__changeNick) |
132 self.networkWidget.sendData.connect(self.__send) |
133 self.networkWidget.sendData.connect(self.__send) |
133 self.networkWidget.away.connect(self.__away) |
134 self.networkWidget.away.connect(self.__away) |
134 self.networkWidget.autoConnected.connect(self.autoConnected) |
135 self.networkWidget.autoConnected.connect(self.autoConnected) |
135 |
136 |
286 if identity: |
287 if identity: |
287 partMsg = identity.getPartMessage() |
288 partMsg = identity.getPartMessage() |
288 for channel in self.__channelList: |
289 for channel in self.__channelList: |
289 channel.setPartMessage(partMsg) |
290 channel.setPartMessage(partMsg) |
290 |
291 |
291 def __joinChannel(self, name, key=""): |
292 def joinChannel(self, name, key=""): |
292 """ |
293 """ |
293 Private slot to join a channel. |
294 Public slot to join a channel. |
294 |
295 |
295 @param name name of the channel (string) |
296 @param name name of the channel (string) |
296 @param key key of the channel (string) |
297 @param key key of the channel (string) |
297 """ |
298 """ |
298 # step 1: check, if this channel is already joined |
299 # step 1: check, if this channel is already joined |
308 channel.setPartMessage(identity.getPartMessage()) |
309 channel.setPartMessage(identity.getPartMessage()) |
309 channel.setUserPrivilegePrefix(self.__userPrefix) |
310 channel.setUserPrivilegePrefix(self.__userPrefix) |
310 channel.initAutoWho() |
311 channel.initAutoWho() |
311 |
312 |
312 channel.sendData.connect(self.__send) |
313 channel.sendData.connect(self.__send) |
|
314 channel.sendCtcpRequest.connect(self.__sendCtcpRequest) |
313 channel.sendCtcpReply.connect(self.__sendCtcpReply) |
315 channel.sendCtcpReply.connect(self.__sendCtcpReply) |
314 channel.channelClosed.connect(self.__closeChannel) |
316 channel.channelClosed.connect(self.__closeChannel) |
315 channel.openPrivateChat.connect(self.__openPrivate) |
317 channel.openPrivateChat.connect(self.__openPrivate) |
|
318 channel.awayCommand.connect(self.networkWidget.handleAwayCommand) |
|
319 channel.leaveChannels.connect(self.__leaveChannels) |
|
320 channel.leaveAllChannels.connect(self.__leaveAllChannels) |
316 |
321 |
317 self.channelsWidget.addTab(channel, name) |
322 self.channelsWidget.addTab(channel, name) |
318 self.__channelList.append(channel) |
323 self.__channelList.append(channel) |
319 self.channelsWidget.setCurrentWidget(channel) |
324 self.channelsWidget.setCurrentWidget(channel) |
320 |
325 |
369 channel.setUserPrivilegePrefix(self.__userPrefix) |
374 channel.setUserPrivilegePrefix(self.__userPrefix) |
370 channel.setPrivate(True, name) |
375 channel.setPrivate(True, name) |
371 channel.addUsers([name, self.__nickName]) |
376 channel.addUsers([name, self.__nickName]) |
372 |
377 |
373 channel.sendData.connect(self.__send) |
378 channel.sendData.connect(self.__send) |
|
379 channel.sendCtcpRequest.connect(self.__sendCtcpRequest) |
374 channel.sendCtcpReply.connect(self.__sendCtcpReply) |
380 channel.sendCtcpReply.connect(self.__sendCtcpReply) |
375 channel.channelClosed.connect(self.__closeChannel) |
381 channel.channelClosed.connect(self.__closeChannel) |
|
382 channel.awayCommand.connect(self.networkWidget.handleAwayCommand) |
|
383 channel.leaveChannels.connect(self.__leaveChannels) |
|
384 channel.leaveAllChannels.connect(self.__leaveAllChannels) |
376 |
385 |
377 self.channelsWidget.addTab(channel, name) |
386 self.channelsWidget.addTab(channel, name) |
378 self.__channelList.append(channel) |
387 self.__channelList.append(channel) |
379 self.channelsWidget.setCurrentWidget(channel) |
388 self.channelsWidget.setCurrentWidget(channel) |
380 |
389 |
383 """ |
392 """ |
384 Private slot to leave a channel and close the associated tab. |
393 Private slot to leave a channel and close the associated tab. |
385 """ |
394 """ |
386 channel = self.channelsWidget.currentWidget() |
395 channel = self.channelsWidget.currentWidget() |
387 channel.requestLeave() |
396 channel.requestLeave() |
|
397 |
|
398 @pyqtSlot(list) |
|
399 def __leaveChannels(self, channelNames): |
|
400 """ |
|
401 Private slot to leave a list of channels and close their associated |
|
402 tabs. |
|
403 |
|
404 @param channelNames list of channels to leave |
|
405 @type list of str |
|
406 """ |
|
407 for channelName in channelNames: |
|
408 for channel in self.__channelList: |
|
409 if channel.name() == channelName: |
|
410 channel.leaveChannel() |
|
411 |
|
412 @pyqtSlot() |
|
413 def __leaveAllChannels(self): |
|
414 """ |
|
415 Private slot to leave all channels and close their tabs. |
|
416 """ |
|
417 while self.__channelList: |
|
418 channel = self.__channelList[0] |
|
419 channel.leaveChannel() |
388 |
420 |
389 def __closeAllChannels(self): |
421 def __closeAllChannels(self): |
390 """ |
422 """ |
391 Private method to close all channels. |
423 Private method to close all channels. |
392 """ |
424 """ |
439 """ |
471 """ |
440 if self.__socket: |
472 if self.__socket: |
441 self.__socket.write( |
473 self.__socket.write( |
442 QByteArray("{0}\r\n".format(data).encode("utf-8"))) |
474 QByteArray("{0}\r\n".format(data).encode("utf-8"))) |
443 |
475 |
|
476 def __sendCtcpRequest(self, receiver, request, arguments): |
|
477 """ |
|
478 Private slot to send a CTCP request. |
|
479 |
|
480 @param receiver nick name of the receiver |
|
481 @type str |
|
482 @param request CTCP request to be sent |
|
483 @type str |
|
484 @param arguments arguments to be sent |
|
485 @type str |
|
486 """ |
|
487 request = request.upper() |
|
488 if request == "PING": |
|
489 arguments = "Eric IRC {0}".format( |
|
490 QDateTime.currentMSecsSinceEpoch()) |
|
491 |
|
492 self.__send("PRIVMSG {0} :\x01{1} {2}\x01".format( |
|
493 receiver, request, arguments)) |
|
494 |
444 def __sendCtcpReply(self, receiver, text): |
495 def __sendCtcpReply(self, receiver, text): |
445 """ |
496 """ |
446 Private slot to send a CTCP reply. |
497 Private slot to send a CTCP reply. |
447 |
498 |
448 @param receiver nick name of the receiver (string) |
499 @param receiver nick name of the receiver |
449 @param text text to be sent (string) |
500 @type str |
|
501 @param text text to be sent |
|
502 @type str |
450 """ |
503 """ |
451 self.__send("NOTICE {0} :\x01{1}\x01".format(receiver, text)) |
504 self.__send("NOTICE {0} :\x01{1}\x01".format(receiver, text)) |
452 |
505 |
453 def __hostFound(self): |
506 def __hostFound(self): |
454 """ |
507 """ |
549 "<br/>{0}").format(line)) |
602 "<br/>{0}").format(line)) |
550 |
603 |
551 self.__updateUsersCount() |
604 self.__updateUsersCount() |
552 self.__buffer = "" |
605 self.__buffer = "" |
553 |
606 |
|
607 def __handleCtcpReply(self, match): |
|
608 """ |
|
609 Private method to handle a server message containing a CTCP reply. |
|
610 |
|
611 @param match reference to the match object |
|
612 """ |
|
613 if "!" in match.group(1): |
|
614 sender = match.group(1).split("!", 1)[0] |
|
615 |
|
616 try: |
|
617 ctcpCommand = match.group(3).split(":", 1)[1] |
|
618 except IndexError: |
|
619 ctcpCommand = match.group(3) |
|
620 ctcpCommand = ctcpCommand[1:].split("\x01", 1)[0] |
|
621 if " " in ctcpCommand: |
|
622 ctcpReply, ctcpArg = ctcpCommand.split(" ", 1) |
|
623 else: |
|
624 ctcpReply, ctcpArg = ctcpCommand, "" |
|
625 ctcpReply = ctcpReply.upper() |
|
626 |
|
627 if ctcpReply == "PING" and ctcpArg.startswith("Eric IRC "): |
|
628 # it is a response to a ping request |
|
629 pingDateTime = int(ctcpArg.split()[-1]) |
|
630 latency = QDateTime.currentMSecsSinceEpoch() - pingDateTime |
|
631 self.networkWidget.addServerMessage( |
|
632 self.tr("CTCP"), |
|
633 self.tr( |
|
634 "Received CTCP-PING response from {0} with latency" |
|
635 " of {1} ms.").format(sender, latency)) |
|
636 else: |
|
637 self.networkWidget.addServerMessage( |
|
638 self.tr("CTCP"), |
|
639 self.tr( |
|
640 "Received unknown CTCP-{0} response from {1}.") |
|
641 .format(ctcpReply, sender)) |
|
642 |
554 def __handleNamedMessage(self, match): |
643 def __handleNamedMessage(self, match): |
555 """ |
644 """ |
556 Private method to handle a server message containing a message name. |
645 Private method to handle a server message containing a message name. |
557 |
646 |
558 @param match reference to the match object |
647 @param match reference to the match object |
562 if name == "NOTICE": |
651 if name == "NOTICE": |
563 try: |
652 try: |
564 msg = match.group(3).split(":", 1)[1] |
653 msg = match.group(3).split(":", 1)[1] |
565 except IndexError: |
654 except IndexError: |
566 msg = match.group(3) |
655 msg = match.group(3) |
|
656 |
|
657 if msg.startswith("\x01"): |
|
658 self.__handleCtcpReply(match) |
|
659 return True |
|
660 |
567 if "!" in match.group(1): |
661 if "!" in match.group(1): |
568 name = match.group(1).split("!", 1)[0] |
662 name = match.group(1).split("!", 1)[0] |
569 msg = "-{0}- {1}".format(name, msg) |
663 msg = "-{0}- {1}".format(name, msg) |
570 self.networkWidget.addServerMessage(self.tr("Notice"), msg) |
664 self.networkWidget.addServerMessage(self.tr("Notice"), msg) |
571 return True |
665 return True |
610 else: |
704 else: |
611 self.networkWidget.addMessage( |
705 self.networkWidget.addMessage( |
612 self.tr("User {0} is now known as {1}.").format( |
706 self.tr("User {0} is now known as {1}.").format( |
613 oldNick, newNick)) |
707 oldNick, newNick)) |
614 return True |
708 return True |
|
709 elif name == "PONG": |
|
710 nick = match.group(3).split(":", 1)[1] |
|
711 self.networkWidget.addMessage( |
|
712 self.tr("Received PONG from {0}").format(nick)) |
|
713 return True |
615 elif name == "ERROR": |
714 elif name == "ERROR": |
616 self.networkWidget.addErrorMessage( |
715 self.networkWidget.addErrorMessage( |
617 self.tr("Server Error"), match.group(3).split(":", 1)[1]) |
716 self.tr("Server Error"), match.group(3).split(":", 1)[1]) |
618 return True |
717 return True |
619 |
718 |
747 """ |
846 """ |
748 for channel in self.networkWidget.getNetworkChannels(): |
847 for channel in self.networkWidget.getNetworkChannels(): |
749 if channel.autoJoin(): |
848 if channel.autoJoin(): |
750 name = channel.getName() |
849 name = channel.getName() |
751 key = channel.getKey() |
850 key = channel.getKey() |
752 self.__joinChannel(name, key) |
851 self.joinChannel(name, key) |
753 |
852 |
754 def __tcpError(self, error): |
853 def __tcpError(self, error): |
755 """ |
854 """ |
756 Private slot to handle errors reported by the TCP socket. |
855 Private slot to handle errors reported by the TCP socket. |
757 |
856 |