Add support for multi-prefix
authorShane Synan <digitalcircuit36939@gmail.com>
Fri, 19 Feb 2016 08:25:10 +0000 (02:25 -0600)
committerShane Synan <digitalcircuit36939@gmail.com>
Fri, 19 Feb 2016 08:35:51 +0000 (02:35 -0600)
Add support for multi-prefix to get a full list of modes in NAMES and
WHO replies, updating ircuser objects as appropriate.  This enables
seeing if an operator (+o) also has voice (+v), etc.  In the future,
Quassel could show this information in a smart, useful manner.

This commit limits synced modes to one for 'NAMES' replies to avoid a
warning in older clients.  The next commit will address this.

See http://ircv3.net/specs/extensions/multi-prefix-3.1.html

src/core/corenetwork.h
src/core/coresessioneventprocessor.cpp

index e3ef945..ae1ebd8 100644 (file)
@@ -177,6 +177,15 @@ public:
      */
     inline bool useCapUserhostInNames() const { return capEnabled("userhost-in-names"); }
 
+    /**
+     * Gets the status of the multi-prefix capability.
+     *
+     * http://ircv3.net/specs/extensions/multi-prefix-3.1.html
+     *
+     * @returns True if multi-prefix is enabled, otherwise false
+     */
+    inline bool useCapMultiPrefix() const { return capEnabled("multi-prefix"); }
+
 public slots:
     virtual void setMyNick(const QString &mynick);
 
index ca9b92d..43f44db 100644 (file)
@@ -194,7 +194,8 @@ void CoreSessionEventProcessor::processIrcEventCap(IrcEvent *e)
                 } else if (availableCapPair.at(0).startsWith("away-notify") ||
                            availableCapPair.at(0).startsWith("account-notify") ||
                            availableCapPair.at(0).startsWith("extended-join") ||
-                           availableCapPair.at(0).startsWith("userhost-in-names")) {
+                           availableCapPair.at(0).startsWith("userhost-in-names") ||
+                           availableCapPair.at(0).startsWith("multi-prefix")) {
                     // Always request these capabilities if available
                     queueCurrentCap = true;
                 }
@@ -918,10 +919,32 @@ void CoreSessionEventProcessor::processIrcEvent352(IrcEvent *e)
         ircuser->setUser(e->params()[1]);
         ircuser->setHost(e->params()[2]);
 
-        bool away = e->params()[5].startsWith("G");
+        bool away = e->params()[5].contains("G", Qt::CaseInsensitive);
         ircuser->setAway(away);
         ircuser->setServer(e->params()[3]);
         ircuser->setRealName(e->params().last().section(" ", 1));
+
+        if (coreNetwork(e)->useCapMultiPrefix()) {
+            // If multi-prefix is enabled, all modes will be sent in WHO replies.
+            // :kenny.chatspike.net 352 guest #test grawity broken.symlink *.chatspike.net grawity H@%+ :0 Mantas M.
+            // See: http://ircv3.net/specs/extensions/multi-prefix-3.1.html
+            QString uncheckedModes = e->params()[5];
+            QString validModes = QString();
+            while (!uncheckedModes.isEmpty()) {
+                // Mode found in 1 left-most character, add it to the list
+                if (e->network()->prefixes().contains(uncheckedModes[0])) {
+                    validModes.append(e->network()->prefixToMode(uncheckedModes[0]));
+                }
+                // Remove this mode from the list of unchecked modes
+                uncheckedModes = uncheckedModes.remove(0, 1);
+            }
+
+            // Some IRC servers decide to not follow the spec, returning only -some- of the user
+            // modes in WHO despite listing them all in NAMES.  For now, assume it can only add
+            // and not take away.  *sigh*
+            if (!validModes.isEmpty())
+                ircuser->addUserModes(validModes);
+        }
     }
 
     // Check if channel name has a who in progress.
@@ -952,10 +975,27 @@ void CoreSessionEventProcessor::processIrcEvent353(IrcEvent *e)
     QStringList nicks;
     QStringList modes;
 
+    // Cache result of multi-prefix to avoid unneeded casts and lookups with each iteration.
+    bool _useCapMultiPrefix = coreNetwork(e)->useCapMultiPrefix();
+
     foreach(QString nick, e->params()[2].split(' ', QString::SkipEmptyParts)) {
         QString mode;
 
-        if (e->network()->prefixes().contains(nick[0])) {
+        if (_useCapMultiPrefix) {
+            // If multi-prefix is enabled, all modes will be sent in NAMES replies.
+            // :hades.arpa 353 guest = #tethys :~&@%+aji &@Attila @+alyx +KindOne Argure
+            // See: http://ircv3.net/specs/extensions/multi-prefix-3.1.html
+            while (e->network()->prefixes().contains(nick[0])) {
+                // Mode found in 1 left-most character, add it to the list.
+                // FIXME Only allow one possible mode to avoid a warning in older clients
+                if (mode.isEmpty())
+                    mode.append(e->network()->prefixToMode(nick[0]));
+                //mode.append(e->network()->prefixToMode(nick[0]));
+                // Remove this mode from the nick
+                nick = nick.remove(0, 1);
+            }
+        } else if (e->network()->prefixes().contains(nick[0])) {
+            // Multi-prefix is disabled and a mode prefix was found.
             mode = e->network()->prefixToMode(nick[0]);
             nick = nick.mid(1);
         }