Handle STATUSMSG messages
authorMichael Marley <michael@michaelmarley.com>
Wed, 23 Mar 2016 20:47:02 +0000 (16:47 -0400)
committerMichael Marley <michael@michaelmarley.com>
Thu, 24 Mar 2016 00:35:22 +0000 (20:35 -0400)
Previously PRIVMSGs to channels prefixed with certain characters
(usually "+" or "@") (example "@#quassel") would appear in new
query buffers instead of in the channel buffer.  People were using
that problem to broadcast query SPAM in active channels such as

This patch fixes the issue by detecting the condition, first in
ircparser.cpp where it will use the channel name instead of the
sender's nick as the target.  ctcpparser.cpp then sees the prefixed
channel name and reacts by truncating the prefix(es) and setting a
new flag so that the client can tell the message was a STATUSMSG.
A look-ahead system is used to ensure that the channel prefix
character is not stripped even when the channel prefix characters
and STATUSMSG prefix characters overlap.

The server-provided STATUSMSG prefixes are used if available,
otherwise "@" and "+" are used.

This patch doesn't make the client display the STATUSMSGs any
differently than regular messages.  I omitted this because there
was some discussion on the channel about the best way to display
these messages, but no conclusion was ever reached.  This patch
will at least stop the query SPAM and also provides the
infrastructure necessary to change the display format later.

src/common/message.h
src/common/network.cpp
src/common/network.h
src/core/ctcpparser.cpp
src/core/ircparser.cpp

index 402faea..a7fb493 100644 (file)
@@ -61,6 +61,7 @@ public:
         Highlight = 0x02,
         Redirected = 0x04,
         ServerMsg = 0x08,
+        StatusMsg = 0x10,
         Backlog = 0x80
     };
     Q_DECLARE_FLAGS(Flags, Flag)
index 24ce125..54d0366 100644 (file)
@@ -77,6 +77,18 @@ bool Network::isChannelName(const QString &channelname) const
 }
 
 
+bool Network::isStatusMsg(const QString &target) const
+{
+    if (target.isEmpty())
+        return false;
+
+    if (supports("STATUSMSG"))
+        return support("STATUSMSG").contains(target[0]);
+    else
+        return QString("@+").contains(target[0]);
+}
+
+
 NetworkInfo Network::networkInfo() const
 {
     NetworkInfo info;
index 190c62c..c6f8f67 100644 (file)
@@ -131,6 +131,7 @@ public :
     inline bool isMe(IrcUser *ircuser) const { return (ircuser->nick().toLower() == myNick().toLower()); }
 
     bool isChannelName(const QString &channelname) const;
+    bool isStatusMsg(const QString &target) const;
 
     inline bool isConnected() const { return _connected; }
     //Network::ConnectionState connectionState() const;
index d2da841..f5257bb 100644 (file)
@@ -171,6 +171,27 @@ void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype)
                            ? Message::Redirected
                            : Message::None;
 
+    bool isStatusMsg = false;
+
+    // First remove all statusmsg prefix characters that are not also channel prefix characters.
+    while (e->network()->isStatusMsg(e->target()) && !e->network()->isChannelName(e->target())) {
+        isStatusMsg = true;
+        e->setTarget(e->target().remove(0, 1));
+    }
+
+    // Then continue removing statusmsg characters as long as removing the character will still result in a
+    // valid channel name.  This prevents removing the channel prefix character if said character is in the
+    // overlap between the statusmsg characters and the channel prefix characters.
+    while (e->network()->isStatusMsg(e->target()) && e->network()->isChannelName(e->target().remove(0, 1))) {
+        isStatusMsg = true;
+        e->setTarget(e->target().remove(0, 1));
+    }
+
+    // If any statusmsg characters were removed, Flag the message as a StatusMsg.
+    if (isStatusMsg) {
+        flags |= Message::StatusMsg;
+    }
+
     if (coreSession()->networkConfig()->standardCtcp())
         parseStandard(e, messagetype, dequotedMessage, ctcptype, flags);
     else
index 681346c..dec7b78 100644 (file)
@@ -186,7 +186,7 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e)
             QStringList targets = net->serverDecode(params.at(0)).split(',', QString::SkipEmptyParts);
             QStringList::const_iterator targetIter;
             for (targetIter = targets.constBegin(); targetIter != targets.constEnd(); ++targetIter) {
-                QString target = net->isChannelName(*targetIter) ? *targetIter : senderNick;
+                QString target = net->isChannelName(*targetIter) || net->isStatusMsg(*targetIter) ? *targetIter : senderNick;
 
                 msg = decrypt(net, target, msg);