Hide AutoWHO for nicks without IrcUser objects
authorShane Synan <digitalcircuit36939@gmail.com>
Thu, 29 Sep 2016 00:28:28 +0000 (19:28 -0500)
committerManuel Nickschas <sputnick@quassel-irc.org>
Thu, 13 Oct 2016 20:19:11 +0000 (22:19 +0200)
Don't require an IrcUser to exist when checking if WHO replies should
be hidden.  The nickname is enough for checking.

This mimics CoreSessionEventProcessor::processIrcEvent403, where
ERR_NOSUCHCHANNEL replies are hidden if nickname is in the list
regardless of whether or not an IrcUser object exists.

Potentially fixes AutoWHO replies showing in the server buffer when
nicks quickly join and leave channels, resulting in the IrcUser
object getting destroyed before the server replies to the AutoWHO
request.

It's difficult to recreate the issue on demand, so it's quite
possible there's more to fix.

Resolves GH-256.

src/core/coresessioneventprocessor.cpp

index c3e6cc1..e4621bf 100644 (file)
@@ -1008,16 +1008,24 @@ void CoreSessionEventProcessor::processIrcEvent352(IrcEvent *e)
         return;
 
     QString channel = e->params()[0];
-    IrcUser *ircuser = e->network()->ircUser(e->params()[4]);
+    // Store the nick separate from ircuser for AutoWho check below
+    QString nick = e->params()[4];
+    IrcUser *ircuser = e->network()->ircUser(nick);
     if (ircuser) {
+        // Only process the WHO information if an IRC user exists.  Don't create an IRC user here;
+        // there's no way to track when the user quits, which would leave a phantom IrcUser lying
+        // around.
+        // NOTE:  Whenever MONITOR support is introduced, the IrcUser will be created by an
+        // RPL_MONONLINE numeric before any WHO commands are run.
         processWhoInformation(e->network(), channel, ircuser, e->params()[3], e->params()[1],
                 e->params()[2], e->params()[5], e->params().last().section(" ", 1));
     }
 
     // Check if channel name has a who in progress.
-    // If not, then check if user nick exists and has a who in progress.
+    // If not, then check if user nickname has a who in progress.  Use nick directly; don't use
+    // ircuser as that may be deleted (e.g. nick joins channel, leaves before WHO reply received).
     if (coreNetwork(e)->isAutoWhoInProgress(channel) ||
-        (ircuser && coreNetwork(e)->isAutoWhoInProgress(ircuser->nick()))) {
+        (coreNetwork(e)->isAutoWhoInProgress(nick))) {
         e->setFlag(EventManager::Silent);
     }
 }
@@ -1104,8 +1112,14 @@ void CoreSessionEventProcessor::processIrcEvent354(IrcEvent *e)
         return;
 
     QString channel = e->params()[1];
-    IrcUser *ircuser = e->network()->ircUser(e->params()[5]);
+    QString nick = e->params()[5];
+    IrcUser *ircuser = e->network()->ircUser(nick);
     if (ircuser) {
+        // Only process the WHO information if an IRC user exists.  Don't create an IRC user here;
+        // there's no way to track when the user quits, which would leave a phantom IrcUser lying
+        // around.
+        // NOTE:  Whenever MONITOR support is introduced, the IrcUser will be created by an
+        // RPL_MONONLINE numeric before any WHO commands are run.
         processWhoInformation(e->network(), channel, ircuser, e->params()[4], e->params()[2],
                 e->params()[3], e->params()[6], e->params().last());
         // Don't use .section(" ", 1) with WHOX replies, for there's no hopcount to trim out
@@ -1123,9 +1137,10 @@ void CoreSessionEventProcessor::processIrcEvent354(IrcEvent *e)
     }
 
     // Check if channel name has a who in progress.
-    // If not, then check if user nick exists and has a who in progress.
+    // If not, then check if user nickname has a who in progress.  Use nick directly; don't use
+    // ircuser as that may be deleted (e.g. nick joins channel, leaves before WHO reply received).
     if (coreNetwork(e)->isAutoWhoInProgress(channel) ||
-        (ircuser && coreNetwork(e)->isAutoWhoInProgress(ircuser->nick()))) {
+        (coreNetwork(e)->isAutoWhoInProgress(nick))) {
         e->setFlag(EventManager::Silent);
     }
 }