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, 4 Apr 2018 21:14:03 +0000 (23:14 +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.

(cherry picked from commit 56b2bf3a1a742971a5de7ced1b57024424fc78b8)

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 ec14064..31cc42e 100644 (file)
@@ -101,6 +101,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 5a41b98..7771527 100644 (file)
@@ -98,6 +98,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);
 
 public slots:
index ad59890..ed2904c 100644 (file)
@@ -449,6 +449,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 43e6754..554cab7 100644 (file)
@@ -59,6 +59,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 943727c..66f0e27 100644 (file)
@@ -342,6 +342,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 7c4c86d..4cfae10 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