Encourage SASL over NickServ when server supports
authorShane Synan <digitalcircuit36939@gmail.com>
Sun, 4 Dec 2016 09:12:02 +0000 (03:12 -0600)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 12 Apr 2017 21:30:16 +0000 (23:30 +0200)
Move Use SASL Authentication above Auto Identify.

Change the label for SASL according to whether or not SASL support
is advertised by the network.  If disconnected or unknown, no change.
Otherwise, set to "Use SASL Authentication (preferred)" when known,
or "Use SASL Authentication (might not work)" when not advertised.

Unfortunately there's no way to be sure, but this seems to do the
right thing.  One can still enable and disable as before.

Add explanatory tooltips to authentication options, including
recommending SASL if you need to identify before joining channels
(this gets asked a lot in #quassel).

src/qtui/settingspages/networkssettingspage.cpp
src/qtui/settingspages/networkssettingspage.h
src/qtui/settingspages/networkssettingspage.ui

index bcdc6cf..52f062f 100644 (file)
@@ -32,6 +32,9 @@
 #include "settingspagedlg.h"
 #include "util.h"
 
+// IRCv3 capabilities
+#include "irccap.h"
+
 #include "settingspages/identitiessettingspage.h"
 
 NetworksSettingsPage::NetworksSettingsPage(QWidget *parent)
@@ -89,12 +92,12 @@ NetworksSettingsPage::NetworksSettingsPage(QWidget *parent)
     connect(ui.identityList, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
     //connect(ui.randomServer, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
     connect(ui.performEdit, SIGNAL(textChanged()), this, SLOT(widgetHasChanged()));
-    connect(ui.autoIdentify, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
-    connect(ui.autoIdentifyService, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
-    connect(ui.autoIdentifyPassword, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
     connect(ui.sasl, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
     connect(ui.saslAccount, SIGNAL(textEdited(QString)), this, SLOT(widgetHasChanged()));
     connect(ui.saslPassword, SIGNAL(textEdited(QString)), this, SLOT(widgetHasChanged()));
+    connect(ui.autoIdentify, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
+    connect(ui.autoIdentifyService, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
+    connect(ui.autoIdentifyPassword, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
     connect(ui.useCustomEncodings, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
     connect(ui.sendEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
     connect(ui.recvEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
@@ -348,6 +351,43 @@ void NetworksSettingsPage::setItemState(NetworkId id, QListWidgetItem *item)
 }
 
 
+void NetworksSettingsPage::setNetworkCapStates(NetworkId id)
+{
+    const Network *net = Client::network(id);
+    if ((Client::coreFeatures() & Quassel::CapNegotiation)
+            && net && net->connectionState() != Network::Disconnected) {
+        // If Capability Negotiation isn't supported by the core, no capabilities are active.
+        // If we're here, the network exists and is connected, check available capabilities...
+        // Don't use net->isConnected() as that won't be true during capability negotiation when
+        // capabilities are added and removed.
+
+        // [SASL]
+        if (net->saslMaybeSupports(IrcCap::SaslMech::PLAIN)) {
+            // The network advertises support for SASL PLAIN.  Encourage using it!  Unfortunately we
+            // don't know for sure if it's desired or functional.
+            ui.sasl->setTitle(QString("%1 (%2)").arg(tr("Use SASL Authentication"),
+                                                     tr("preferred")));
+        } else {
+            // The network doesn't advertise support for SASL PLAIN.  Here be dragons.
+            ui.sasl->setTitle(QString("%1 (%2)").arg(tr("Use SASL Authentication"),
+                                                     tr("might not work")));
+        }
+        // Split up the messages to ease translation and re-use existing "Use SASL Authentication"
+        // translations.  If some languages rearrange phrases such that this would not make sense,
+        // these strings can be merged into one.
+
+        // Add additional capability-dependent interface updates here
+    } else {
+        // We're not connected or the network doesn't yet exist.  Don't assume anything and reset
+        // all capability-dependent interface elements to neutral.
+        // [SASL]
+        ui.sasl->setTitle(tr("Use SASL Authentication"));
+
+        // Add additional capability-dependent interface updates here
+    }
+}
+
+
 void NetworksSettingsPage::coreConnectionStateChanged(bool state)
 {
     this->setEnabled(state);
@@ -434,6 +474,10 @@ void NetworksSettingsPage::clientNetworkAdded(NetworkId id)
 
     connect(Client::network(id), SIGNAL(connectionStateSet(Network::ConnectionState)), this, SLOT(networkConnectionStateChanged(Network::ConnectionState)));
     connect(Client::network(id), SIGNAL(connectionError(const QString &)), this, SLOT(networkConnectionError(const QString &)));
+
+    // Handle capability changes in case a server dis/connects with the settings window open.
+    connect(Client::network(id), SIGNAL(capAdded(const QString &)), this, SLOT(clientNetworkCapsUpdated()));
+    connect(Client::network(id), SIGNAL(capRemoved(const QString &)), this, SLOT(clientNetworkCapsUpdated()));
 }
 
 
@@ -478,6 +522,11 @@ void NetworksSettingsPage::networkConnectionStateChanged(Network::ConnectionStat
     }
     */
     setItemState(net->networkId());
+    if (net->networkId() == currentId) {
+        // Network is currently shown.  Update the capability-dependent UI in case capabilities have
+        // changed.
+        setNetworkCapStates(currentId);
+    }
     setWidgetStates();
 }
 
@@ -545,6 +594,8 @@ void NetworksSettingsPage::displayNetwork(NetworkId id)
         }
         //setItemState(id);
         //ui.randomServer->setChecked(info.useRandomServer);
+        // Update the capability-dependent UI in case capabilities have changed.
+        setNetworkCapStates(id);
         ui.performEdit->setPlainText(info.perform.join("\n"));
         ui.autoIdentify->setChecked(info.useAutoIdentify);
         ui.autoIdentifyService->setText(info.autoIdentifyService);
@@ -635,6 +686,22 @@ void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo &info)
 }
 
 
+void NetworksSettingsPage::clientNetworkCapsUpdated()
+{
+    // Grab the updated network
+    const Network *net = qobject_cast<const Network *>(sender());
+    if (!net) {
+        qWarning() << "Update request for unknown network received!";
+        return;
+    }
+    if (net->networkId() == currentId) {
+        // Network is currently shown.  Update the capability-dependent UI in case capabilities have
+        // changed.
+        setNetworkCapStates(currentId);
+    }
+}
+
+
 #ifdef HAVE_SSL
 void NetworksSettingsPage::sslUpdated()
 {
index d760621..e88f281 100644 (file)
@@ -58,6 +58,16 @@ private slots:
     void displayNetwork(NetworkId);
     void setItemState(NetworkId, QListWidgetItem *item = 0);
 
+    /**
+     * Update the capability-dependent settings according to what the server supports
+     *
+     * For example, this updates the SASL text for when the server advertises support.  This should
+     * only be called on the currently displayed network.
+     *
+     * @param[in] id  NetworkId referencing network used to update settings user interface.
+     */
+    void setNetworkCapStates(NetworkId id);
+
     void clientNetworkAdded(NetworkId);
     void clientNetworkRemoved(NetworkId);
     void clientNetworkUpdated();
@@ -66,6 +76,11 @@ private slots:
     void clientIdentityRemoved(IdentityId);
     void clientIdentityUpdated();
 
+    /**
+     * Update the settings user interface according to capabilities advertised by the IRC server
+     */
+    void clientNetworkCapsUpdated();
+
 #ifdef HAVE_SSL
     void sslUpdated();
 #endif
index 5b93160..160c6b3 100644 (file)
@@ -664,12 +664,15 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
          </attribute>
          <layout class="QVBoxLayout" name="verticalLayout_4">
           <item>
-           <widget class="QGroupBox" name="autoIdentify">
+           <widget class="QGroupBox" name="sasl">
             <property name="enabled">
              <bool>true</bool>
             </property>
+            <property name="toolTip">
+             <string>Authenticate using your nickname and password before joining any channels</string>
+            </property>
             <property name="title">
-             <string>Auto Identify</string>
+             <string>Use SASL Authentication</string>
             </property>
             <property name="checkable">
              <bool>true</bool>
@@ -677,41 +680,50 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
             <property name="checked">
              <bool>true</bool>
             </property>
-            <layout class="QGridLayout" name="gridLayout">
-             <item row="0" column="1">
-              <widget class="QLineEdit" name="autoIdentifyService">
+            <layout class="QGridLayout" name="gridLayout_2">
+             <item row="1" column="1">
+              <widget class="QLineEdit" name="saslPassword">
                <property name="enabled">
                 <bool>true</bool>
                </property>
-               <property name="text">
-                <string>NickServ</string>
+               <property name="toolTip">
+                <string>Account password</string>
+               </property>
+               <property name="echoMode">
+                <enum>QLineEdit::Password</enum>
                </property>
               </widget>
              </item>
-             <item row="1" column="1">
-              <widget class="QLineEdit" name="autoIdentifyPassword">
+             <item row="1" column="0">
+              <widget class="QLabel" name="saslPasswordLabel">
                <property name="enabled">
                 <bool>true</bool>
                </property>
-               <property name="echoMode">
-                <enum>QLineEdit::Password</enum>
+               <property name="text">
+                <string>Password:</string>
                </property>
               </widget>
              </item>
              <item row="0" column="0">
-              <widget class="QLabel" name="label_2">
+              <widget class="QLabel" name="saslAccountLabel">
+               <property name="enabled">
+                <bool>true</bool>
+               </property>
                <property name="text">
-                <string>Service:</string>
+                <string>Account:</string>
                </property>
               </widget>
              </item>
-             <item row="1" column="0">
-              <widget class="QLabel" name="label_3">
+             <item row="0" column="1">
+              <widget class="QLineEdit" name="saslAccount">
                <property name="enabled">
                 <bool>true</bool>
                </property>
+               <property name="toolTip">
+                <string>Account name, often the same as your nickname</string>
+               </property>
                <property name="text">
-                <string>Password:</string>
+                <string/>
                </property>
               </widget>
              </item>
@@ -719,12 +731,25 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
            </widget>
           </item>
           <item>
-           <widget class="QGroupBox" name="sasl">
+           <widget class="QLabel" name="saslExtInfo">
+            <property name="text">
+             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Note:&lt;/span&gt; because the identity has an ssl certificate set, SASL EXTERNAL will be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QGroupBox" name="autoIdentify">
             <property name="enabled">
              <bool>true</bool>
             </property>
+            <property name="toolTip">
+             <string>Authenticate to services using your password.  Use SASL instead to identify before joining channels.</string>
+            </property>
             <property name="title">
-             <string>Use SASL Authentication</string>
+             <string>Auto Identify</string>
             </property>
             <property name="checkable">
              <bool>true</bool>
@@ -732,60 +757,53 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
             <property name="checked">
              <bool>true</bool>
             </property>
-            <layout class="QGridLayout" name="gridLayout_2">
+            <layout class="QGridLayout" name="gridLayout">
              <item row="0" column="1">
-              <widget class="QLineEdit" name="saslAccount">
+              <widget class="QLineEdit" name="autoIdentifyService">
                <property name="enabled">
                 <bool>true</bool>
                </property>
+               <property name="toolTip">
+                <string>Service user to send your password to, usually NickServ</string>
+               </property>
                <property name="text">
-                <string/>
+                <string>NickServ</string>
                </property>
               </widget>
              </item>
              <item row="1" column="1">
-              <widget class="QLineEdit" name="saslPassword">
+              <widget class="QLineEdit" name="autoIdentifyPassword">
                <property name="enabled">
                 <bool>true</bool>
                </property>
+               <property name="toolTip">
+                <string>Account password</string>
+               </property>
                <property name="echoMode">
                 <enum>QLineEdit::Password</enum>
                </property>
               </widget>
              </item>
-             <item row="1" column="0">
-              <widget class="QLabel" name="saslPasswordLabel">
-               <property name="enabled">
-                <bool>true</bool>
-               </property>
+             <item row="0" column="0">
+              <widget class="QLabel" name="identifyServiceLabel">
                <property name="text">
-                <string>Password:</string>
+                <string>Service:</string>
                </property>
               </widget>
              </item>
-             <item row="0" column="0">
-              <widget class="QLabel" name="saslAccountLabel">
+             <item row="1" column="0">
+              <widget class="QLabel" name="identifyPasswordLabel">
                <property name="enabled">
                 <bool>true</bool>
                </property>
                <property name="text">
-                <string>Account:</string>
+                <string>Password:</string>
                </property>
               </widget>
              </item>
             </layout>
            </widget>
           </item>
-          <item>
-           <widget class="QLabel" name="saslExtInfo">
-            <property name="text">
-             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Note:&lt;/span&gt; because the identity has an ssl certificate set, SASL EXTERNAL will be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-            </property>
-            <property name="wordWrap">
-             <bool>true</bool>
-            </property>
-           </widget>
-          </item>
           <item>
            <spacer name="verticalSpacer_2">
             <property name="orientation">
@@ -794,7 +812,7 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
             <property name="sizeHint" stdset="0">
              <size>
               <width>20</width>
-              <height>40</height>
+              <height>10</height>
              </size>
             </property>
            </spacer>
@@ -961,12 +979,12 @@ Unless you *really* know what you do, leave this as ISO-8859-1!</string>
   <tabstop>messageRateBurstSize</tabstop>
   <tabstop>unlimitedMessageRate</tabstop>
   <tabstop>messageRateDelay</tabstop>
-  <tabstop>autoIdentify</tabstop>
-  <tabstop>autoIdentifyService</tabstop>
-  <tabstop>autoIdentifyPassword</tabstop>
   <tabstop>sasl</tabstop>
   <tabstop>saslAccount</tabstop>
   <tabstop>saslPassword</tabstop>
+  <tabstop>autoIdentify</tabstop>
+  <tabstop>autoIdentifyService</tabstop>
+  <tabstop>autoIdentifyPassword</tabstop>
   <tabstop>useCustomEncodings</tabstop>
   <tabstop>sendEncoding</tabstop>
   <tabstop>recvEncoding</tabstop>