Simplify CTCP parsing by default
authorBas Pape <baspape@gmail.com>
Tue, 25 Sep 2012 18:57:14 +0000 (20:57 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Tue, 19 Feb 2013 20:50:55 +0000 (21:50 +0100)
Rather than adhering to the CTCP 'specification', reply only to single
CTCP messages without text around them. All messages not fitting the
requirements are simply displayed in the buffer. The old behaviour can
still be enabled in the settings dialog.

Fixes #1130

src/common/networkconfig.cpp
src/common/networkconfig.h
src/core/corenetworkconfig.h
src/core/ctcpparser.cpp
src/core/ctcpparser.h
src/qtui/settingspages/connectionsettingspage.cpp
src/qtui/settingspages/connectionsettingspage.ui

index 17a37b4..066988f 100644 (file)
@@ -29,7 +29,8 @@ NetworkConfig::NetworkConfig(const QString &objectName, QObject *parent)
     _autoWhoEnabled(true),
     _autoWhoInterval(90),
     _autoWhoNickLimit(200),
-    _autoWhoDelay(5)
+    _autoWhoDelay(5),
+    _standardCtcp(false)
 {
 }
 
@@ -107,3 +108,14 @@ void NetworkConfig::setAutoWhoDelay(int delay)
     SYNC(ARG(delay))
     emit autoWhoDelaySet(delay);
 }
+
+
+void NetworkConfig::setStandardCtcp(bool enabled)
+{
+    if (_standardCtcp == enabled)
+        return;
+
+    _standardCtcp = enabled;
+    SYNC(ARG(enabled))
+    emit standardCtcpSet(enabled);
+}
index 3d18077..ae121aa 100644 (file)
@@ -35,6 +35,7 @@ class NetworkConfig : public SyncableObject
     Q_PROPERTY(int autoWhoInterval READ autoWhoInterval WRITE setAutoWhoInterval)
     Q_PROPERTY(int autoWhoNickLimit READ autoWhoNickLimit WRITE setAutoWhoNickLimit)
     Q_PROPERTY(int autoWhoDelay READ autoWhoDelay WRITE setAutoWhoDelay)
+    Q_PROPERTY(bool standardCtcp READ standardCtcp WRITE setStandardCtcp)
 
 public :
         NetworkConfig(const QString &objectName = "GlobalNetworkConfig", QObject *parent = 0);
@@ -70,6 +71,10 @@ public slots:
     void setAutoWhoDelay(int);
     virtual inline void requestSetAutoWhoDelay(int i) { REQUEST(ARG(i)) }
 
+    inline bool standardCtcp() const { return _standardCtcp; }
+    void setStandardCtcp(bool);
+    virtual inline void requestSetStandardCtcp(bool b) { REQUEST(ARG(b)) }
+
 signals:
     void pingTimeoutEnabledSet(bool);
     void pingIntervalSet(int);
@@ -78,6 +83,7 @@ signals:
     void autoWhoIntervalSet(int);
 //   void autoWhoNickLimitSet(int);
     void autoWhoDelaySet(int);
+    void standardCtcpSet(bool);
 
 //   void setPingTimeoutEnabledRequested(bool);
 //   void setPingIntervalRequested(int);
@@ -96,6 +102,8 @@ private:
     int _autoWhoInterval;
     int _autoWhoNickLimit;
     int _autoWhoDelay;
+
+    bool _standardCtcp;
 };
 
 
index d906dcb..e045697 100644 (file)
@@ -45,6 +45,7 @@ public slots:
     virtual inline void requestSetAutoWhoInterval(int interval) { setAutoWhoInterval(interval); }
     virtual inline void requestSetAutoWhoNickLimit(int nickLimit) { setAutoWhoNickLimit(nickLimit); }
     virtual inline void requestSetAutoWhoDelay(int delay) { setAutoWhoDelay(delay); }
+    virtual inline void requestSetStandardCtcp(bool enabled) { setStandardCtcp(enabled); }
 };
 
 
index cddb6e1..ee300df 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "ctcpparser.h"
 
+#include "corenetworkconfig.h"
 #include "coresession.h"
 #include "ctcpevent.h"
 #include "messageevent.h"
@@ -148,8 +149,6 @@ void CtcpParser::processIrcEventRawPrivmsg(IrcEventRawMessage *event)
 
 void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype)
 {
-    QByteArray ctcp;
-
     //lowlevel message dequote
     QByteArray dequotedMessage = lowLevelDequote(e->rawMessage());
 
@@ -161,6 +160,53 @@ void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype)
                            ? Message::Redirected
                            : Message::None;
 
+    if (coreSession()->networkConfig()->standardCtcp())
+        parseStandard(e, messagetype, dequotedMessage, ctcptype, flags);
+    else
+        parseSimple(e, messagetype, dequotedMessage, ctcptype, flags);
+}
+
+
+// only accept CTCPs in their simplest form, i.e. one ctcp, from start to
+// end, no text around it; not as per the 'specs', but makes people happier
+void CtcpParser::parseSimple(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags)
+{
+    if (dequotedMessage.count(XDELIM) != 2 || dequotedMessage[0] != '\001' || dequotedMessage[dequotedMessage.count() -1] != '\001') {
+        displayMsg(e, messagetype, targetDecode(e, dequotedMessage), e->prefix(), e->target(), flags);
+    } else {
+        int spacePos = -1;
+        QString ctcpcmd, ctcpparam;
+
+        QByteArray ctcp = xdelimDequote(dequotedMessage.mid(1, dequotedMessage.count() - 2));
+        spacePos = ctcp.indexOf(' ');
+        if (spacePos != -1) {
+            ctcpcmd = targetDecode(e, ctcp.left(spacePos));
+            ctcpparam = targetDecode(e, ctcp.mid(spacePos + 1));
+        } else {
+            ctcpcmd = targetDecode(e, ctcp);
+            ctcpparam = QString();
+        }
+        ctcpcmd = ctcpcmd.toUpper();
+
+        // we don't want to block /me messages by the CTCP ignore list
+        if (ctcpcmd == QLatin1String("ACTION") || !coreSession()->ignoreListManager()->ctcpMatch(e->prefix(), e->network()->networkName(), ctcpcmd)) {
+            QUuid uuid = QUuid::createUuid();
+            _replies.insert(uuid, CtcpReply(coreNetwork(e), nickFromMask(e->prefix())));
+            CtcpEvent *event = new CtcpEvent(EventManager::CtcpEvent, e->network(), e->prefix(), e->target(),
+                ctcptype, ctcpcmd, ctcpparam, e->timestamp(), uuid);
+            emit newEvent(event);
+            CtcpEvent *flushEvent = new CtcpEvent(EventManager::CtcpEventFlush, e->network(), e->prefix(), e->target(),
+                ctcptype, "INVALID", QString(), e->timestamp(), uuid);
+            emit newEvent(flushEvent);
+        }
+    }
+}
+
+
+void CtcpParser::parseStandard(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags)
+{
+    QByteArray ctcp;
+
     QList<CtcpEvent *> ctcpEvents;
     QUuid uuid; // needed to group all replies together
 
index 255539e..d3f50c9 100644 (file)
@@ -26,6 +26,7 @@
 #include "corenetwork.h"
 #include "eventmanager.h"
 #include "ircevent.h"
+#include "ctcpevent.h"
 
 class CoreSession;
 class CtcpEvent;
@@ -63,6 +64,8 @@ protected:
         Message::Flags msgFlags = Message::None);
 
     void parse(IrcEventRawMessage *event, Message::Type msgType);
+    void parseSimple(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags);
+    void parseStandard(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags);
 
     QByteArray lowLevelQuote(const QByteArray &);
     QByteArray lowLevelDequote(const QByteArray &);
index 3d4ac7a..4fcc70a 100644 (file)
@@ -85,6 +85,8 @@ QVariant ConnectionSettingsPage::loadAutoWidgetValue(const QString &widgetName)
         return config->autoWhoNickLimit();
     if (widgetName == "autoWhoDelay")
         return config->autoWhoDelay();
+    if (widgetName == "standardCtcp")
+        return config->standardCtcp();
 
     return SettingsPage::loadAutoWidgetValue(widgetName);
 }
@@ -109,6 +111,8 @@ void ConnectionSettingsPage::saveAutoWidgetValue(const QString &widgetName, cons
         config->requestSetAutoWhoNickLimit(value.toInt());
     else if (widgetName == "autoWhoDelay")
         config->requestSetAutoWhoDelay(value.toInt());
+    else if (widgetName == "standardCtcp")
+        config->requestSetStandardCtcp(value.toBool());
 
     else
         SettingsPage::saveAutoWidgetValue(widgetName, value);
index 484454c..e1ca248 100644 (file)
      </layout>
     </widget>
    </item>
+   <item>
+    <widget class="QCheckBox" name="standardCtcp">
+     <property name="text">
+      <string>Enable standard-compliant CTCP behavior</string>
+     </property>
+     <property name="settingsKey" stdset="0">
+      <string notr="true" />
+     </property>
+    </widget>
+   </item>
    <item>
     <spacer name="verticalSpacer">
      <property name="orientation">