X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fsettingspages%2Fnetworkssettingspage.cpp;h=52f062fb8a831860072898c73bbde58b9cfb6e0e;hp=011328d5ebe0a8e596a33d54a70722f212a632d7;hb=d5b5dab4ffbdbf30612f49cb77e000ad07b800c2;hpb=695758015a80eb8c158a9ac4c0f1c0b547e70df3 diff --git a/src/qtui/settingspages/networkssettingspage.cpp b/src/qtui/settingspages/networkssettingspage.cpp index 011328d5..52f062fb 100644 --- a/src/qtui/settingspages/networkssettingspage.cpp +++ b/src/qtui/settingspages/networkssettingspage.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2015 by the Quassel Project * + * Copyright (C) 2005-2016 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -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())); @@ -104,6 +107,15 @@ NetworksSettingsPage::NetworksSettingsPage(QWidget *parent) 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())); + + // Core features can change during a reconnect. Always connect these here, delaying testing for + // the core feature flag in load(). + connect(ui.useCustomMessageRate, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged())); + connect(ui.messageRateBurstSize, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged())); + connect(ui.messageRateDelay, SIGNAL(valueChanged(double)), this, SLOT(widgetHasChanged())); + connect(ui.unlimitedMessageRate, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged())); + + // Add additional widgets here //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged())); //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged())); @@ -158,10 +170,44 @@ void NetworksSettingsPage::save() void NetworksSettingsPage::load() { reset(); + + // Handle UI dependent on core feature flags here + if (Client::coreFeatures() & Quassel::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 + foreach(NetworkId netid, Client::networkIds()) { clientNetworkAdded(netid); } ui.networkList->setCurrentRow(0); + setChangedState(false); } @@ -305,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); @@ -391,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())); } @@ -435,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(); } @@ -502,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); @@ -526,6 +620,14 @@ 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 @@ -575,6 +677,28 @@ 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 Network *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); + } } @@ -786,6 +910,30 @@ NetworkAddDlg::NetworkAddDlg(const QStringList &exist, QWidget *parent) : QDialo ui.setupUi(this); ui.useSSL->setIcon(QIcon::fromTheme("document-encrypt")); + // Whenever useSSL is toggled, update the port number if not changed from the default + connect(ui.useSSL, SIGNAL(toggled(bool)), SLOT(updateSslPort(bool))); + // 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::coreFeatures() & Quassel::VerifyServerSSL) { + // Synchronize requiring SSL with the use SSL checkbox + ui.sslVerify->setEnabled(ui.useSSL->isChecked()); + connect(ui.useSSL, SIGNAL(toggled(bool)), ui.sslVerify, SLOT(setEnabled(bool))); + } 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(); foreach(QString s, existing) @@ -807,7 +955,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,6 +978,19 @@ 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 *************************************************************************/ @@ -869,19 +1032,64 @@ ServerEditDlg::ServerEditDlg(const Network::Server &server, QWidget *parent) : Q 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, SIGNAL(toggled(bool)), SLOT(updateSslPort(bool))); + // 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::coreFeatures() & Quassel::VerifyServerSSL) { + // Synchronize requiring SSL with the use SSL checkbox + ui.sslVerify->setEnabled(ui.useSSL->isChecked()); + connect(ui.useSSL, SIGNAL(toggled(bool)), ui.sslVerify, SLOT(setEnabled(bool))); + } 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 +1106,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 *************************************************************************/