diff -r e1fcd71fbda3 -r f11a703e4664 Network/IRC/IrcChannelWidget.py --- a/Network/IRC/IrcChannelWidget.py Fri Sep 28 20:07:25 2018 +0200 +++ b/Network/IRC/IrcChannelWidget.py Sat Sep 29 19:32:33 2018 +0200 @@ -9,10 +9,15 @@ from __future__ import unicode_literals +try: + from itertools import izip_longest as zip_longest # __IGNORE_EXCEPTION__ +except ImportError: + from itertools import zip_longest + import re from PyQt5.QtCore import pyqtSlot, pyqtSignal, QDateTime, QPoint, QFileInfo, \ - QTimer, QUrl + QTimer, QUrl, QCoreApplication from PyQt5.QtGui import QIcon, QPainter, QTextCursor, QDesktopServices from PyQt5.QtWidgets import QWidget, QListWidgetItem, QMenu, QApplication, \ QInputDialog, QLineEdit @@ -63,7 +68,9 @@ self.__privilege = IrcUserItem.Normal self.__name = name + self.__ignored = False + self.__setText() self.__setIcon() def name(self): @@ -81,7 +88,7 @@ @param name new nick name for the user (string) """ self.__name = name - self.setText(name) + self.__setText() def changePrivilege(self, privilege): """ @@ -106,6 +113,17 @@ self.__privilege = IrcUserItem.Normal self.__setIcon() + def __setText(self): + """ + Private method to set the user item text. + """ + if self.__ignored: + self.setText(QCoreApplication.translate( + "IrcUserItem", + "{0} (ignored)").format(self.__name)) + else: + self.setText(self.__name) + def __setIcon(self): """ Private method to set the icon dependent on user privileges. @@ -176,6 +194,25 @@ return(bool(self.__privilege & IrcUserItem.Operator) or bool(self.__privilege & IrcUserItem.Admin) or bool(self.__privilege & IrcUserItem.Owner)) + + def setIgnored(self, ignored): + """ + Public method to set the user status to ignored. + + @param ignored flag indicating the new ignored status + @type bool + """ + self.__ignored = ignored + self.__setText() + + def isIgnored(self): + """ + Public method to check, if this user is ignored. + + @return flag indicating the ignored status + @rtype bool + """ + return self.__ignored class IrcChannelWidget(QWidget, Ui_IrcChannelWidget): @@ -183,15 +220,24 @@ Class implementing the IRC channel widget. @signal sendData(str) emitted to send a message to the channel + @signal sendCtcpRequest(str, str, str) emitted to send a CTCP request @signal sendCtcpReply(str, str) emitted to send a CTCP reply @signal channelClosed(str) emitted after the user has left the channel @signal openPrivateChat(str) emitted to open a "channel" for private messages + @signal awayCommand(str) emitted to set the away status via the /away + command + @signal leaveChannels(list) emitted to leave a list of channels + @signal leaveAllChannels() emitted to leave all channels """ sendData = pyqtSignal(str) + sendCtcpRequest = pyqtSignal(str, str, str) sendCtcpReply = pyqtSignal(str, str) channelClosed = pyqtSignal(str) openPrivateChat = pyqtSignal(str) + awayCommand = pyqtSignal(str) + leaveChannels = pyqtSignal(list) + leaveAllChannels = pyqtSignal() UrlRe = re.compile( r"""((?:http|ftp|https):\/\/[\w\-_]+(?:\.[\w\-_]+)+""" @@ -358,6 +404,7 @@ Preferences.getIrc("OwnNickColour"), ircTimestamp(), self.__userName, Utilities.html_encode(msg))) + if msg.startswith("/"): if self.__private: E5MessageBox.information( @@ -367,9 +414,12 @@ """Messages starting with a '/' are not allowed""" """ in private chats.""")) else: + sendData = True + # flag set to False, if command was handled + msgList = msg.split() cmd = msgList[0][1:].upper() - if cmd == "MSG": + if cmd in ["MSG", "QUERY"]: cmd = "PRIVMSG" if len(msgList) > 1: if msgList[1].strip().lower() in \ @@ -383,9 +433,77 @@ else: msgList[0] = cmd msg = " ".join(msgList) + elif cmd == "NOTICE": + if len(msgList) > 2: + msg = "NOTICE {0} :{1}".format( + msgList[1], " ".join(msgList[2:])) + else: + msg = "NOTICE {0}".format(" ".join(msgList[1:])) + elif cmd == "PING": + receiver = msgList[1] + msg = "PING {0} " + self.sendCtcpRequest.emit(receiver, "PING", "") + sendData = False + elif cmd == "IGNORE": + sendData = False + if len(msgList) > 1: + if msgList[1] == "-r": + ignored = False + userNamesList = msgList[2:] + else: + ignored = True + userNamesList = msgList[1:] + else: + userNamesList = [] + userNames = ",".join( + u.rstrip(",") for u in userNamesList).split(",") + for userName in userNames: + itm = self.__findUser(userName) + if itm: + itm.setIgnored(ignored) + elif cmd == "UNIGNORE": + sendData = False + if len(msgList) > 1: + userNamesList = msgList[1:] + else: + userNamesList = [] + userNames = ",".join( + u.rstrip(",") for u in userNamesList).split(",") + for userName in userNames: + itm = self.__findUser(userName) + if itm: + itm.setIgnored(False) + elif cmd == "AWAY": + sendData = False + if len(msgList) > 1: + msg = " ".join(msgList[1:]) + else: + msg = "" + self.awayCommand.emit(msg) + elif cmd == "JOIN": + sendData = False + if len(msgList) > 1: + channels = msgList[1].split(",") + if len(msgList) > 2: + keys = msgList[2].split(",") + else: + keys = [] + for channel, key in zip_longest( + channels, keys, fillvalue=""): + self.__ircWidget.joinChannel(channel, key) + elif cmd == "PART": + sendData = False + if len(msgList) == 1: + self.leaveChannel() + else: + self.leaveChannels.emit(msgList[1:]) + elif cmd == "PARTALL": + sendData = False + self.leaveAllChannels.emit() else: msg = msg[1:] - self.sendData.emit(msg) + if sendData: + self.sendData.emit(msg) else: if self.__private: self.sendData.emit( @@ -393,6 +511,7 @@ else: self.sendData.emit( "PRIVMSG " + self.__name + " :" + msg) + self.messageEdit.clear() self.unsetMarkerLine() @@ -404,13 +523,19 @@ self, self.tr("Leave IRC channel"), self.tr( - """Do you really want to leave the IRC channel <b>{0}</b>?""") - .format(self.__name)) + """Do you really want to leave the IRC channel""" + """ <b>{0}</b>?""").format(self.__name)) if ok: - if not self.__private: - self.sendData.emit( - "PART " + self.__name + " :" + self.__partMessage) - self.channelClosed.emit(self.__name) + self.leaveChannel() + + def leaveChannel(self): + """ + Public slot to leave the channel. + """ + if not self.__private: + self.sendData.emit( + "PART " + self.__name + " :" + self.__partMessage) + self.channelClosed.emit(self.__name) def name(self): """ @@ -515,10 +640,16 @@ # group(3) target nick # group(4) message if match.group(3).lower() == self.__name.lower(): + senderName = match.group(1) + itm = self.__findUser(senderName) + if itm and itm.isIgnored(): + # user should be ignored + return True + if match.group(4).startswith("\x01"): return self.__handleCtcp(match) - self.addMessage(match.group(1), match.group(4)) + self.addMessage(senderName, match.group(4)) if self.__private and not self.topicLabel.text(): self.setPrivateInfo( "{0} - {1}".format(match.group(1), match.group(2)))