Show IRC server error messages when unexpected
authorShane Synan <digitalcircuit36939@gmail.com>
Tue, 6 Sep 2016 21:33:58 +0000 (16:33 -0500)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 14 Sep 2016 20:45:38 +0000 (22:45 +0200)
Handle ERROR replies from IRC servers, displaying the error message
in the status buffer.

Add method 'disconnectExpected' to CoreNetwork to expose when a
disconnect is expected.  As we're expecting a server error message
when issuing QUIT, hide it to avoid showing redundant information.

This fixes users getting disconnected by the server without any way
to find out why.

Resolves GH-238.

src/common/eventmanager.h
src/core/corenetwork.h
src/core/coresessioneventprocessor.cpp
src/core/coresessioneventprocessor.h
src/core/eventstringifier.cpp
src/core/eventstringifier.h

index 2d88143..33c41c9 100644 (file)
@@ -104,6 +104,7 @@ public :
         IrcEventPrivmsg,
         IrcEventQuit,
         IrcEventTopic,
+        IrcEventError,        /// ERROR message from server
         IrcEventWallops,
         IrcEventRawPrivmsg, ///< Undecoded privmsg (still needs CTCP parsing)
         IrcEventRawNotice, ///< Undecoded notice (still needs CTCP parsing)
index 8201b43..4d4e673 100644 (file)
@@ -101,6 +101,15 @@ public:
     inline quint16 localPort() const { return socket.localPort(); }
     inline quint16 peerPort() const { return socket.peerPort(); }
 
+    /**
+     * Gets whether or not a disconnect was expected.
+     *
+     * Distinguishes desired quits from unexpected disconnections such as socket errors or timeouts.
+     *
+     * @return True if disconnect was requested, otherwise false.
+     */
+    inline bool disconnectExpected() const { return _disconnectExpected; }
+
     QList<QList<QByteArray>> splitMessage(const QString &cmd, const QString &message, std::function<QList<QByteArray>(QString &)> cmdGenerator);
 
     // IRCv3 capability negotiation
index eef1e26..c3e6cc1 100644 (file)
@@ -662,6 +662,21 @@ void CoreSessionEventProcessor::processIrcEventTopic(IrcEvent *e)
     }
 }
 
+/* ERROR - "ERROR :reason"
+Example:  ERROR :Closing Link: nickname[xxx.xxx.xxx.xxx] (Large base64 image paste.)
+See https://tools.ietf.org/html/rfc2812#section-3.7.4 */
+void CoreSessionEventProcessor::processIrcEventError(IrcEvent *e)
+{
+    if (!checkParamCount(e, 1))
+        return;
+
+    if (coreNetwork(e)->disconnectExpected()) {
+        // During QUIT, the server should send an error (often, but not always, "Closing Link"). As
+        // we're expecting it, don't show this to the user.
+        e->setFlag(EventManager::Silent);
+    }
+}
+
 
 #ifdef HAVE_QCA2
 void CoreSessionEventProcessor::processKeyEvent(KeyEvent *e)
index 3a1070d..52aa3db 100644 (file)
@@ -62,6 +62,7 @@ public:
     Q_INVOKABLE void processIrcEventQuit(IrcEvent *event);
     Q_INVOKABLE void lateProcessIrcEventQuit(IrcEvent *event);
     Q_INVOKABLE void processIrcEventTopic(IrcEvent *event);
+    Q_INVOKABLE void processIrcEventError(IrcEvent *event);       /// ERROR message from server
 #ifdef HAVE_QCA2
     Q_INVOKABLE void processKeyEvent(KeyEvent *event);
 #endif
index f18af10..6ef3f8a 100644 (file)
@@ -356,6 +356,15 @@ void EventStringifier::processIrcEventTopic(IrcEvent *e)
         .arg(e->nick(), e->params().at(0), e->params().at(1)), QString(), e->params().at(0));
 }
 
+void EventStringifier::processIrcEventError(IrcEvent *e)
+{
+    // Need an error reason
+    if (!checkParamCount(e, 1))
+        return;
+
+    displayMsg(e, Message::Server, tr("Error from server: ") + e->params().join(""));
+}
+
 void EventStringifier::processIrcEventWallops(IrcEvent *e)
 {
     displayMsg(e, Message::Server, tr("[Operwall] %1: %2").arg(e->nick(), e->params().join(" ")));
index bef6ab8..499a766 100644 (file)
@@ -64,6 +64,7 @@ public:
     Q_INVOKABLE void processIrcEventPong(IrcEvent *event);
     Q_INVOKABLE void processIrcEventQuit(IrcEvent *event);
     Q_INVOKABLE void processIrcEventTopic(IrcEvent *event);
+    Q_INVOKABLE void processIrcEventError(IrcEvent *event);    /// ERROR message from server
     Q_INVOKABLE void processIrcEventWallops(IrcEvent *event);
 
     Q_INVOKABLE void processIrcEvent005(IrcEvent *event);    // RPL_ISUPPORT