ssl cert and key can now be configured per drag & drop
[quassel.git] / src / qtui / settingspages / identitiessettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-08 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) any later version.                                   *
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  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "identitiessettingspage.h"
22
23 #include <QDesktopServices>
24 #include <QDragEnterEvent>
25 #include <QDropEvent>
26 #include <QFileDialog>
27 #include <QInputDialog>
28 #include <QMessageBox>
29
30 #include "client.h"
31 #include "iconloader.h"
32 #include "signalproxy.h"
33
34 IdentitiesSettingsPage::IdentitiesSettingsPage(QWidget *parent)
35   : SettingsPage(tr("General"), tr("Identities"), parent),
36     _editSsl(false)
37 {
38
39   ui.setupUi(this);
40   ui.renameIdentity->setIcon(BarIcon("edit-rename"));
41   ui.addIdentity->setIcon(BarIcon("list-add-user"));
42   ui.deleteIdentity->setIcon(BarIcon("list-remove-user"));
43   ui.addNick->setIcon(SmallIcon("list-add"));
44   ui.deleteNick->setIcon(SmallIcon("edit-delete"));
45   ui.renameNick->setIcon(SmallIcon("edit-rename"));
46   ui.nickUp->setIcon(SmallIcon("go-up"));
47   ui.nickDown->setIcon(SmallIcon("go-down"));
48
49   setEnabled(Client::isConnected());  // need a core connection!
50   setWidgetStates();
51   connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
52   connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientIdentityCreated(IdentityId)));
53   connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientIdentityRemoved(IdentityId)));
54
55   currentId = 0;
56
57   // We need to know whenever the state of input widgets changes...
58   //connect(ui.identityList, SIGNAL(editTextChanged(const QString &)), this, SLOT(widgetHasChanged()));
59   connect(ui.realName, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
60   connect(ui.nicknameList, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(widgetHasChanged()));
61   connect(ui.awayNick, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
62   connect(ui.awayNickEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
63   connect(ui.awayReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
64   connect(ui.awayReasonEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
65   connect(ui.autoAwayEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
66   connect(ui.autoAwayTime, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
67   connect(ui.autoAwayReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
68   connect(ui.autoAwayReasonEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
69   connect(ui.detachAwayEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
70   connect(ui.detachAwayReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
71   connect(ui.detachAwayReasonEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
72   connect(ui.ident, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
73   connect(ui.kickReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
74   connect(ui.partReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
75   connect(ui.quitReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
76
77   connect(ui.nicknameList, SIGNAL(itemSelectionChanged()), this, SLOT(setWidgetStates()));
78
79   // we would need this if we enabled drag and drop in the nicklist...
80   //connect(ui.nicknameList, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(setWidgetStates()));
81   //connect(ui.nicknameList->model(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(nicklistHasChanged()));
82
83   ui.sslKeyGroupBox->setAcceptDrops(true);
84   ui.sslKeyGroupBox->installEventFilter(this);
85   ui.sslCertGroupBox->setAcceptDrops(true);
86   ui.sslCertGroupBox->installEventFilter(this);
87 }
88
89 void IdentitiesSettingsPage::setWidgetStates() {
90   if(ui.nicknameList->selectedItems().count()) {
91     ui.renameNick->setEnabled(true);
92     ui.nickUp->setEnabled(ui.nicknameList->row(ui.nicknameList->selectedItems()[0]) > 0);
93     ui.nickDown->setEnabled(ui.nicknameList->row(ui.nicknameList->selectedItems()[0]) < ui.nicknameList->count()-1);
94   } else {
95     ui.renameNick->setDisabled(true);
96     ui.nickUp->setDisabled(true);
97     ui.nickDown->setDisabled(true);
98   }
99   ui.deleteNick->setEnabled(ui.nicknameList->count() > 1);
100 }
101
102 void IdentitiesSettingsPage::coreConnectionStateChanged(bool connected) {
103   setEnabled(connected);
104   if(connected) {
105 #ifdef HAVE_SSL
106     if(Client::signalProxy()->isSecure())
107       ui.keyAndCertSettings->setCurrentIndex(2);
108     else
109       ui.keyAndCertSettings->setCurrentIndex(1);
110 #else
111     ui.keyAndCertSettings->setCurrentIndex(0);
112 #endif
113     load();
114   } else {
115     // reset
116     currentId = 0;
117   }
118 }
119
120 void IdentitiesSettingsPage::save() {
121   setEnabled(false);
122   QList<CertIdentity *> toCreate, toUpdate;
123   // we need to remove our temporarily created identities.
124   // these are going to be re-added after the core has propagated them back...
125   QHash<IdentityId, CertIdentity *>::iterator i = identities.begin();
126   while(i != identities.end()) {
127     if((*i)->id() < 0) {
128       CertIdentity *temp = *i;
129       i = identities.erase(i);
130       toCreate.append(temp);
131       ui.identityList->removeItem(ui.identityList->findData(temp->id().toInt()));
132     } else {
133       if(**i != *Client::identity((*i)->id()) || (*i)->isDirty()) {
134         toUpdate.append(*i);
135       }
136       ++i;
137     }
138   }
139   SaveIdentitiesDlg dlg(toCreate, toUpdate, deletedIdentities, this);
140   int ret = dlg.exec();
141   if(ret == QDialog::Rejected) {
142     // canceled -> reload everything to be safe
143     load();
144   }
145   foreach(Identity *id, toCreate) {
146     id->deleteLater();
147   }
148   changedIdentities.clear();
149   deletedIdentities.clear();
150   setChangedState(false);
151   setEnabled(true);
152 }
153
154 void IdentitiesSettingsPage::load() {
155   currentId = 0;
156   foreach(Identity *identity, identities.values()) {
157     identity->deleteLater();
158   }
159   identities.clear();
160   deletedIdentities.clear();
161   changedIdentities.clear();
162   ui.identityList->clear();
163   foreach(IdentityId id, Client::identityIds()) {
164     clientIdentityCreated(id);
165   }
166   setChangedState(false);
167 }
168
169 void IdentitiesSettingsPage::widgetHasChanged() {
170   bool changed = testHasChanged();
171   if(changed != hasChanged()) setChangedState(changed);
172 }
173
174 bool IdentitiesSettingsPage::testHasChanged() {
175   if(deletedIdentities.count()) return true;
176   if(currentId < 0) {
177     return true; // new identity
178   } else {
179     if(currentId != 0) {
180       changedIdentities.removeAll(currentId);
181       CertIdentity temp(currentId, this);
182       saveToIdentity(&temp);
183       temp.setIdentityName(identities[currentId]->identityName());
184       if(temp != *Client::identity(currentId) || temp.isDirty())
185         changedIdentities.append(currentId);
186     }
187     return changedIdentities.count();
188   }
189 }
190
191 bool IdentitiesSettingsPage::aboutToSave() {
192   saveToIdentity(identities[currentId]);
193   QList<int> errors;
194   foreach(Identity *id, identities.values()) {
195     if(id->identityName().isEmpty()) errors.append(1);
196     if(!id->nicks().count()) errors.append(2);
197     if(id->realName().isEmpty()) errors.append(3);
198     if(id->ident().isEmpty()) errors.append(4);
199   }
200   if(!errors.count()) return true;
201   QString error(tr("<b>The following problems need to be corrected before your changes can be applied:</b><ul>"));
202   if(errors.contains(1)) error += tr("<li>All identities need an identity name set</li>");
203   if(errors.contains(2)) error += tr("<li>Every identity needs at least one nickname defined</li>");
204   if(errors.contains(3)) error += tr("<li>You need to specify a real name for every identity</li>");
205   if(errors.contains(4)) error += tr("<li>You need to specify an ident for every identity</li>");
206   error += tr("</ul>");
207   QMessageBox::warning(this, tr("One or more identities are invalid"), error);
208   return false;
209 }
210
211 void IdentitiesSettingsPage::clientIdentityCreated(IdentityId id) {
212   CertIdentity *identity = new CertIdentity(*Client::identity(id), this);
213   identity->enableEditSsl(_editSsl);
214   insertIdentity(identity);
215   connect(identity, SIGNAL(sslSettingsUpdated()), this, SLOT(clientIdentityUpdated()));
216   connect(Client::identity(id), SIGNAL(updatedRemotely()), this, SLOT(clientIdentityUpdated()));
217 }
218
219 void IdentitiesSettingsPage::clientIdentityUpdated() {
220   const Identity *clientIdentity = qobject_cast<Identity *>(sender());
221   if(!clientIdentity) {
222     qWarning() << "Invalid identity to update!";
223     return;
224   }
225   if(!identities.contains(clientIdentity->id())) {
226     qWarning() << "Unknown identity to update:" << clientIdentity->identityName();
227     return;
228   }
229
230   CertIdentity *identity = identities[clientIdentity->id()];
231
232   if(identity->identityName() != clientIdentity->identityName())
233     renameIdentity(identity->id(), clientIdentity->identityName());
234
235   identity->update(*clientIdentity);
236
237   if(identity->id() == currentId)
238     displayIdentity(identity, true);
239 }
240
241 void IdentitiesSettingsPage::clientIdentityRemoved(IdentityId id) {
242   if(identities.contains(id)) {
243     removeIdentity(identities[id]);
244     changedIdentities.removeAll(id);
245     deletedIdentities.removeAll(id);
246   }
247 }
248
249 void IdentitiesSettingsPage::insertIdentity(CertIdentity *identity) {
250   IdentityId id = identity->id();
251   identities[id] = identity;
252   if(id == 1) {
253     // default identity is always the first one!
254     ui.identityList->insertItem(0, identity->identityName(), id.toInt());
255   } else {
256     QString name = identity->identityName();
257     for(int j = 0; j < ui.identityList->count(); j++) {
258       if((j>0 || ui.identityList->itemData(0).toInt() != 1) && name.localeAwareCompare(ui.identityList->itemText(j)) < 0) {
259         ui.identityList->insertItem(j, name, id.toInt());
260         widgetHasChanged();
261         return;
262       }
263     }
264     // append
265     ui.identityList->insertItem(ui.identityList->count(), name, id.toInt());
266     widgetHasChanged();
267   }
268 }
269
270 void IdentitiesSettingsPage::renameIdentity(IdentityId id, const QString &newName) {
271   Identity *identity = identities[id];
272   ui.identityList->setItemText(ui.identityList->findData(identity->id().toInt()), newName);
273   identity->setIdentityName(newName);
274 }
275
276 void IdentitiesSettingsPage::removeIdentity(Identity *id) {
277   identities.remove(id->id());
278   ui.identityList->removeItem(ui.identityList->findData(id->id().toInt()));
279   changedIdentities.removeAll(id->id());
280   if(currentId == id->id()) currentId = 0;
281   id->deleteLater();
282   widgetHasChanged();
283 }
284
285 void IdentitiesSettingsPage::on_identityList_currentIndexChanged(int index) {
286   if(index < 0) {
287     //ui.identityList->setEditable(false);
288     displayIdentity(0);
289   } else {
290     IdentityId id = ui.identityList->itemData(index).toInt();
291     if(identities.contains(id)) displayIdentity(identities[id]);
292     ui.deleteIdentity->setEnabled(id != 1); // default identity cannot be deleted
293     ui.renameIdentity->setEnabled(id != 1); // ...or renamed
294   }
295 }
296
297 void IdentitiesSettingsPage::displayIdentity(CertIdentity *id, bool dontsave) {
298   if(currentId != 0 && !dontsave && identities.contains(currentId)) {
299     saveToIdentity(identities[currentId]);
300   }
301   if(id) {
302     currentId = id->id();
303     ui.realName->setText(id->realName());
304     ui.nicknameList->clear();
305     ui.nicknameList->addItems(id->nicks());
306     //for(int i = 0; i < ui.nicknameList->count(); i++) {
307     //  ui.nicknameList->item(i)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled);
308     //}
309     if(ui.nicknameList->count()) ui.nicknameList->setCurrentRow(0);
310     ui.awayNick->setText(id->awayNick());
311     ui.awayNickEnabled->setChecked(id->awayNickEnabled());
312     ui.awayReason->setText(id->awayReason());
313     ui.awayReasonEnabled->setChecked(id->awayReasonEnabled());
314     ui.autoAwayEnabled->setChecked(id->autoAwayEnabled());
315     ui.autoAwayTime->setValue(id->autoAwayTime());
316     ui.autoAwayReason->setText(id->autoAwayReason());
317     ui.autoAwayReasonEnabled->setChecked(id->autoAwayReasonEnabled());
318     ui.detachAwayEnabled->setChecked(id->detachAwayEnabled());
319     ui.detachAwayReason->setText(id->detachAwayReason());
320     ui.detachAwayReasonEnabled->setChecked(id->detachAwayReasonEnabled());
321     ui.ident->setText(id->ident());
322     ui.kickReason->setText(id->kickReason());
323     ui.partReason->setText(id->partReason());
324     ui.quitReason->setText(id->quitReason());
325     showKeyState(id->sslKey());
326     showCertState(id->sslCert());
327   }
328 }
329
330 void IdentitiesSettingsPage::saveToIdentity(CertIdentity *id) {
331   id->setRealName(ui.realName->text());
332   QStringList nicks;
333   for(int i = 0; i < ui.nicknameList->count(); i++) {
334     nicks << ui.nicknameList->item(i)->text();
335   }
336   id->setNicks(nicks);
337   id->setAwayNick(ui.awayNick->text());
338   id->setAwayNickEnabled(ui.awayNickEnabled->isChecked());
339   id->setAwayReason(ui.awayReason->text());
340   id->setAwayReasonEnabled(ui.awayReasonEnabled->isChecked());
341   id->setAutoAwayEnabled(ui.autoAwayEnabled->isChecked());
342   id->setAutoAwayTime(ui.autoAwayTime->value());
343   id->setAutoAwayReason(ui.autoAwayReason->text());
344   id->setAutoAwayReasonEnabled(ui.autoAwayReasonEnabled->isChecked());
345   id->setDetachAwayEnabled(ui.detachAwayEnabled->isChecked());
346   id->setDetachAwayReason(ui.detachAwayReason->text());
347   id->setDetachAwayReasonEnabled(ui.detachAwayReasonEnabled->isChecked());
348   id->setIdent(ui.ident->text());
349   id->setKickReason(ui.kickReason->text());
350   id->setPartReason(ui.partReason->text());
351   id->setQuitReason(ui.quitReason->text());
352   id->setSslKey(QSslKey(ui.keyTypeLabel->property("sslKey").toByteArray(), (QSsl::KeyAlgorithm)(ui.keyTypeLabel->property("sslKeyType").toInt())));
353   id->setSslCert(QSslCertificate(ui.certOrgLabel->property("sslCert").toByteArray()));
354 }
355
356 void IdentitiesSettingsPage::on_addIdentity_clicked() {
357   CreateIdentityDlg dlg(ui.identityList->model(), this);
358   if(dlg.exec() == QDialog::Accepted) {
359     // find a free (negative) ID
360     IdentityId id;
361     for(id = 1; id <= identities.count(); id++) {
362       if(!identities.keys().contains(-id.toInt())) break;
363     }
364     id = -id.toInt();
365     CertIdentity *newId = new CertIdentity(id, this);
366     newId->enableEditSsl(_editSsl);
367     if(dlg.duplicateId() != 0) {
368       // duplicate
369       newId->update(*identities[dlg.duplicateId()]);
370       newId->setId(id);
371     }
372     newId->setIdentityName(dlg.identityName());
373     identities[id] = newId;
374     insertIdentity(newId);
375     ui.identityList->setCurrentIndex(ui.identityList->findData(id.toInt()));
376     widgetHasChanged();
377   }
378 }
379
380 void IdentitiesSettingsPage::on_deleteIdentity_clicked() {
381   Identity *id = identities[currentId];
382   int ret = QMessageBox::question(this, tr("Delete Identity?"),
383                                   tr("Do you really want to delete identity \"%1\"?").arg(id->identityName()),
384                                   QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
385   if(ret != QMessageBox::Yes) return;
386   if(id->id() > 0) deletedIdentities.append(id->id());
387   currentId = 0;
388   removeIdentity(id);
389 }
390
391 void IdentitiesSettingsPage::on_renameIdentity_clicked() {
392   QString oldName = identities[currentId]->identityName();
393   bool ok = false;
394   QString name = QInputDialog::getText(this, tr("Rename Identity"),
395                                        tr("Please enter a new name for the identity \"%1\"!").arg(oldName),
396                                        QLineEdit::Normal, oldName, &ok);
397   if(ok && !name.isEmpty()) {
398     renameIdentity(currentId, name);
399     widgetHasChanged();
400   }
401 }
402
403 void IdentitiesSettingsPage::on_addNick_clicked() {
404   QStringList existing;
405   for(int i = 0; i < ui.nicknameList->count(); i++) existing << ui.nicknameList->item(i)->text();
406   NickEditDlg dlg(QString(), existing, this);
407   if(dlg.exec() == QDialog::Accepted) {
408     ui.nicknameList->addItem(dlg.nick());
409     ui.nicknameList->setCurrentRow(ui.nicknameList->count()-1);
410     setWidgetStates();
411     widgetHasChanged();
412   }
413 }
414
415 void IdentitiesSettingsPage::on_deleteNick_clicked() {
416   // no confirmation, since a nickname is really nothing hard to recreate
417   if(ui.nicknameList->selectedItems().count()) {
418     delete ui.nicknameList->takeItem(ui.nicknameList->row(ui.nicknameList->selectedItems()[0]));
419     ui.nicknameList->setCurrentRow(qMin(ui.nicknameList->currentRow()+1, ui.nicknameList->count()-1));
420     setWidgetStates();
421     widgetHasChanged();
422   }
423 }
424
425 void IdentitiesSettingsPage::on_renameNick_clicked() {
426   if(!ui.nicknameList->selectedItems().count()) return;
427   QString old = ui.nicknameList->selectedItems()[0]->text();
428   QStringList existing;
429   for(int i = 0; i < ui.nicknameList->count(); i++) existing << ui.nicknameList->item(i)->text();
430   NickEditDlg dlg(old, existing, this);
431   if(dlg.exec() == QDialog::Accepted) {
432     ui.nicknameList->selectedItems()[0]->setText(dlg.nick());
433   }
434
435 }
436
437 void IdentitiesSettingsPage::on_nickUp_clicked() {
438   if(!ui.nicknameList->selectedItems().count()) return;
439   int row = ui.nicknameList->row(ui.nicknameList->selectedItems()[0]);
440   if(row > 0) {
441     ui.nicknameList->insertItem(row-1, ui.nicknameList->takeItem(row));
442     ui.nicknameList->setCurrentRow(row-1);
443     setWidgetStates();
444     widgetHasChanged();
445   }
446 }
447
448 void IdentitiesSettingsPage::on_nickDown_clicked() {
449   if(!ui.nicknameList->selectedItems().count()) return;
450   int row = ui.nicknameList->row(ui.nicknameList->selectedItems()[0]);
451   if(row < ui.nicknameList->count()-1) {
452     ui.nicknameList->insertItem(row+1, ui.nicknameList->takeItem(row));
453     ui.nicknameList->setCurrentRow(row+1);
454     setWidgetStates();
455     widgetHasChanged();
456   }
457 }
458
459 void IdentitiesSettingsPage::on_continueUnsecured_clicked() {
460   _editSsl = true;
461
462   QHash<IdentityId, CertIdentity *>::iterator idIter;
463   for(idIter = identities.begin(); idIter != identities.end(); idIter++) {
464     idIter.value()->enableEditSsl();
465   }
466
467   ui.keyAndCertSettings->setCurrentIndex(2);
468 }
469
470 bool IdentitiesSettingsPage::eventFilter(QObject *watched, QEvent *event) {
471   bool isCert = (watched == ui.sslCertGroupBox);
472   switch(event->type()) {
473   case QEvent::DragEnter:
474     sslDragEnterEvent(static_cast<QDragEnterEvent *>(event));
475     return true;
476   case QEvent::Drop:
477     sslDropEvent(static_cast<QDropEvent *>(event), isCert);
478     return true;
479   default:
480     return false;
481   }
482 }
483
484 void IdentitiesSettingsPage::sslDragEnterEvent(QDragEnterEvent *event) {
485   if(event->mimeData()->hasFormat("text/uri-list") || event->mimeData()->hasFormat("text/uri")) {
486     event->setDropAction(Qt::CopyAction);
487     event->accept();
488   }
489 }
490
491 void IdentitiesSettingsPage::sslDropEvent(QDropEvent *event, bool isCert) {
492   QByteArray rawUris;
493   if(event->mimeData()->hasFormat("text/uri-list"))
494     rawUris = event->mimeData()->data("text/uri-list");
495   else
496     rawUris = event->mimeData()->data("text/uri");
497
498   QTextStream uriStream(rawUris);
499   QString filename = QUrl(uriStream.readLine()).toLocalFile();
500
501   if(isCert) {
502     QSslCertificate cert = certByFilename(filename);
503     if(cert.isValid())
504       showCertState(cert);
505   } else {
506     QSslKey key = keyByFilename(filename);
507     if(!key.isNull())
508       showKeyState(key);
509   }
510   event->accept();
511   widgetHasChanged();
512 }
513
514 void IdentitiesSettingsPage::on_clearOrLoadKeyButton_clicked() {
515   QSslKey key;
516
517   if(ui.keyTypeLabel->property("sslKey").toByteArray().isEmpty())
518     key = keyByFilename(QFileDialog::getOpenFileName(this, tr("Load a Key"), QDesktopServices::storageLocation(QDesktopServices::HomeLocation)));
519
520   showKeyState(key);
521   widgetHasChanged();
522 }
523
524 QSslKey IdentitiesSettingsPage::keyByFilename(const QString &filename) {
525   QSslKey key;
526
527   QFile keyFile(filename);
528   keyFile.open(QIODevice::ReadOnly);
529   QByteArray keyRaw = keyFile.read(2 << 20);
530   keyFile.close();
531
532   for(int i = 0; i < 2; i++) {
533     for(int j = 0; j < 2; j++) {
534       key = QSslKey(keyRaw, (QSsl::KeyAlgorithm)j, (QSsl::EncodingFormat)i);
535       if(!key.isNull())
536         goto returnKey;
537     }
538   }
539  returnKey:
540   return key;
541 }
542
543 void IdentitiesSettingsPage::showKeyState(const QSslKey &key) {
544   if(key.isNull()) {
545     ui.keyTypeLabel->setText(tr("No Key loaded"));
546     ui.clearOrLoadKeyButton->setText(tr("Load"));
547   } else {
548     switch(key.algorithm()) {
549     case QSsl::Rsa:
550       ui.keyTypeLabel->setText(tr("RSA"));
551       break;
552     case QSsl::Dsa:
553       ui.keyTypeLabel->setText(tr("DSA"));
554       break;
555     default:
556       ui.keyTypeLabel->setText(tr("No Key Loaded"));
557     }
558     ui.clearOrLoadKeyButton->setText(tr("Clear"));
559   }
560   ui.keyTypeLabel->setProperty("sslKey", key.toPem());
561   ui.keyTypeLabel->setProperty("sslKeyType", (int)key.algorithm());
562 }
563
564 void IdentitiesSettingsPage::on_clearOrLoadCertButton_clicked() {
565   QSslCertificate cert;
566
567   if(ui.certOrgLabel->property("sslCert").toByteArray().isEmpty())
568     cert = certByFilename(QFileDialog::getOpenFileName(this, tr("Load a Certificate"), QDesktopServices::storageLocation(QDesktopServices::HomeLocation)));
569
570   showCertState(cert);
571   widgetHasChanged();
572 }
573
574 QSslCertificate IdentitiesSettingsPage::certByFilename(const QString &filename) {
575   QSslCertificate cert;
576   QFile certFile(filename);
577   certFile.open(QIODevice::ReadOnly);
578   QByteArray certRaw = certFile.read(2 << 20);
579   certFile.close();
580
581   for(int i = 0; i < 2; i++) {
582     cert = QSslCertificate(certRaw, (QSsl::EncodingFormat)i);
583     if(cert.isValid())
584       break;
585   }
586   return cert;
587 }
588
589 void IdentitiesSettingsPage::showCertState(const QSslCertificate &cert) {
590   if(!cert.isValid()) {
591     ui.certOrgLabel->setText(tr("No Certificate loaded"));
592     ui.certCNameLabel->setText(tr("No Certificate loaded"));
593     ui.clearOrLoadCertButton->setText(tr("Load"));
594   } else {
595     ui.certOrgLabel->setText(cert.subjectInfo(QSslCertificate::Organization));
596     ui.certCNameLabel->setText(cert.subjectInfo(QSslCertificate::CommonName));
597     ui.clearOrLoadCertButton->setText(tr("Clear"));
598   }
599   ui.certOrgLabel->setProperty("sslCert", cert.toPem());
600  }
601
602 /*****************************************************************************************/
603
604 CreateIdentityDlg::CreateIdentityDlg(QAbstractItemModel *model, QWidget *parent)
605   : QDialog(parent)
606 {
607   ui.setupUi(this);
608
609   ui.identityList->setModel(model);  // now we use the identity list of the main page... Trolltech <3
610   on_identityName_textChanged("");   // disable ok button :)
611 }
612
613 QString CreateIdentityDlg::identityName() const {
614   return ui.identityName->text();
615 }
616
617 IdentityId CreateIdentityDlg::duplicateId() const {
618   if(!ui.duplicateIdentity->isChecked()) return 0;
619   if(ui.identityList->currentIndex() >= 0) {
620     return ui.identityList->itemData(ui.identityList->currentIndex()).toInt();
621   }
622   return 0;
623 }
624
625 void CreateIdentityDlg::on_identityName_textChanged(const QString &text) {
626   ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(text.count());
627
628 }
629
630 /*********************************************************************************************/
631
632 SaveIdentitiesDlg::SaveIdentitiesDlg(const QList<CertIdentity *> &toCreate, const QList<CertIdentity *> &toUpdate, const QList<IdentityId> &toRemove, QWidget *parent)
633   : QDialog(parent)
634 {
635   ui.setupUi(this);
636   ui.abort->setIcon(SmallIcon("dialog-cancel"));
637
638   numevents = toCreate.count() + toUpdate.count() + toRemove.count();
639   rcvevents = 0;
640   if(numevents) {
641     ui.progressBar->setMaximum(numevents);
642     ui.progressBar->setValue(0);
643
644     connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientEvent()));
645     connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientEvent()));
646
647     foreach(CertIdentity *id, toCreate) {
648       Client::createIdentity(*id);
649     }
650     foreach(CertIdentity *id, toUpdate) {
651       const Identity *cid = Client::identity(id->id());
652       if(!cid) {
653         qWarning() << "Invalid client identity!";
654         numevents--;
655         continue;
656       }
657       connect(cid, SIGNAL(updatedRemotely()), this, SLOT(clientEvent()));
658       Client::updateIdentity(id->id(), id->toVariantMap());
659       id->requestUpdateSslSettings();
660     }
661     foreach(IdentityId id, toRemove) {
662       Client::removeIdentity(id);
663     }
664   } else {
665     qWarning() << "Sync dialog called without stuff to change!";
666     accept();
667   }
668 }
669
670 void SaveIdentitiesDlg::clientEvent() {
671   ui.progressBar->setValue(++rcvevents);
672   if(rcvevents >= numevents) accept();
673 }
674
675 /*************************************************************************************************/
676
677 NickEditDlg::NickEditDlg(const QString &old, const QStringList &exist, QWidget *parent)
678   : QDialog(parent), oldNick(old), existing(exist) {
679   ui.setupUi(this);
680
681   // define a regexp for valid nicknames
682   // TODO: add max nicklength according to ISUPPORT
683   QString letter = "A-Za-z";
684   QString special = "\x5b-\x60\x7b-\x7d";
685   QRegExp rx(QString("[%1%2][%1%2\\d-]*").arg(letter, special));
686   ui.nickEdit->setValidator(new QRegExpValidator(rx, ui.nickEdit));
687   if(old.isEmpty()) {
688     // new nick
689     setWindowTitle(tr("Add Nickname"));
690     on_nickEdit_textChanged(""); // disable ok button
691   } else ui.nickEdit->setText(old);
692 }
693
694 QString NickEditDlg::nick() const {
695   return ui.nickEdit->text();
696
697 }
698
699 void NickEditDlg::on_nickEdit_textChanged(const QString &text) {
700   ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text));
701 }
702
703
704