X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fsettingspages%2Fnetworkssettingspage.cpp;h=a886d92ef4a9353ff640611a40a57e3acda2f0c5;hp=69f5c814dcf40c86512c11f8bb39437d0785d06a;hb=900cce213a6ed000b7131a05a0dec7d04b35b023;hpb=ac82870ae2e9f512f2f669504e9586a3dd2bd7ec diff --git a/src/qtui/settingspages/networkssettingspage.cpp b/src/qtui/settingspages/networkssettingspage.cpp index 69f5c814..a886d92e 100644 --- a/src/qtui/settingspages/networkssettingspage.cpp +++ b/src/qtui/settingspages/networkssettingspage.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2014 by the Quassel Project * + * Copyright (C) 2005-2018 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -21,52 +21,56 @@ #include #include #include +#include #include "networkssettingspage.h" #include "client.h" -#include "iconloader.h" +#include "icon.h" #include "identity.h" #include "network.h" #include "presetnetworks.h" #include "settingspagedlg.h" #include "util.h" +#include "widgethelpers.h" + +// IRCv3 capabilities +#include "irccap.h" #include "settingspages/identitiessettingspage.h" NetworksSettingsPage::NetworksSettingsPage(QWidget *parent) : SettingsPage(tr("IRC"), tr("Networks"), parent) -#ifdef HAVE_SSL - , _cid(0) -#endif { ui.setupUi(this); // hide SASL options for older cores - if (!(Client::coreFeatures() & Quassel::SaslAuthentication)) + if (!Client::isCoreFeatureEnabled(Quassel::Feature::SaslAuthentication)) ui.sasl->hide(); - if (!(Client::coreFeatures() & Quassel::SaslExternal)) + if (!Client::isCoreFeatureEnabled(Quassel::Feature::SaslExternal)) ui.saslExtInfo->hide(); #ifndef HAVE_SSL ui.saslExtInfo->hide(); #endif // set up icons - ui.renameNetwork->setIcon(SmallIcon("edit-rename")); - ui.addNetwork->setIcon(SmallIcon("list-add")); - ui.deleteNetwork->setIcon(SmallIcon("edit-delete")); - ui.addServer->setIcon(SmallIcon("list-add")); - ui.deleteServer->setIcon(SmallIcon("edit-delete")); - ui.editServer->setIcon(SmallIcon("configure")); - ui.upServer->setIcon(SmallIcon("go-up")); - ui.downServer->setIcon(SmallIcon("go-down")); - ui.editIdentities->setIcon(SmallIcon("configure")); - - _ignoreWidgetChanges = false; - - connectedIcon = SmallIcon("network-connect"); - connectingIcon = SmallIcon("network-wired"); // FIXME network-connecting - disconnectedIcon = SmallIcon("network-disconnect"); + ui.renameNetwork->setIcon(icon::get("edit-rename")); + ui.addNetwork->setIcon(icon::get("list-add")); + ui.deleteNetwork->setIcon(icon::get("edit-delete")); + ui.addServer->setIcon(icon::get("list-add")); + ui.deleteServer->setIcon(icon::get("edit-delete")); + ui.editServer->setIcon(icon::get("configure")); + ui.upServer->setIcon(icon::get("go-up")); + ui.downServer->setIcon(icon::get("go-down")); + ui.editIdentities->setIcon(icon::get("configure")); + + connectedIcon = icon::get("network-connect"); + connectingIcon = icon::get("network-wired"); // FIXME network-connecting + disconnectedIcon = icon::get("network-disconnect"); + + // Status icons + infoIcon = icon::get("dialog-information"); + warningIcon = icon::get("dialog-warning"); foreach(int mib, QTextCodec::availableMibs()) { QByteArray codec = QTextCodec::codecForMib(mib)->name(); @@ -80,32 +84,36 @@ NetworksSettingsPage::NetworksSettingsPage(QWidget *parent) currentId = 0; setEnabled(Client::isConnected()); // need a core connection! setWidgetStates(); - connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool))); - connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientNetworkAdded(NetworkId))); - connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientNetworkRemoved(NetworkId))); - connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientIdentityAdded(IdentityId))); - connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientIdentityRemoved(IdentityId))); - - 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.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())); - connect(ui.serverEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged())); - connect(ui.autoReconnect, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged())); - connect(ui.reconnectInterval, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged())); - connect(ui.reconnectRetries, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged())); - connect(ui.unlimitedRetries, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged())); - connect(ui.rejoinOnReconnect, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged())); - //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged())); - //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged())); + + connectToWidgetsChangedSignals({ + ui.identityList, + ui.performEdit, + ui.sasl, + ui.saslAccount, + ui.saslPassword, + ui.autoIdentify, + ui.autoIdentifyService, + ui.autoIdentifyPassword, + ui.useCustomEncodings, + ui.sendEncoding, + ui.recvEncoding, + ui.serverEncoding, + ui.autoReconnect, + ui.reconnectInterval, + ui.reconnectRetries, + ui.unlimitedRetries, + ui.rejoinOnReconnect, + ui.useCustomMessageRate, + ui.messageRateBurstSize, + ui.messageRateDelay, + ui.unlimitedMessageRate + }, this, &NetworksSettingsPage::widgetHasChanged); + + connect(Client::instance(), &Client::coreConnectionStateChanged, this, &NetworksSettingsPage::coreConnectionStateChanged); + connect(Client::instance(), &Client::networkCreated, this, &NetworksSettingsPage::clientNetworkAdded); + connect(Client::instance(), &Client::networkRemoved, this, &NetworksSettingsPage::clientNetworkRemoved); + connect(Client::instance(), &Client::identityCreated, this, &NetworksSettingsPage::clientIdentityAdded); + connect(Client::instance(), &Client::identityRemoved, this, &NetworksSettingsPage::clientIdentityRemoved); foreach(IdentityId id, Client::identityIds()) { clientIdentityAdded(id); @@ -158,10 +166,47 @@ void NetworksSettingsPage::save() void NetworksSettingsPage::load() { reset(); + + // Handle UI dependent on core feature flags here + if (Client::isCoreFeatureEnabled(Quassel::Feature::CustomRateLimits)) { + // Custom rate limiting supported, allow toggling + ui.useCustomMessageRate->setEnabled(true); + // Reset tooltip to default. + ui.useCustomMessageRate->setToolTip(QString("%1").arg( + tr("

Override default message rate limiting.

" + "

Setting limits too low may get you disconnected" + " from the server!

"))); + // If changed, update the message below! + } else { + // Custom rate limiting not supported, disallow toggling + ui.useCustomMessageRate->setEnabled(false); + // Split up the message to allow re-using translations: + // [Original tool-tip] + // [Bold 'does not support feature' message] + // [Specific version needed and feature details] + ui.useCustomMessageRate->setToolTip(QString("%1
%2
%3").arg( + tr("

Override default message rate limiting.

" + "

Setting limits too low may get you disconnected" + " from the server!

"), + tr("Your Quassel core does not support this feature"), + tr("You need a Quassel core v0.13.0 or newer in order to " + "modify message rate limits."))); + } + +#ifdef HAVE_SSL + // Hide the SASL EXTERNAL notice until a network's shown. Stops it from showing while loading + // backlog from the core. + sslUpdated(); +#endif + + // Reset network capability status in case no valid networks get selected (a rare situation) + resetNetworkCapStates(); + foreach(NetworkId netid, Client::networkIds()) { clientNetworkAdded(netid); } ui.networkList->setCurrentRow(0); + setChangedState(false); } @@ -305,6 +350,48 @@ void NetworksSettingsPage::setItemState(NetworkId id, QListWidgetItem *item) } +void NetworksSettingsPage::resetNetworkCapStates() +{ + // Set the status to a blank (invalid) network ID, reseting all UI + setNetworkCapStates(NetworkId()); +} + + +void NetworksSettingsPage::setNetworkCapStates(NetworkId id) +{ + const Network *net = Client::network(id); + if (net && Client::isCoreFeatureEnabled(Quassel::Feature::CapNegotiation)) { + // Capability negotiation is supported, network exists. + // Check if the network is connected. Don't use net->isConnected() as that won't be true + // during capability negotiation when capabilities are added and removed. + if (net->connectionState() != Network::Disconnected) { + // Network exists and is connected, check available capabilities... + // [SASL] + if (net->saslMaybeSupports(IrcCap::SaslMech::PLAIN)) { + setSASLStatus(CapSupportStatus::MaybeSupported); + } else { + setSASLStatus(CapSupportStatus::MaybeUnsupported); + } + + // Add additional capability-dependent interface updates here + } else { + // Network is disconnected + // [SASL] + setSASLStatus(CapSupportStatus::Disconnected); + + // Add additional capability-dependent interface updates here + } + } else { + // Capability negotiation is not supported and/or network doesn't exist. + // Don't assume anything and reset all capability-dependent interface elements to neutral. + // [SASL] + setSASLStatus(CapSupportStatus::Unknown); + + // Add additional capability-dependent interface updates here + } +} + + void NetworksSettingsPage::coreConnectionStateChanged(bool state) { this->setEnabled(state); @@ -321,7 +408,7 @@ void NetworksSettingsPage::coreConnectionStateChanged(bool state) void NetworksSettingsPage::clientIdentityAdded(IdentityId id) { const Identity *identity = Client::identity(id); - connect(identity, SIGNAL(updatedRemotely()), this, SLOT(clientIdentityUpdated())); + connect(identity, &SyncableObject::updatedRemotely, this, &NetworksSettingsPage::clientIdentityUpdated); QString name = identity->identityName(); for (int j = 0; j < ui.identityList->count(); j++) { @@ -339,7 +426,7 @@ void NetworksSettingsPage::clientIdentityAdded(IdentityId id) void NetworksSettingsPage::clientIdentityUpdated() { - const Identity *identity = qobject_cast(sender()); + const auto *identity = qobject_cast(sender()); if (!identity) { qWarning() << "NetworksSettingsPage: Invalid identity to update!"; return; @@ -379,24 +466,28 @@ QListWidgetItem *NetworksSettingsPage::networkItem(NetworkId id) const QListWidgetItem *item = ui.networkList->item(i); if (item->data(Qt::UserRole).value() == id) return item; } - return 0; + return nullptr; } void NetworksSettingsPage::clientNetworkAdded(NetworkId id) { insertNetwork(id); - //connect(Client::network(id), SIGNAL(updatedRemotely()), this, SLOT(clientNetworkUpdated())); - connect(Client::network(id), SIGNAL(configChanged()), this, SLOT(clientNetworkUpdated())); + //connect(Client::network(id), &Network::updatedRemotely, this, &NetworksSettingsPage::clientNetworkUpdated); + connect(Client::network(id), &Network::configChanged, this, &NetworksSettingsPage::clientNetworkUpdated); + + connect(Client::network(id), &Network::connectionStateSet, this, &NetworksSettingsPage::networkConnectionStateChanged); + connect(Client::network(id), &Network::connectionError, this, &NetworksSettingsPage::networkConnectionError); - 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), &Network::capAdded, this, &NetworksSettingsPage::clientNetworkCapsUpdated); + connect(Client::network(id), &Network::capRemoved, this, &NetworksSettingsPage::clientNetworkCapsUpdated); } void NetworksSettingsPage::clientNetworkUpdated() { - const Network *net = qobject_cast(sender()); + const auto *net = qobject_cast(sender()); if (!net) { qWarning() << "Update request for unknown network received!"; return; @@ -427,7 +518,7 @@ void NetworksSettingsPage::clientNetworkRemoved(NetworkId id) void NetworksSettingsPage::networkConnectionStateChanged(Network::ConnectionState state) { Q_UNUSED(state); - const Network *net = qobject_cast(sender()); + const auto *net = qobject_cast(sender()); if (!net) return; /* if(net->networkId() == currentId) { @@ -435,6 +526,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(); } @@ -454,7 +550,7 @@ QListWidgetItem *NetworksSettingsPage::insertNetwork(NetworkId id) QListWidgetItem *NetworksSettingsPage::insertNetwork(const NetworkInfo &info) { - QListWidgetItem *item = 0; + QListWidgetItem *item = nullptr; QList items = ui.networkList->findItems(info.networkName, Qt::MatchExactly); if (!items.count()) item = new QListWidgetItem(disconnectedIcon, info.networkName, ui.networkList); else { @@ -473,6 +569,14 @@ QListWidgetItem *NetworksSettingsPage::insertNetwork(const NetworkInfo &info) } +// Called when selecting 'Configure' from the buffer list +void NetworksSettingsPage::bufferList_Open(NetworkId netId) +{ + QListWidgetItem *item = networkItem(netId); + ui.networkList->setCurrentItem(item, QItemSelectionModel::SelectCurrent); +} + + void NetworksSettingsPage::displayNetwork(NetworkId id) { _ignoreWidgetChanges = true; @@ -481,14 +585,14 @@ void NetworksSettingsPage::displayNetwork(NetworkId id) #ifdef HAVE_SSL // this is only needed when the core supports SASL EXTERNAL - if (Client::coreFeatures() & Quassel::SaslExternal) { + if (Client::isCoreFeatureEnabled(Quassel::Feature::SaslExternal)) { if (_cid) { - disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated())); + disconnect(_cid, &CertIdentity::sslSettingsUpdated, this, &NetworksSettingsPage::sslUpdated); delete _cid; } _cid = new CertIdentity(*Client::identity(info.identity), this); _cid->enableEditSsl(true); - connect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated())); + connect(_cid, &CertIdentity::sslSettingsUpdated, this, &NetworksSettingsPage::sslUpdated); } #endif @@ -497,11 +601,13 @@ void NetworksSettingsPage::displayNetwork(NetworkId id) foreach(Network::Server server, info.serverList) { QListWidgetItem *item = new QListWidgetItem(QString("%1:%2").arg(server.host).arg(server.port)); if (server.useSsl) - item->setIcon(SmallIcon("document-encrypt")); + item->setIcon(icon::get("document-encrypt")); ui.serverList->addItem(item); } //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); @@ -526,12 +632,20 @@ void NetworksSettingsPage::displayNetwork(NetworkId id) ui.reconnectRetries->setValue(info.autoReconnectRetries); ui.unlimitedRetries->setChecked(info.unlimitedReconnectRetries); ui.rejoinOnReconnect->setChecked(info.rejoinChannels); + // Custom rate limiting + ui.unlimitedMessageRate->setChecked(info.unlimitedMessageRate); + // Set 'ui.useCustomMessageRate' after 'ui.unlimitedMessageRate' so if the latter is + // disabled, 'ui.messageRateDelayFrame' will remain disabled. + ui.useCustomMessageRate->setChecked(info.useCustomMessageRate); + ui.messageRateBurstSize->setValue(info.messageRateBurstSize); + // Convert milliseconds (integer) into seconds (double) + ui.messageRateDelay->setValue(info.messageRateDelay / 1000.0f); } else { // just clear widgets #ifdef HAVE_SSL if (_cid) { - disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated())); + disconnect(_cid, &CertIdentity::sslSettingsUpdated, this, &NetworksSettingsPage::sslUpdated); delete _cid; } #endif @@ -575,6 +689,66 @@ void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo &info) info.autoReconnectRetries = ui.reconnectRetries->value(); info.unlimitedReconnectRetries = ui.unlimitedRetries->isChecked(); info.rejoinChannels = ui.rejoinOnReconnect->isChecked(); + // Custom rate limiting + info.useCustomMessageRate = ui.useCustomMessageRate->isChecked(); + info.messageRateBurstSize = ui.messageRateBurstSize->value(); + // Convert seconds (double) into milliseconds (integer) + info.messageRateDelay = static_cast((ui.messageRateDelay->value() * 1000)); + info.unlimitedMessageRate = ui.unlimitedMessageRate->isChecked(); +} + + +void NetworksSettingsPage::clientNetworkCapsUpdated() +{ + // Grab the updated network + const auto *net = qobject_cast(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); + } +} + + +void NetworksSettingsPage::setSASLStatus(const CapSupportStatus saslStatus) +{ + if (_saslStatusSelected != saslStatus) { + // Update the cached copy of SASL status used with the Details dialog + _saslStatusSelected = saslStatus; + + // Update the user interface + switch (saslStatus) { + case CapSupportStatus::Unknown: + // There's no capability negotiation or network doesn't exist. Don't assume + // anything. + ui.saslStatusLabel->setText(QString("%1").arg( + tr("Could not check if supported by network"))); + ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16)); + break; + case CapSupportStatus::Disconnected: + // Disconnected from network, no way to check. + ui.saslStatusLabel->setText(QString("%1").arg( + tr("Cannot check if supported when disconnected"))); + ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16)); + break; + case CapSupportStatus::MaybeUnsupported: + // The network doesn't advertise support for SASL PLAIN. Here be dragons. + ui.saslStatusLabel->setText(QString("%1").arg( + tr("Not currently supported by network"))); + ui.saslStatusIcon->setPixmap(warningIcon.pixmap(16)); + break; + case CapSupportStatus::MaybeSupported: + // The network advertises support for SASL PLAIN. Encourage using it! + // Unfortunately we don't know for sure if it's desired or functional. + ui.saslStatusLabel->setText(QString("%1").arg(tr("Supported by network"))); + ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16)); + break; + } + } } @@ -582,16 +756,21 @@ void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo &info) void NetworksSettingsPage::sslUpdated() { if (_cid && !_cid->sslKey().isNull()) { - ui.saslAccount->setDisabled(true); - ui.saslAccountLabel->setDisabled(true); - ui.saslPassword->setDisabled(true); - ui.saslPasswordLabel->setDisabled(true); + ui.saslContents->setDisabled(true); ui.saslExtInfo->setHidden(false); } else { - ui.saslAccount->setDisabled(false); - ui.saslAccountLabel->setDisabled(false); - ui.saslPassword->setDisabled(false); - ui.saslPasswordLabel->setDisabled(false); + ui.saslContents->setDisabled(false); + // Directly re-enabling causes the widgets to ignore the parent "Use SASL Authentication" + // state to indicate whether or not it's disabled. To workaround this, keep track of + // whether or not "Use SASL Authentication" is enabled, then quickly uncheck/recheck the + // group box. + if (!ui.sasl->isChecked()) { + // SASL is not enabled, uncheck/recheck the group box to re-disable saslContents. + // Leaving saslContents disabled doesn't work as that prevents it from re-enabling if + // sasl is later checked. + ui.sasl->setChecked(true); + ui.sasl->setChecked(false); + } ui.saslExtInfo->setHidden(true); } } @@ -765,6 +944,67 @@ void NetworksSettingsPage::on_editIdentities_clicked() } +void NetworksSettingsPage::on_saslStatusDetails_clicked() +{ + if (ui.networkList->selectedItems().count()) { + NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value(); + QString &netName = networkInfos[netid].networkName; + + // If these strings are visible, one of the status messages wasn't detected below. + QString saslStatusHeader = "[header unintentionally left blank]"; + QString saslStatusExplanation = "[explanation unintentionally left blank]"; + + // If true, show a warning icon instead of an information icon + bool useWarningIcon = false; + + // Determine which explanation to show + switch (_saslStatusSelected) { + case CapSupportStatus::Unknown: + saslStatusHeader = tr("Could not check if SASL supported by network"); + saslStatusExplanation = tr("Quassel could not check if \"%1\" supports SASL. This may " + "be due to unsaved changes or an older Quassel core. You " + "can still try using SASL.").arg(netName); + break; + case CapSupportStatus::Disconnected: + saslStatusHeader = tr("Cannot check if SASL supported when disconnected"); + saslStatusExplanation = tr("Quassel cannot check if \"%1\" supports SASL when " + "disconnected. Connect to the network, or try using SASL " + "anyways.").arg(netName); + break; + case CapSupportStatus::MaybeUnsupported: + saslStatusHeader = tr("SASL not currently supported by network"); + saslStatusExplanation = tr("The network \"%1\" does not currently support SASL. " + "However, support might be added later on.").arg(netName); + useWarningIcon = true; + break; + case CapSupportStatus::MaybeSupported: + saslStatusHeader = tr("SASL supported by network"); + saslStatusExplanation = tr("The network \"%1\" supports SASL. In most cases, you " + "should use SASL instead of NickServ identification." + ).arg(netName); + break; + } + + // Process this in advance for reusability below + const QString saslStatusMsgTitle = tr("SASL support for \"%1\"").arg(netName); + const QString saslStatusMsgText = + QString("

%1


%2


%3

" + ).arg(saslStatusHeader, + saslStatusExplanation, + tr("SASL is a standardized way to log in and identify yourself to " + "IRC servers.")); + + if (useWarningIcon) { + // Show as a warning dialog box + QMessageBox::warning(this, saslStatusMsgTitle, saslStatusMsgText); + } else { + // Show as an information dialog box + QMessageBox::information(this, saslStatusMsgTitle, saslStatusMsgText); + } + } +} + + IdentityId NetworksSettingsPage::defaultIdentity() const { IdentityId defaultId = 0; @@ -781,10 +1021,34 @@ IdentityId NetworksSettingsPage::defaultIdentity() const * NetworkAddDlg *************************************************************************/ -NetworkAddDlg::NetworkAddDlg(const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist) +NetworkAddDlg::NetworkAddDlg(QStringList exist, QWidget *parent) : QDialog(parent), existing(std::move(exist)) { ui.setupUi(this); - ui.useSSL->setIcon(SmallIcon("document-encrypt")); + ui.useSSL->setIcon(icon::get("document-encrypt")); + + // Whenever useSSL is toggled, update the port number if not changed from the default + connect(ui.useSSL, &QAbstractButton::toggled, this, &NetworkAddDlg::updateSslPort); + // Do NOT call updateSslPort when loading settings, otherwise port settings may be overriden. + // If useSSL is later changed to be checked by default, change port's default value, too. + + if (Client::isCoreFeatureEnabled(Quassel::Feature::VerifyServerSSL)) { + // Synchronize requiring SSL with the use SSL checkbox + ui.sslVerify->setEnabled(ui.useSSL->isChecked()); + connect(ui.useSSL, &QAbstractButton::toggled, ui.sslVerify, &QWidget::setEnabled); + } else { + // Core isn't new enough to allow requiring SSL; disable checkbox and uncheck + ui.sslVerify->setEnabled(false); + ui.sslVerify->setChecked(false); + // Split up the message to allow re-using translations: + // [Original tool-tip] + // [Bold 'does not support feature' message] + // [Specific version needed and feature details] + ui.sslVerify->setToolTip(QString("%1
%2
%3").arg( + ui.sslVerify->toolTip(), + tr("Your Quassel core does not support this feature"), + tr("You need a Quassel core v0.13.0 or newer in order to " + "verify connection security."))); + } // read preset networks QStringList networks = PresetNetworks::names(); @@ -796,8 +1060,10 @@ NetworkAddDlg::NetworkAddDlg(const QStringList &exist, QWidget *parent) : QDialo ui.useManual->setChecked(true); ui.usePreset->setEnabled(false); } - connect(ui.networkName, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates())); - connect(ui.serverAddress, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates())); + connect(ui.networkName, &QLineEdit::textChanged, this, &NetworkAddDlg::setButtonStates); + connect(ui.serverAddress, &QLineEdit::textChanged, this, &NetworkAddDlg::setButtonStates); + connect(ui.usePreset, &QRadioButton::toggled, this, &NetworkAddDlg::setButtonStates); + connect(ui.useManual, &QRadioButton::toggled, this, &NetworkAddDlg::setButtonStates); setButtonStates(); } @@ -807,7 +1073,9 @@ NetworkInfo NetworkAddDlg::networkInfo() const if (ui.useManual->isChecked()) { NetworkInfo info; info.networkName = ui.networkName->text().trimmed(); - info.serverList << Network::Server(ui.serverAddress->text().trimmed(), ui.port->value(), ui.serverPassword->text(), ui.useSSL->isChecked()); + info.serverList << Network::Server(ui.serverAddress->text().trimmed(), ui.port->value(), + ui.serverPassword->text(), ui.useSSL->isChecked(), + ui.sslVerify->isChecked()); return info; } else @@ -828,11 +1096,24 @@ void NetworkAddDlg::setButtonStates() } +void NetworkAddDlg::updateSslPort(bool isChecked) +{ + // "Use encrypted connection" was toggled, check the state... + if (isChecked && ui.port->value() == Network::PORT_PLAINTEXT) { + // Had been using the plain-text port, use the SSL default + ui.port->setValue(Network::PORT_SSL); + } else if (!isChecked && ui.port->value() == Network::PORT_SSL) { + // Had been using the SSL port, use the plain-text default + ui.port->setValue(Network::PORT_PLAINTEXT); + } +} + + /************************************************************************** * NetworkEditDlg *************************************************************************/ -NetworkEditDlg::NetworkEditDlg(const QString &old, const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist) +NetworkEditDlg::NetworkEditDlg(const QString &old, QStringList exist, QWidget *parent) : QDialog(parent), existing(std::move(exist)) { ui.setupUi(this); @@ -863,25 +1144,70 @@ void NetworkEditDlg::on_networkEdit_textChanged(const QString &text) ServerEditDlg::ServerEditDlg(const Network::Server &server, QWidget *parent) : QDialog(parent) { ui.setupUi(this); - ui.useSSL->setIcon(SmallIcon("document-encrypt")); + ui.useSSL->setIcon(icon::get("document-encrypt")); ui.host->setText(server.host); ui.host->setFocus(); ui.port->setValue(server.port); ui.password->setText(server.password); ui.useSSL->setChecked(server.useSsl); + ui.sslVerify->setChecked(server.sslVerify); + ui.sslVersion->setCurrentIndex(server.sslVersion); ui.useProxy->setChecked(server.useProxy); ui.proxyType->setCurrentIndex(server.proxyType == QNetworkProxy::Socks5Proxy ? 0 : 1); ui.proxyHost->setText(server.proxyHost); ui.proxyPort->setValue(server.proxyPort); ui.proxyUsername->setText(server.proxyUser); ui.proxyPassword->setText(server.proxyPass); + + // This is a dirty hack to display the core->IRC SSL protocol dropdown + // only if the core won't use autonegotiation to determine the best + // protocol. When autonegotiation was introduced, it would have been + // a good idea to use the CoreFeatures enum to accomplish this. + // However, since multiple versions have been released since then, that + // is no longer possible. Instead, we rely on the fact that the + // Datastream protocol was introduced in the same version (0.10) as SSL + // autonegotiation. Because of that, we can display the dropdown only + // if the Legacy protocol is in use. If any other RemotePeer protocol + // is in use, that means a newer protocol is in use and therefore the + // core will use autonegotiation. + if (Client::coreConnection()->peer()->protocol() != Protocol::LegacyProtocol) { + ui.label_3->hide(); + ui.sslVersion->hide(); + } + + // Whenever useSSL is toggled, update the port number if not changed from the default + connect(ui.useSSL, &QAbstractButton::toggled, this, &ServerEditDlg::updateSslPort); + // Do NOT call updateSslPort when loading settings, otherwise port settings may be overriden. + // If useSSL is later changed to be checked by default, change port's default value, too. + + if (Client::isCoreFeatureEnabled(Quassel::Feature::VerifyServerSSL)) { + // Synchronize requiring SSL with the use SSL checkbox + ui.sslVerify->setEnabled(ui.useSSL->isChecked()); + connect(ui.useSSL, &QAbstractButton::toggled, ui.sslVerify, &QWidget::setEnabled); + } else { + // Core isn't new enough to allow requiring SSL; disable checkbox and uncheck + ui.sslVerify->setEnabled(false); + ui.sslVerify->setChecked(false); + // Split up the message to allow re-using translations: + // [Original tool-tip] + // [Bold 'does not support feature' message] + // [Specific version needed and feature details] + ui.sslVerify->setToolTip(QString("%1
%2
%3").arg( + ui.sslVerify->toolTip(), + tr("Your Quassel core does not support this feature"), + tr("You need a Quassel core v0.13.0 or newer in order to " + "verify connection security."))); + } + on_host_textChanged(); } Network::Server ServerEditDlg::serverData() const { - Network::Server server(ui.host->text().trimmed(), ui.port->value(), ui.password->text(), ui.useSSL->isChecked()); + Network::Server server(ui.host->text().trimmed(), ui.port->value(), ui.password->text(), + ui.useSSL->isChecked(), ui.sslVerify->isChecked()); + server.sslVersion = ui.sslVersion->currentIndex(); server.useProxy = ui.useProxy->isChecked(); server.proxyType = ui.proxyType->currentIndex() == 0 ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy; server.proxyHost = ui.proxyHost->text(); @@ -898,6 +1224,19 @@ void ServerEditDlg::on_host_textChanged() } +void ServerEditDlg::updateSslPort(bool isChecked) +{ + // "Use encrypted connection" was toggled, check the state... + if (isChecked && ui.port->value() == Network::PORT_PLAINTEXT) { + // Had been using the plain-text port, use the SSL default + ui.port->setValue(Network::PORT_SSL); + } else if (!isChecked && ui.port->value() == Network::PORT_SSL) { + // Had been using the SSL port, use the plain-text default + ui.port->setValue(Network::PORT_PLAINTEXT); + } +} + + /************************************************************************** * SaveNetworksDlg *************************************************************************/ @@ -912,8 +1251,8 @@ SaveNetworksDlg::SaveNetworksDlg(const QList &toCreate, const QList ui.progressBar->setMaximum(numevents); ui.progressBar->setValue(0); - connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientEvent())); - connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientEvent())); + connect(Client::instance(), &Client::networkCreated, this, &SaveNetworksDlg::clientEvent); + connect(Client::instance(), &Client::networkRemoved, this, &SaveNetworksDlg::clientEvent); foreach(NetworkId id, toRemove) { Client::removeNetwork(id); @@ -929,7 +1268,7 @@ SaveNetworksDlg::SaveNetworksDlg(const QList &toCreate, const QList continue; } // FIXME this only checks for one changed item rather than all! - connect(net, SIGNAL(updatedRemotely()), this, SLOT(clientEvent())); + connect(net, &SyncableObject::updatedRemotely, this, &SaveNetworksDlg::clientEvent); Client::updateNetwork(info); } }