Network/IRC/IrcChannelWidget.py

changeset 6514
f11a703e4664
parent 6513
e1fcd71fbda3
child 6532
f253f0f9ea7f
--- 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)))

eric ide

mercurial