db51da3edc30deba7b5fbdb3f3960ef3311c8890
[quassel.git] / src / qtui / settingspages / networkssettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2016 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include <QHeaderView>
22 #include <QIcon>
23 #include <QMessageBox>
24 #include <QTextCodec>
25
26 #include "networkssettingspage.h"
27
28 #include "client.h"
29 #include "identity.h"
30 #include "network.h"
31 #include "presetnetworks.h"
32 #include "settingspagedlg.h"
33 #include "util.h"
34
35 // IRCv3 capabilities
36 #include "irccap.h"
37
38 #include "settingspages/identitiessettingspage.h"
39
40 NetworksSettingsPage::NetworksSettingsPage(QWidget *parent)
41     : SettingsPage(tr("IRC"), tr("Networks"), parent)
42 #ifdef HAVE_SSL
43       , _cid(0)
44 #endif
45 {
46     ui.setupUi(this);
47
48     // hide SASL options for older cores
49     if (!(Client::coreFeatures() & Quassel::SaslAuthentication))
50         ui.sasl->hide();
51     if (!(Client::coreFeatures() & Quassel::SaslExternal))
52         ui.saslExtInfo->hide();
53 #ifndef HAVE_SSL
54     ui.saslExtInfo->hide();
55 #endif
56
57     // set up icons
58     ui.renameNetwork->setIcon(QIcon::fromTheme("edit-rename"));
59     ui.addNetwork->setIcon(QIcon::fromTheme("list-add"));
60     ui.deleteNetwork->setIcon(QIcon::fromTheme("edit-delete"));
61     ui.addServer->setIcon(QIcon::fromTheme("list-add"));
62     ui.deleteServer->setIcon(QIcon::fromTheme("edit-delete"));
63     ui.editServer->setIcon(QIcon::fromTheme("configure"));
64     ui.upServer->setIcon(QIcon::fromTheme("go-up"));
65     ui.downServer->setIcon(QIcon::fromTheme("go-down"));
66     ui.editIdentities->setIcon(QIcon::fromTheme("configure"));
67
68     _ignoreWidgetChanges = false;
69
70     connectedIcon = QIcon::fromTheme("network-connect");
71     connectingIcon = QIcon::fromTheme("network-wired"); // FIXME network-connecting
72     disconnectedIcon = QIcon::fromTheme("network-disconnect");
73
74     // Status icons
75     infoIcon = QIcon::fromTheme("dialog-information");
76     warningIcon = QIcon::fromTheme("dialog-warning");
77
78     foreach(int mib, QTextCodec::availableMibs()) {
79         QByteArray codec = QTextCodec::codecForMib(mib)->name();
80         ui.sendEncoding->addItem(codec);
81         ui.recvEncoding->addItem(codec);
82         ui.serverEncoding->addItem(codec);
83     }
84     ui.sendEncoding->model()->sort(0);
85     ui.recvEncoding->model()->sort(0);
86     ui.serverEncoding->model()->sort(0);
87     currentId = 0;
88     setEnabled(Client::isConnected()); // need a core connection!
89     setWidgetStates();
90     connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
91     connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientNetworkAdded(NetworkId)));
92     connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientNetworkRemoved(NetworkId)));
93     connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientIdentityAdded(IdentityId)));
94     connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientIdentityRemoved(IdentityId)));
95
96     connect(ui.identityList, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
97     //connect(ui.randomServer, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
98     connect(ui.performEdit, SIGNAL(textChanged()), this, SLOT(widgetHasChanged()));
99     connect(ui.sasl, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
100     connect(ui.saslAccount, SIGNAL(textEdited(QString)), this, SLOT(widgetHasChanged()));
101     connect(ui.saslPassword, SIGNAL(textEdited(QString)), this, SLOT(widgetHasChanged()));
102     connect(ui.autoIdentify, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
103     connect(ui.autoIdentifyService, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
104     connect(ui.autoIdentifyPassword, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
105     connect(ui.useCustomEncodings, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
106     connect(ui.sendEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
107     connect(ui.recvEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
108     connect(ui.serverEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
109     connect(ui.autoReconnect, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
110     connect(ui.reconnectInterval, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
111     connect(ui.reconnectRetries, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
112     connect(ui.unlimitedRetries, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
113     connect(ui.rejoinOnReconnect, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
114
115     // Core features can change during a reconnect.  Always connect these here, delaying testing for
116     // the core feature flag in load().
117     connect(ui.useCustomMessageRate, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
118     connect(ui.messageRateBurstSize, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
119     connect(ui.messageRateDelay, SIGNAL(valueChanged(double)), this, SLOT(widgetHasChanged()));
120     connect(ui.unlimitedMessageRate, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
121
122     // Add additional widgets here
123     //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged()));
124     //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged()));
125
126     foreach(IdentityId id, Client::identityIds()) {
127         clientIdentityAdded(id);
128     }
129 }
130
131
132 void NetworksSettingsPage::save()
133 {
134     setEnabled(false);
135     if (currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
136
137     QList<NetworkInfo> toCreate, toUpdate;
138     QList<NetworkId> toRemove;
139     QHash<NetworkId, NetworkInfo>::iterator i = networkInfos.begin();
140     while (i != networkInfos.end()) {
141         NetworkId id = (*i).networkId;
142         if (id < 0) {
143             toCreate.append(*i);
144             //if(id == currentId) currentId = 0;
145             //QList<QListWidgetItem *> items = ui.networkList->findItems((*i).networkName, Qt::MatchExactly);
146             //if(items.count()) {
147             //  Q_ASSERT(items[0]->data(Qt::UserRole).value<NetworkId>() == id);
148             //  delete items[0];
149             //}
150             //i = networkInfos.erase(i);
151             ++i;
152         }
153         else {
154             if ((*i) != Client::network((*i).networkId)->networkInfo()) {
155                 toUpdate.append(*i);
156             }
157             ++i;
158         }
159     }
160     foreach(NetworkId id, Client::networkIds()) {
161         if (!networkInfos.contains(id)) toRemove.append(id);
162     }
163     SaveNetworksDlg dlg(toCreate, toUpdate, toRemove, this);
164     int ret = dlg.exec();
165     if (ret == QDialog::Rejected) {
166         // canceled -> reload everything to be safe
167         load();
168     }
169     setChangedState(false);
170     setEnabled(true);
171 }
172
173
174 void NetworksSettingsPage::load()
175 {
176     reset();
177
178     // Handle UI dependent on core feature flags here
179     if (Client::coreFeatures() & Quassel::CustomRateLimits) {
180         // Custom rate limiting supported, allow toggling
181         ui.useCustomMessageRate->setEnabled(true);
182         // Reset tooltip to default.
183         ui.useCustomMessageRate->setToolTip(QString("%1").arg(
184                                           tr("<p>Override default message rate limiting.</p>"
185                                              "<p><b>Setting limits too low may get you disconnected"
186                                              " from the server!</b></p>")));
187         // If changed, update the message below!
188     } else {
189         // Custom rate limiting not supported, disallow toggling
190         ui.useCustomMessageRate->setEnabled(false);
191         // Split up the message to allow re-using translations:
192         // [Original tool-tip]
193         // [Bold 'does not support feature' message]
194         // [Specific version needed and feature details]
195         ui.useCustomMessageRate->setToolTip(QString("%1<br/><b>%2</b><br/>%3").arg(
196                                           tr("<p>Override default message rate limiting.</p>"
197                                              "<p><b>Setting limits too low may get you disconnected"
198                                              " from the server!</b></p>"),
199                                           tr("Your Quassel core does not support this feature"),
200                                           tr("You need a Quassel core v0.13.0 or newer in order to "
201                                           "modify message rate limits.")));
202     }
203
204 #ifdef HAVE_SSL
205     // Hide the SASL EXTERNAL notice until a network's shown.  Stops it from showing while loading
206     // backlog from the core.
207     sslUpdated();
208 #endif
209
210     foreach(NetworkId netid, Client::networkIds()) {
211         clientNetworkAdded(netid);
212     }
213     ui.networkList->setCurrentRow(0);
214
215     setChangedState(false);
216 }
217
218
219 void NetworksSettingsPage::reset()
220 {
221     currentId = 0;
222     ui.networkList->clear();
223     networkInfos.clear();
224 }
225
226
227 bool NetworksSettingsPage::aboutToSave()
228 {
229     if (currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
230     QList<int> errors;
231     foreach(NetworkInfo info, networkInfos.values()) {
232         if (!info.serverList.count()) errors.append(1);
233     }
234     if (!errors.count()) return true;
235     QString error(tr("<b>The following problems need to be corrected before your changes can be applied:</b><ul>"));
236     if (errors.contains(1)) error += tr("<li>All networks need at least one server defined</li>");
237     error += tr("</ul>");
238     QMessageBox::warning(this, tr("Invalid Network Settings"), error);
239     return false;
240 }
241
242
243 void NetworksSettingsPage::widgetHasChanged()
244 {
245     if (_ignoreWidgetChanges) return;
246     bool changed = testHasChanged();
247     if (changed != hasChanged()) setChangedState(changed);
248 }
249
250
251 bool NetworksSettingsPage::testHasChanged()
252 {
253     if (currentId != 0) {
254         saveToNetworkInfo(networkInfos[currentId]);
255     }
256     if (Client::networkIds().count() != networkInfos.count()) return true;
257     foreach(NetworkId id, networkInfos.keys()) {
258         if (id < 0) return true;
259         if (Client::network(id)->networkInfo() != networkInfos[id]) return true;
260     }
261     return false;
262 }
263
264
265 void NetworksSettingsPage::setWidgetStates()
266 {
267     // network list
268     if (ui.networkList->selectedItems().count()) {
269         ui.detailsBox->setEnabled(true);
270         ui.renameNetwork->setEnabled(true);
271         ui.deleteNetwork->setEnabled(true);
272
273         /* button disabled for now
274         NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
275         const Network *net = id > 0 ? Client::network(id) : 0;
276         ui.connectNow->setEnabled(net);
277         //    && (Client::network(id)->connectionState() == Network::Initialized
278         //    || Client::network(id)->connectionState() == Network::Disconnected));
279         if(net) {
280           if(net->connectionState() == Network::Disconnected) {
281             ui.connectNow->setIcon(connectedIcon);
282             ui.connectNow->setText(tr("Connect"));
283           } else {
284             ui.connectNow->setIcon(disconnectedIcon);
285             ui.connectNow->setText(tr("Disconnect"));
286           }
287         } else {
288           ui.connectNow->setIcon(QIcon());
289           ui.connectNow->setText(tr("Apply first!"));
290         } */
291     }
292     else {
293         ui.renameNetwork->setEnabled(false);
294         ui.deleteNetwork->setEnabled(false);
295         //ui.connectNow->setEnabled(false);
296         ui.detailsBox->setEnabled(false);
297     }
298     // network details
299     if (ui.serverList->selectedItems().count()) {
300         ui.editServer->setEnabled(true);
301         ui.deleteServer->setEnabled(true);
302         ui.upServer->setEnabled(ui.serverList->currentRow() > 0);
303         ui.downServer->setEnabled(ui.serverList->currentRow() < ui.serverList->count() - 1);
304     }
305     else {
306         ui.editServer->setEnabled(false);
307         ui.deleteServer->setEnabled(false);
308         ui.upServer->setEnabled(false);
309         ui.downServer->setEnabled(false);
310     }
311 }
312
313
314 void NetworksSettingsPage::setItemState(NetworkId id, QListWidgetItem *item)
315 {
316     if (!item && !(item = networkItem(id))) return;
317     const Network *net = Client::network(id);
318     if (!net || net->isInitialized()) item->setFlags(item->flags() | Qt::ItemIsEnabled);
319     else item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
320     if (net && net->connectionState() == Network::Initialized) {
321         item->setIcon(connectedIcon);
322     }
323     else if (net && net->connectionState() != Network::Disconnected) {
324         item->setIcon(connectingIcon);
325     }
326     else {
327         item->setIcon(disconnectedIcon);
328     }
329     if (net) {
330         bool select = false;
331         // check if we already have another net of this name in the list, and replace it
332         QList<QListWidgetItem *> items = ui.networkList->findItems(net->networkName(), Qt::MatchExactly);
333         if (items.count()) {
334             foreach(QListWidgetItem *i, items) {
335                 NetworkId oldid = i->data(Qt::UserRole).value<NetworkId>();
336                 if (oldid > 0) continue;  // only locally created nets should be replaced
337                 if (oldid == currentId) {
338                     select = true;
339                     currentId = 0;
340                     ui.networkList->clearSelection();
341                 }
342                 int row = ui.networkList->row(i);
343                 if (row >= 0) {
344                     QListWidgetItem *olditem = ui.networkList->takeItem(row);
345                     Q_ASSERT(olditem);
346                     delete olditem;
347                 }
348                 networkInfos.remove(oldid);
349                 break;
350             }
351         }
352         item->setText(net->networkName());
353         if (select) item->setSelected(true);
354     }
355 }
356
357
358 void NetworksSettingsPage::setNetworkCapStates(NetworkId id)
359 {
360     const Network *net = Client::network(id);
361     if ((Client::coreFeatures() & Quassel::CapNegotiation) && net) {
362         // Capability negotiation is supported, network exists.
363         // Check if the network is connected.  Don't use net->isConnected() as that won't be true
364         // during capability negotiation when capabilities are added and removed.
365         if (net->connectionState() != Network::Disconnected) {
366             // Network exists and is connected, check available capabilities...
367             // [SASL]
368             if (net->saslMaybeSupports(IrcCap::SaslMech::PLAIN)) {
369                 setSASLStatus(CapSupportStatus::MaybeSupported);
370             } else {
371                 setSASLStatus(CapSupportStatus::MaybeUnsupported);
372             }
373
374             // Add additional capability-dependent interface updates here
375         } else {
376             // Network is disconnected
377             // [SASL]
378             setSASLStatus(CapSupportStatus::Disconnected);
379
380             // Add additional capability-dependent interface updates here
381         }
382     } else {
383         // Capability negotiation is not supported and/or network doesn't exist.
384         // Don't assume anything and reset all capability-dependent interface elements to neutral.
385         // [SASL]
386         setSASLStatus(CapSupportStatus::Unknown);
387
388         // Add additional capability-dependent interface updates here
389     }
390 }
391
392
393 void NetworksSettingsPage::coreConnectionStateChanged(bool state)
394 {
395     this->setEnabled(state);
396     if (state) {
397         load();
398     }
399     else {
400         // reset
401         //currentId = 0;
402     }
403 }
404
405
406 void NetworksSettingsPage::clientIdentityAdded(IdentityId id)
407 {
408     const Identity *identity = Client::identity(id);
409     connect(identity, SIGNAL(updatedRemotely()), this, SLOT(clientIdentityUpdated()));
410
411     QString name = identity->identityName();
412     for (int j = 0; j < ui.identityList->count(); j++) {
413         if ((j > 0 || ui.identityList->itemData(0).toInt() != 1) && name.localeAwareCompare(ui.identityList->itemText(j)) < 0) {
414             ui.identityList->insertItem(j, name, id.toInt());
415             widgetHasChanged();
416             return;
417         }
418     }
419     // append
420     ui.identityList->insertItem(ui.identityList->count(), name, id.toInt());
421     widgetHasChanged();
422 }
423
424
425 void NetworksSettingsPage::clientIdentityUpdated()
426 {
427     const Identity *identity = qobject_cast<const Identity *>(sender());
428     if (!identity) {
429         qWarning() << "NetworksSettingsPage: Invalid identity to update!";
430         return;
431     }
432     int row = ui.identityList->findData(identity->id().toInt());
433     if (row < 0) {
434         qWarning() << "NetworksSettingsPage: Invalid identity to update!";
435         return;
436     }
437     if (ui.identityList->itemText(row) != identity->identityName()) {
438         ui.identityList->setItemText(row, identity->identityName());
439     }
440 }
441
442
443 void NetworksSettingsPage::clientIdentityRemoved(IdentityId id)
444 {
445     IdentityId defaultId = defaultIdentity();
446     if (currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
447     foreach(NetworkInfo info, networkInfos.values()) {
448         if (info.identity == id) {
449             if (info.networkId == currentId)
450                 ui.identityList->setCurrentIndex(0);
451             info.identity = defaultId;
452             networkInfos[info.networkId] = info;
453             if (info.networkId > 0) Client::updateNetwork(info);
454         }
455     }
456     ui.identityList->removeItem(ui.identityList->findData(id.toInt()));
457     widgetHasChanged();
458 }
459
460
461 QListWidgetItem *NetworksSettingsPage::networkItem(NetworkId id) const
462 {
463     for (int i = 0; i < ui.networkList->count(); i++) {
464         QListWidgetItem *item = ui.networkList->item(i);
465         if (item->data(Qt::UserRole).value<NetworkId>() == id) return item;
466     }
467     return 0;
468 }
469
470
471 void NetworksSettingsPage::clientNetworkAdded(NetworkId id)
472 {
473     insertNetwork(id);
474     //connect(Client::network(id), SIGNAL(updatedRemotely()), this, SLOT(clientNetworkUpdated()));
475     connect(Client::network(id), SIGNAL(configChanged()), this, SLOT(clientNetworkUpdated()));
476
477     connect(Client::network(id), SIGNAL(connectionStateSet(Network::ConnectionState)), this, SLOT(networkConnectionStateChanged(Network::ConnectionState)));
478     connect(Client::network(id), SIGNAL(connectionError(const QString &)), this, SLOT(networkConnectionError(const QString &)));
479
480     // Handle capability changes in case a server dis/connects with the settings window open.
481     connect(Client::network(id), SIGNAL(capAdded(const QString &)), this, SLOT(clientNetworkCapsUpdated()));
482     connect(Client::network(id), SIGNAL(capRemoved(const QString &)), this, SLOT(clientNetworkCapsUpdated()));
483 }
484
485
486 void NetworksSettingsPage::clientNetworkUpdated()
487 {
488     const Network *net = qobject_cast<const Network *>(sender());
489     if (!net) {
490         qWarning() << "Update request for unknown network received!";
491         return;
492     }
493     networkInfos[net->networkId()] = net->networkInfo();
494     setItemState(net->networkId());
495     if (net->networkId() == currentId) displayNetwork(net->networkId());
496     setWidgetStates();
497     widgetHasChanged();
498 }
499
500
501 void NetworksSettingsPage::clientNetworkRemoved(NetworkId id)
502 {
503     if (!networkInfos.contains(id)) return;
504     if (id == currentId) displayNetwork(0);
505     NetworkInfo info = networkInfos.take(id);
506     QList<QListWidgetItem *> items = ui.networkList->findItems(info.networkName, Qt::MatchExactly);
507     foreach(QListWidgetItem *item, items) {
508         if (item->data(Qt::UserRole).value<NetworkId>() == id)
509             delete ui.networkList->takeItem(ui.networkList->row(item));
510     }
511     setWidgetStates();
512     widgetHasChanged();
513 }
514
515
516 void NetworksSettingsPage::networkConnectionStateChanged(Network::ConnectionState state)
517 {
518     Q_UNUSED(state);
519     const Network *net = qobject_cast<const Network *>(sender());
520     if (!net) return;
521     /*
522     if(net->networkId() == currentId) {
523       ui.connectNow->setEnabled(state == Network::Initialized || state == Network::Disconnected);
524     }
525     */
526     setItemState(net->networkId());
527     if (net->networkId() == currentId) {
528         // Network is currently shown.  Update the capability-dependent UI in case capabilities have
529         // changed.
530         setNetworkCapStates(currentId);
531     }
532     setWidgetStates();
533 }
534
535
536 void NetworksSettingsPage::networkConnectionError(const QString &)
537 {
538 }
539
540
541 QListWidgetItem *NetworksSettingsPage::insertNetwork(NetworkId id)
542 {
543     NetworkInfo info = Client::network(id)->networkInfo();
544     networkInfos[id] = info;
545     return insertNetwork(info);
546 }
547
548
549 QListWidgetItem *NetworksSettingsPage::insertNetwork(const NetworkInfo &info)
550 {
551     QListWidgetItem *item = 0;
552     QList<QListWidgetItem *> items = ui.networkList->findItems(info.networkName, Qt::MatchExactly);
553     if (!items.count()) item = new QListWidgetItem(disconnectedIcon, info.networkName, ui.networkList);
554     else {
555         // we overwrite an existing net if it a) has the same name and b) has a negative ID meaning we created it locally before
556         // -> then we can be sure that this is the core-side replacement for the net we created
557         foreach(QListWidgetItem *i, items) {
558             NetworkId id = i->data(Qt::UserRole).value<NetworkId>();
559             if (id < 0) { item = i; break; }
560         }
561         if (!item) item = new QListWidgetItem(disconnectedIcon, info.networkName, ui.networkList);
562     }
563     item->setData(Qt::UserRole, QVariant::fromValue<NetworkId>(info.networkId));
564     setItemState(info.networkId, item);
565     widgetHasChanged();
566     return item;
567 }
568
569
570 void NetworksSettingsPage::displayNetwork(NetworkId id)
571 {
572     _ignoreWidgetChanges = true;
573     if (id != 0) {
574         NetworkInfo info = networkInfos[id];
575
576 #ifdef HAVE_SSL
577         // this is only needed when the core supports SASL EXTERNAL
578         if (Client::coreFeatures() & Quassel::SaslExternal) {
579             if (_cid) {
580                 disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
581                 delete _cid;
582             }
583             _cid = new CertIdentity(*Client::identity(info.identity), this);
584             _cid->enableEditSsl(true);
585             connect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
586         }
587 #endif
588
589         ui.identityList->setCurrentIndex(ui.identityList->findData(info.identity.toInt()));
590         ui.serverList->clear();
591         foreach(Network::Server server, info.serverList) {
592             QListWidgetItem *item = new QListWidgetItem(QString("%1:%2").arg(server.host).arg(server.port));
593             if (server.useSsl)
594                 item->setIcon(QIcon::fromTheme("document-encrypt"));
595             ui.serverList->addItem(item);
596         }
597         //setItemState(id);
598         //ui.randomServer->setChecked(info.useRandomServer);
599         // Update the capability-dependent UI in case capabilities have changed.
600         setNetworkCapStates(id);
601         ui.performEdit->setPlainText(info.perform.join("\n"));
602         ui.autoIdentify->setChecked(info.useAutoIdentify);
603         ui.autoIdentifyService->setText(info.autoIdentifyService);
604         ui.autoIdentifyPassword->setText(info.autoIdentifyPassword);
605         ui.sasl->setChecked(info.useSasl);
606         ui.saslAccount->setText(info.saslAccount);
607         ui.saslPassword->setText(info.saslPassword);
608         if (info.codecForEncoding.isEmpty()) {
609             ui.sendEncoding->setCurrentIndex(ui.sendEncoding->findText(Network::defaultCodecForEncoding()));
610             ui.recvEncoding->setCurrentIndex(ui.recvEncoding->findText(Network::defaultCodecForDecoding()));
611             ui.serverEncoding->setCurrentIndex(ui.serverEncoding->findText(Network::defaultCodecForServer()));
612             ui.useCustomEncodings->setChecked(false);
613         }
614         else {
615             ui.sendEncoding->setCurrentIndex(ui.sendEncoding->findText(info.codecForEncoding));
616             ui.recvEncoding->setCurrentIndex(ui.recvEncoding->findText(info.codecForDecoding));
617             ui.serverEncoding->setCurrentIndex(ui.serverEncoding->findText(info.codecForServer));
618             ui.useCustomEncodings->setChecked(true);
619         }
620         ui.autoReconnect->setChecked(info.useAutoReconnect);
621         ui.reconnectInterval->setValue(info.autoReconnectInterval);
622         ui.reconnectRetries->setValue(info.autoReconnectRetries);
623         ui.unlimitedRetries->setChecked(info.unlimitedReconnectRetries);
624         ui.rejoinOnReconnect->setChecked(info.rejoinChannels);
625         // Custom rate limiting
626         ui.unlimitedMessageRate->setChecked(info.unlimitedMessageRate);
627         // Set 'ui.useCustomMessageRate' after 'ui.unlimitedMessageRate' so if the latter is
628         // disabled, 'ui.messageRateDelayFrame' will remain disabled.
629         ui.useCustomMessageRate->setChecked(info.useCustomMessageRate);
630         ui.messageRateBurstSize->setValue(info.messageRateBurstSize);
631         // Convert milliseconds (integer) into seconds (double)
632         ui.messageRateDelay->setValue(info.messageRateDelay / 1000.0f);
633     }
634     else {
635         // just clear widgets
636 #ifdef HAVE_SSL
637         if (_cid) {
638             disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
639             delete _cid;
640         }
641 #endif
642         ui.identityList->setCurrentIndex(-1);
643         ui.serverList->clear();
644         ui.performEdit->clear();
645         ui.autoIdentifyService->clear();
646         ui.autoIdentifyPassword->clear();
647         ui.saslAccount->clear();
648         ui.saslPassword->clear();
649         setWidgetStates();
650     }
651     _ignoreWidgetChanges = false;
652     currentId = id;
653 }
654
655
656 void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo &info)
657 {
658     info.identity = ui.identityList->itemData(ui.identityList->currentIndex()).toInt();
659     //info.useRandomServer = ui.randomServer->isChecked();
660     info.perform = ui.performEdit->toPlainText().split("\n");
661     info.useAutoIdentify = ui.autoIdentify->isChecked();
662     info.autoIdentifyService = ui.autoIdentifyService->text();
663     info.autoIdentifyPassword = ui.autoIdentifyPassword->text();
664     info.useSasl = ui.sasl->isChecked();
665     info.saslAccount = ui.saslAccount->text();
666     info.saslPassword = ui.saslPassword->text();
667     if (!ui.useCustomEncodings->isChecked()) {
668         info.codecForEncoding.clear();
669         info.codecForDecoding.clear();
670         info.codecForServer.clear();
671     }
672     else {
673         info.codecForEncoding = ui.sendEncoding->currentText().toLatin1();
674         info.codecForDecoding = ui.recvEncoding->currentText().toLatin1();
675         info.codecForServer = ui.serverEncoding->currentText().toLatin1();
676     }
677     info.useAutoReconnect = ui.autoReconnect->isChecked();
678     info.autoReconnectInterval = ui.reconnectInterval->value();
679     info.autoReconnectRetries = ui.reconnectRetries->value();
680     info.unlimitedReconnectRetries = ui.unlimitedRetries->isChecked();
681     info.rejoinChannels = ui.rejoinOnReconnect->isChecked();
682     // Custom rate limiting
683     info.useCustomMessageRate = ui.useCustomMessageRate->isChecked();
684     info.messageRateBurstSize = ui.messageRateBurstSize->value();
685     // Convert seconds (double) into milliseconds (integer)
686     info.messageRateDelay = static_cast<quint32>((ui.messageRateDelay->value() * 1000));
687     info.unlimitedMessageRate = ui.unlimitedMessageRate->isChecked();
688 }
689
690
691 void NetworksSettingsPage::clientNetworkCapsUpdated()
692 {
693     // Grab the updated network
694     const Network *net = qobject_cast<const Network *>(sender());
695     if (!net) {
696         qWarning() << "Update request for unknown network received!";
697         return;
698     }
699     if (net->networkId() == currentId) {
700         // Network is currently shown.  Update the capability-dependent UI in case capabilities have
701         // changed.
702         setNetworkCapStates(currentId);
703     }
704 }
705
706
707 void NetworksSettingsPage::setSASLStatus(const CapSupportStatus saslStatus)
708 {
709     if (_saslStatusSelected != saslStatus) {
710         // Update the cached copy of SASL status used with the Details dialog
711         _saslStatusSelected = saslStatus;
712
713         // Update the user interface
714         switch (saslStatus) {
715             case CapSupportStatus::Unknown:
716                 // There's no capability negotiation or network doesn't exist.  Don't assume
717                 // anything.
718                 ui.saslStatusLabel->setText(QString("<i>%1</i>").arg(
719                                             tr("Could not check if supported by network")));
720                 ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16));
721                 break;
722             case CapSupportStatus::Disconnected:
723                 // Disconnected from network, no way to check.
724                 ui.saslStatusLabel->setText(QString("<i>%1</i>").arg(
725                                                 tr("Cannot check if supported when disconnected")));
726                 ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16));
727                 break;
728             case CapSupportStatus::MaybeUnsupported:
729                 // The network doesn't advertise support for SASL PLAIN.  Here be dragons.
730                 ui.saslStatusLabel->setText(QString("<i>%1</i>").arg(
731                                                 tr("Not currently supported by network")));
732                 ui.saslStatusIcon->setPixmap(warningIcon.pixmap(16));
733                 break;
734             case CapSupportStatus::MaybeSupported:
735                 // The network advertises support for SASL PLAIN.  Encourage using it!
736                 // Unfortunately we don't know for sure if it's desired or functional.
737                 ui.saslStatusLabel->setText(QString("<i>%1</i>").arg(tr("Supported by network")));
738                 ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16));
739                 break;
740         }
741     }
742 }
743
744
745 #ifdef HAVE_SSL
746 void NetworksSettingsPage::sslUpdated()
747 {
748     if (_cid && !_cid->sslKey().isNull()) {
749         ui.saslAccount->setDisabled(true);
750         ui.saslAccountLabel->setDisabled(true);
751         ui.saslPassword->setDisabled(true);
752         ui.saslPasswordLabel->setDisabled(true);
753         ui.saslExtInfo->setHidden(false);
754     } else {
755         ui.saslAccount->setDisabled(false);
756         ui.saslAccountLabel->setDisabled(false);
757         ui.saslPassword->setDisabled(false);
758         ui.saslPasswordLabel->setDisabled(false);
759         ui.saslExtInfo->setHidden(true);
760     }
761 }
762 #endif
763
764
765 /*** Network list ***/
766
767 void NetworksSettingsPage::on_networkList_itemSelectionChanged()
768 {
769     if (currentId != 0) {
770         saveToNetworkInfo(networkInfos[currentId]);
771     }
772     if (ui.networkList->selectedItems().count()) {
773         NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
774         currentId = id;
775         displayNetwork(id);
776         ui.serverList->setCurrentRow(0);
777     }
778     else {
779         currentId = 0;
780     }
781     setWidgetStates();
782 }
783
784
785 void NetworksSettingsPage::on_addNetwork_clicked()
786 {
787     QStringList existing;
788     for (int i = 0; i < ui.networkList->count(); i++) existing << ui.networkList->item(i)->text();
789     NetworkAddDlg dlg(existing, this);
790     if (dlg.exec() == QDialog::Accepted) {
791         NetworkInfo info = dlg.networkInfo();
792         if (info.networkName.isEmpty())
793             return;  // sanity check
794
795         NetworkId id;
796         for (id = 1; id <= networkInfos.count(); id++) {
797             widgetHasChanged();
798             if (!networkInfos.keys().contains(-id.toInt())) break;
799         }
800         id = -id.toInt();
801         info.networkId = id;
802         info.identity = defaultIdentity();
803         networkInfos[id] = info;
804         QListWidgetItem *item = insertNetwork(info);
805         ui.networkList->setCurrentItem(item);
806         setWidgetStates();
807     }
808 }
809
810
811 void NetworksSettingsPage::on_deleteNetwork_clicked()
812 {
813     if (ui.networkList->selectedItems().count()) {
814         NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
815         int ret = QMessageBox::question(this, tr("Delete Network?"),
816             tr("Do you really want to delete the network \"%1\" and all related settings, including the backlog?").arg(networkInfos[netid].networkName),
817             QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
818         if (ret == QMessageBox::Yes) {
819             currentId = 0;
820             networkInfos.remove(netid);
821             delete ui.networkList->takeItem(ui.networkList->row(ui.networkList->selectedItems()[0]));
822             ui.networkList->setCurrentRow(qMin(ui.networkList->currentRow()+1, ui.networkList->count()-1));
823             setWidgetStates();
824             widgetHasChanged();
825         }
826     }
827 }
828
829
830 void NetworksSettingsPage::on_renameNetwork_clicked()
831 {
832     if (!ui.networkList->selectedItems().count()) return;
833     QString old = ui.networkList->selectedItems()[0]->text();
834     QStringList existing;
835     for (int i = 0; i < ui.networkList->count(); i++) existing << ui.networkList->item(i)->text();
836     NetworkEditDlg dlg(old, existing, this);
837     if (dlg.exec() == QDialog::Accepted) {
838         ui.networkList->selectedItems()[0]->setText(dlg.networkName());
839         NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
840         networkInfos[netid].networkName = dlg.networkName();
841         widgetHasChanged();
842     }
843 }
844
845
846 /*
847 void NetworksSettingsPage::on_connectNow_clicked() {
848   if(!ui.networkList->selectedItems().count()) return;
849   NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
850   const Network *net = Client::network(id);
851   if(!net) return;
852   if(net->connectionState() == Network::Disconnected) net->requestConnect();
853   else net->requestDisconnect();
854 }
855 */
856
857 /*** Server list ***/
858
859 void NetworksSettingsPage::on_serverList_itemSelectionChanged()
860 {
861     setWidgetStates();
862 }
863
864
865 void NetworksSettingsPage::on_addServer_clicked()
866 {
867     if (currentId == 0) return;
868     ServerEditDlg dlg(Network::Server(), this);
869     if (dlg.exec() == QDialog::Accepted) {
870         networkInfos[currentId].serverList.append(dlg.serverData());
871         displayNetwork(currentId);
872         ui.serverList->setCurrentRow(ui.serverList->count()-1);
873         widgetHasChanged();
874     }
875 }
876
877
878 void NetworksSettingsPage::on_editServer_clicked()
879 {
880     if (currentId == 0) return;
881     int cur = ui.serverList->currentRow();
882     ServerEditDlg dlg(networkInfos[currentId].serverList[cur], this);
883     if (dlg.exec() == QDialog::Accepted) {
884         networkInfos[currentId].serverList[cur] = dlg.serverData();
885         displayNetwork(currentId);
886         ui.serverList->setCurrentRow(cur);
887         widgetHasChanged();
888     }
889 }
890
891
892 void NetworksSettingsPage::on_deleteServer_clicked()
893 {
894     if (currentId == 0) return;
895     int cur = ui.serverList->currentRow();
896     networkInfos[currentId].serverList.removeAt(cur);
897     displayNetwork(currentId);
898     ui.serverList->setCurrentRow(qMin(cur, ui.serverList->count()-1));
899     widgetHasChanged();
900 }
901
902
903 void NetworksSettingsPage::on_upServer_clicked()
904 {
905     int cur = ui.serverList->currentRow();
906     Network::Server server = networkInfos[currentId].serverList.takeAt(cur);
907     networkInfos[currentId].serverList.insert(cur-1, server);
908     displayNetwork(currentId);
909     ui.serverList->setCurrentRow(cur-1);
910     widgetHasChanged();
911 }
912
913
914 void NetworksSettingsPage::on_downServer_clicked()
915 {
916     int cur = ui.serverList->currentRow();
917     Network::Server server = networkInfos[currentId].serverList.takeAt(cur);
918     networkInfos[currentId].serverList.insert(cur+1, server);
919     displayNetwork(currentId);
920     ui.serverList->setCurrentRow(cur+1);
921     widgetHasChanged();
922 }
923
924
925 void NetworksSettingsPage::on_editIdentities_clicked()
926 {
927     SettingsPageDlg dlg(new IdentitiesSettingsPage(this), this);
928     dlg.exec();
929 }
930
931
932 void NetworksSettingsPage::on_saslStatusDetails_clicked()
933 {
934     if (ui.networkList->selectedItems().count()) {
935         NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
936         QString &netName = networkInfos[netid].networkName;
937
938         // If these strings are visible, one of the status messages wasn't detected below.
939         QString saslStatusHeader = "[header unintentionally left blank]";
940         QString saslStatusExplanation = "[explanation unintentionally left blank]";
941
942         // If true, show a warning icon instead of an information icon
943         bool useWarningIcon = false;
944
945         // Determine which explanation to show
946         switch (_saslStatusSelected) {
947         case CapSupportStatus::Unknown:
948             saslStatusHeader = tr("Could not check if SASL supported by network");
949             saslStatusExplanation = tr("Quassel could not check if \"%1\" supports SASL.  This may "
950                                        "be due to unsaved changes or an older Quassel core.  You "
951                                        "can still try using SASL.").arg(netName);
952             break;
953         case CapSupportStatus::Disconnected:
954             saslStatusHeader = tr("Cannot check if SASL supported when disconnected");
955             saslStatusExplanation = tr("Quassel cannot check if \"%1\" supports SASL when "
956                                        "disconnected.  Connect to the network, or try using SASL "
957                                        "anyways.").arg(netName);
958             break;
959         case CapSupportStatus::MaybeUnsupported:
960             saslStatusHeader = tr("SASL not currently supported by network");
961             saslStatusExplanation = tr("The network \"%1\" does not currently support SASL.  "
962                                        "However, support might be added later on.").arg(netName);
963             useWarningIcon = true;
964             break;
965         case CapSupportStatus::MaybeSupported:
966             saslStatusHeader = tr("SASL supported by network");
967             saslStatusExplanation = tr("The network \"%1\" supports SASL.  In most cases, you "
968                                        "should use SASL instead of NickServ identification."
969                                        ).arg(netName);
970             break;
971         }
972
973         // Process this in advance for reusability below
974         const QString saslStatusMsgTitle = tr("SASL support for \"%1\"").arg(netName);
975         const QString saslStatusMsgText =
976                 QString("<p><b>%1</b></p></br><p>%2</p></br><p><i>%3</i></p>"
977                         ).arg(saslStatusHeader,
978                               saslStatusExplanation,
979                               tr("SASL is a standardized way to log in and identify yourself to "
980                                  "IRC servers."));
981
982         if (useWarningIcon) {
983             // Show as a warning dialog box
984             QMessageBox::warning(this, saslStatusMsgTitle, saslStatusMsgText);
985         } else {
986             // Show as an information dialog box
987             QMessageBox::information(this, saslStatusMsgTitle, saslStatusMsgText);
988         }
989     }
990 }
991
992
993 IdentityId NetworksSettingsPage::defaultIdentity() const
994 {
995     IdentityId defaultId = 0;
996     QList<IdentityId> ids = Client::identityIds();
997     foreach(IdentityId id, ids) {
998         if (defaultId == 0 || id < defaultId)
999             defaultId = id;
1000     }
1001     return defaultId;
1002 }
1003
1004
1005 /**************************************************************************
1006 * NetworkAddDlg
1007 *************************************************************************/
1008
1009 NetworkAddDlg::NetworkAddDlg(const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist)
1010 {
1011     ui.setupUi(this);
1012     ui.useSSL->setIcon(QIcon::fromTheme("document-encrypt"));
1013
1014     // Whenever useSSL is toggled, update the port number if not changed from the default
1015     connect(ui.useSSL, SIGNAL(toggled(bool)), SLOT(updateSslPort(bool)));
1016     // Do NOT call updateSslPort when loading settings, otherwise port settings may be overriden.
1017     // If useSSL is later changed to be checked by default, change port's default value, too.
1018
1019     if (Client::coreFeatures() & Quassel::VerifyServerSSL) {
1020         // Synchronize requiring SSL with the use SSL checkbox
1021         ui.sslVerify->setEnabled(ui.useSSL->isChecked());
1022         connect(ui.useSSL, SIGNAL(toggled(bool)), ui.sslVerify, SLOT(setEnabled(bool)));
1023     } else {
1024         // Core isn't new enough to allow requiring SSL; disable checkbox and uncheck
1025         ui.sslVerify->setEnabled(false);
1026         ui.sslVerify->setChecked(false);
1027         // Split up the message to allow re-using translations:
1028         // [Original tool-tip]
1029         // [Bold 'does not support feature' message]
1030         // [Specific version needed and feature details]
1031         ui.sslVerify->setToolTip(QString("%1<br/><b>%2</b><br/>%3").arg(
1032                                        ui.sslVerify->toolTip(),
1033                                        tr("Your Quassel core does not support this feature"),
1034                                        tr("You need a Quassel core v0.13.0 or newer in order to "
1035                                           "verify connection security.")));
1036     }
1037
1038     // read preset networks
1039     QStringList networks = PresetNetworks::names();
1040     foreach(QString s, existing)
1041     networks.removeAll(s);
1042     if (networks.count())
1043         ui.presetList->addItems(networks);
1044     else {
1045         ui.useManual->setChecked(true);
1046         ui.usePreset->setEnabled(false);
1047     }
1048     connect(ui.networkName, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates()));
1049     connect(ui.serverAddress, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates()));
1050     setButtonStates();
1051 }
1052
1053
1054 NetworkInfo NetworkAddDlg::networkInfo() const
1055 {
1056     if (ui.useManual->isChecked()) {
1057         NetworkInfo info;
1058         info.networkName = ui.networkName->text().trimmed();
1059         info.serverList << Network::Server(ui.serverAddress->text().trimmed(), ui.port->value(),
1060                                            ui.serverPassword->text(), ui.useSSL->isChecked(),
1061                                            ui.sslVerify->isChecked());
1062         return info;
1063     }
1064     else
1065         return PresetNetworks::networkInfo(ui.presetList->currentText());
1066 }
1067
1068
1069 void NetworkAddDlg::setButtonStates()
1070 {
1071     bool ok = false;
1072     if (ui.usePreset->isChecked() && ui.presetList->count())
1073         ok = true;
1074     else if (ui.useManual->isChecked()) {
1075         ok = !ui.networkName->text().trimmed().isEmpty() && !existing.contains(ui.networkName->text().trimmed())
1076              && !ui.serverAddress->text().isEmpty();
1077     }
1078     ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
1079 }
1080
1081
1082 void NetworkAddDlg::updateSslPort(bool isChecked)
1083 {
1084     // "Use encrypted connection" was toggled, check the state...
1085     if (isChecked && ui.port->value() == Network::PORT_PLAINTEXT) {
1086         // Had been using the plain-text port, use the SSL default
1087         ui.port->setValue(Network::PORT_SSL);
1088     } else if (!isChecked && ui.port->value() == Network::PORT_SSL) {
1089         // Had been using the SSL port, use the plain-text default
1090         ui.port->setValue(Network::PORT_PLAINTEXT);
1091     }
1092 }
1093
1094
1095 /**************************************************************************
1096  * NetworkEditDlg
1097  *************************************************************************/
1098
1099 NetworkEditDlg::NetworkEditDlg(const QString &old, const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist)
1100 {
1101     ui.setupUi(this);
1102
1103     if (old.isEmpty()) {
1104         // new network
1105         setWindowTitle(tr("Add Network"));
1106         on_networkEdit_textChanged(""); // disable ok button
1107     }
1108     else ui.networkEdit->setText(old);
1109 }
1110
1111
1112 QString NetworkEditDlg::networkName() const
1113 {
1114     return ui.networkEdit->text().trimmed();
1115 }
1116
1117
1118 void NetworkEditDlg::on_networkEdit_textChanged(const QString &text)
1119 {
1120     ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text.trimmed()));
1121 }
1122
1123
1124 /**************************************************************************
1125  * ServerEditDlg
1126  *************************************************************************/
1127 ServerEditDlg::ServerEditDlg(const Network::Server &server, QWidget *parent) : QDialog(parent)
1128 {
1129     ui.setupUi(this);
1130     ui.useSSL->setIcon(QIcon::fromTheme("document-encrypt"));
1131     ui.host->setText(server.host);
1132     ui.host->setFocus();
1133     ui.port->setValue(server.port);
1134     ui.password->setText(server.password);
1135     ui.useSSL->setChecked(server.useSsl);
1136     ui.sslVerify->setChecked(server.sslVerify);
1137     ui.sslVersion->setCurrentIndex(server.sslVersion);
1138     ui.useProxy->setChecked(server.useProxy);
1139     ui.proxyType->setCurrentIndex(server.proxyType == QNetworkProxy::Socks5Proxy ? 0 : 1);
1140     ui.proxyHost->setText(server.proxyHost);
1141     ui.proxyPort->setValue(server.proxyPort);
1142     ui.proxyUsername->setText(server.proxyUser);
1143     ui.proxyPassword->setText(server.proxyPass);
1144
1145     // This is a dirty hack to display the core->IRC SSL protocol dropdown
1146     // only if the core won't use autonegotiation to determine the best
1147     // protocol.  When autonegotiation was introduced, it would have been
1148     // a good idea to use the CoreFeatures enum to accomplish this.
1149     // However, since multiple versions have been released since then, that
1150     // is no longer possible.  Instead, we rely on the fact that the
1151     // Datastream protocol was introduced in the same version (0.10) as SSL
1152     // autonegotiation.  Because of that, we can display the dropdown only
1153     // if the Legacy protocol is in use.  If any other RemotePeer protocol
1154     // is in use, that means a newer protocol is in use and therefore the
1155     // core will use autonegotiation.
1156     if (Client::coreConnection()->peer()->protocol() != Protocol::LegacyProtocol) {
1157         ui.label_3->hide();
1158         ui.sslVersion->hide();
1159     }
1160
1161     // Whenever useSSL is toggled, update the port number if not changed from the default
1162     connect(ui.useSSL, SIGNAL(toggled(bool)), SLOT(updateSslPort(bool)));
1163     // Do NOT call updateSslPort when loading settings, otherwise port settings may be overriden.
1164     // If useSSL is later changed to be checked by default, change port's default value, too.
1165
1166     if (Client::coreFeatures() & Quassel::VerifyServerSSL) {
1167         // Synchronize requiring SSL with the use SSL checkbox
1168         ui.sslVerify->setEnabled(ui.useSSL->isChecked());
1169         connect(ui.useSSL, SIGNAL(toggled(bool)), ui.sslVerify, SLOT(setEnabled(bool)));
1170     } else {
1171         // Core isn't new enough to allow requiring SSL; disable checkbox and uncheck
1172         ui.sslVerify->setEnabled(false);
1173         ui.sslVerify->setChecked(false);
1174         // Split up the message to allow re-using translations:
1175         // [Original tool-tip]
1176         // [Bold 'does not support feature' message]
1177         // [Specific version needed and feature details]
1178         ui.sslVerify->setToolTip(QString("%1<br/><b>%2</b><br/>%3").arg(
1179                                        ui.sslVerify->toolTip(),
1180                                        tr("Your Quassel core does not support this feature"),
1181                                        tr("You need a Quassel core v0.13.0 or newer in order to "
1182                                           "verify connection security.")));
1183     }
1184
1185     on_host_textChanged();
1186 }
1187
1188
1189 Network::Server ServerEditDlg::serverData() const
1190 {
1191     Network::Server server(ui.host->text().trimmed(), ui.port->value(), ui.password->text(),
1192                            ui.useSSL->isChecked(), ui.sslVerify->isChecked());
1193     server.sslVersion = ui.sslVersion->currentIndex();
1194     server.useProxy = ui.useProxy->isChecked();
1195     server.proxyType = ui.proxyType->currentIndex() == 0 ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy;
1196     server.proxyHost = ui.proxyHost->text();
1197     server.proxyPort = ui.proxyPort->value();
1198     server.proxyUser = ui.proxyUsername->text();
1199     server.proxyPass = ui.proxyPassword->text();
1200     return server;
1201 }
1202
1203
1204 void ServerEditDlg::on_host_textChanged()
1205 {
1206     ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(ui.host->text().trimmed().isEmpty());
1207 }
1208
1209
1210 void ServerEditDlg::updateSslPort(bool isChecked)
1211 {
1212     // "Use encrypted connection" was toggled, check the state...
1213     if (isChecked && ui.port->value() == Network::PORT_PLAINTEXT) {
1214         // Had been using the plain-text port, use the SSL default
1215         ui.port->setValue(Network::PORT_SSL);
1216     } else if (!isChecked && ui.port->value() == Network::PORT_SSL) {
1217         // Had been using the SSL port, use the plain-text default
1218         ui.port->setValue(Network::PORT_PLAINTEXT);
1219     }
1220 }
1221
1222
1223 /**************************************************************************
1224  * SaveNetworksDlg
1225  *************************************************************************/
1226
1227 SaveNetworksDlg::SaveNetworksDlg(const QList<NetworkInfo> &toCreate, const QList<NetworkInfo> &toUpdate, const QList<NetworkId> &toRemove, QWidget *parent) : QDialog(parent)
1228 {
1229     ui.setupUi(this);
1230
1231     numevents = toCreate.count() + toUpdate.count() + toRemove.count();
1232     rcvevents = 0;
1233     if (numevents) {
1234         ui.progressBar->setMaximum(numevents);
1235         ui.progressBar->setValue(0);
1236
1237         connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientEvent()));
1238         connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientEvent()));
1239
1240         foreach(NetworkId id, toRemove) {
1241             Client::removeNetwork(id);
1242         }
1243         foreach(NetworkInfo info, toCreate) {
1244             Client::createNetwork(info);
1245         }
1246         foreach(NetworkInfo info, toUpdate) {
1247             const Network *net = Client::network(info.networkId);
1248             if (!net) {
1249                 qWarning() << "Invalid client network!";
1250                 numevents--;
1251                 continue;
1252             }
1253             // FIXME this only checks for one changed item rather than all!
1254             connect(net, SIGNAL(updatedRemotely()), this, SLOT(clientEvent()));
1255             Client::updateNetwork(info);
1256         }
1257     }
1258     else {
1259         qWarning() << "Sync dialog called without stuff to change!";
1260         accept();
1261     }
1262 }
1263
1264
1265 void SaveNetworksDlg::clientEvent()
1266 {
1267     ui.progressBar->setValue(++rcvevents);
1268     if (rcvevents >= numevents) accept();
1269 }