Fix ALL the license headers!
[quassel.git] / src / qtui / settingspages / identityeditwidget.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2012 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 "identityeditwidget.h"
22
23 #include <QDesktopServices>
24 #include <QDragEnterEvent>
25 #include <QDropEvent>
26 #include <QFileDialog>
27 #include <QUrl>
28
29 #include "client.h"
30 #include "iconloader.h"
31
32 IdentityEditWidget::IdentityEditWidget(QWidget *parent)
33     : QWidget(parent)
34 {
35     ui.setupUi(this);
36
37     ui.addNick->setIcon(SmallIcon("list-add"));
38     ui.deleteNick->setIcon(SmallIcon("edit-delete"));
39     ui.renameNick->setIcon(SmallIcon("edit-rename"));
40     ui.nickUp->setIcon(SmallIcon("go-up"));
41     ui.nickDown->setIcon(SmallIcon("go-down"));
42
43     // We need to know whenever the state of input widgets changes...
44     connect(ui.realName, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
45     connect(ui.nicknameList, SIGNAL(itemChanged(QListWidgetItem *)), this, SIGNAL(widgetHasChanged()));
46     connect(ui.awayNick, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
47     connect(ui.awayReason, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
48     connect(ui.autoAwayEnabled, SIGNAL(clicked(bool)), this, SIGNAL(widgetHasChanged()));
49     connect(ui.autoAwayTime, SIGNAL(valueChanged(int)), this, SIGNAL(widgetHasChanged()));
50     connect(ui.autoAwayReason, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
51     connect(ui.autoAwayReasonEnabled, SIGNAL(clicked(bool)), this, SIGNAL(widgetHasChanged()));
52     connect(ui.detachAwayEnabled, SIGNAL(clicked(bool)), this, SIGNAL(widgetHasChanged()));
53     connect(ui.detachAwayReason, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
54     connect(ui.ident, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
55     connect(ui.kickReason, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
56     connect(ui.partReason, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
57     connect(ui.quitReason, SIGNAL(textEdited(const QString &)), this, SIGNAL(widgetHasChanged()));
58
59     setWidgetStates();
60     connect(ui.nicknameList, SIGNAL(itemSelectionChanged()), this, SLOT(setWidgetStates()));
61
62     connect(ui.continueUnsecured, SIGNAL(clicked()), this, SIGNAL(requestEditSsl()));
63
64     // we would need this if we enabled drag and drop in the nicklist...
65     //connect(ui.nicknameList, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(setWidgetStates()));
66     //connect(ui.nicknameList->model(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(nicklistHasChanged()));
67
68     // disabling unused stuff
69     ui.autoAwayEnabled->hide();
70     ui.awayNick->hide();
71     ui.awayNickLabel->hide();
72
73     ui.detachAwayEnabled->setVisible(!Client::internalCore());
74
75 #ifdef HAVE_SSL
76     ui.sslKeyGroupBox->setAcceptDrops(true);
77     ui.sslKeyGroupBox->installEventFilter(this);
78     ui.sslCertGroupBox->setAcceptDrops(true);
79     ui.sslCertGroupBox->installEventFilter(this);
80 #endif
81 }
82
83
84 void IdentityEditWidget::setWidgetStates()
85 {
86     if (ui.nicknameList->selectedItems().count()) {
87         ui.renameNick->setEnabled(true);
88         ui.nickUp->setEnabled(ui.nicknameList->row(ui.nicknameList->selectedItems()[0]) > 0);
89         ui.nickDown->setEnabled(ui.nicknameList->row(ui.nicknameList->selectedItems()[0]) < ui.nicknameList->count()-1);
90     }
91     else {
92         ui.renameNick->setDisabled(true);
93         ui.nickUp->setDisabled(true);
94         ui.nickDown->setDisabled(true);
95     }
96     ui.deleteNick->setEnabled(ui.nicknameList->count() > 1);
97 }
98
99
100 void IdentityEditWidget::displayIdentity(CertIdentity *id, CertIdentity *saveId)
101 {
102     if (saveId) {
103         saveToIdentity(saveId);
104     }
105
106     if (!id)
107         return;
108
109     ui.realName->setText(id->realName());
110     ui.nicknameList->clear();
111     ui.nicknameList->addItems(id->nicks());
112     //for(int i = 0; i < ui.nicknameList->count(); i++) {
113     //  ui.nicknameList->item(i)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled);
114     //}
115     if (ui.nicknameList->count()) ui.nicknameList->setCurrentRow(0);
116     ui.awayNick->setText(id->awayNick());
117     ui.awayReason->setText(id->awayReason());
118     ui.autoAwayEnabled->setChecked(id->autoAwayEnabled());
119     ui.autoAwayTime->setValue(id->autoAwayTime());
120     ui.autoAwayReason->setText(id->autoAwayReason());
121     ui.autoAwayReasonEnabled->setChecked(id->autoAwayReasonEnabled());
122     ui.detachAwayEnabled->setChecked(id->detachAwayEnabled());
123     ui.detachAwayReason->setText(id->detachAwayReason());
124     ui.ident->setText(id->ident());
125     ui.kickReason->setText(id->kickReason());
126     ui.partReason->setText(id->partReason());
127     ui.quitReason->setText(id->quitReason());
128 #ifdef HAVE_SSL
129     showKeyState(id->sslKey());
130     showCertState(id->sslCert());
131 #endif
132 }
133
134
135 void IdentityEditWidget::saveToIdentity(CertIdentity *id)
136 {
137     id->setRealName(ui.realName->text());
138     QStringList nicks;
139     for (int i = 0; i < ui.nicknameList->count(); i++) {
140         nicks << ui.nicknameList->item(i)->text();
141     }
142     id->setNicks(nicks);
143     id->setAwayNick(ui.awayNick->text());
144     id->setAwayNickEnabled(true);
145     id->setAwayReason(ui.awayReason->text());
146     id->setAwayReasonEnabled(true);
147     id->setAutoAwayEnabled(ui.autoAwayEnabled->isChecked());
148     id->setAutoAwayTime(ui.autoAwayTime->value());
149     id->setAutoAwayReason(ui.autoAwayReason->text());
150     id->setAutoAwayReasonEnabled(ui.autoAwayReasonEnabled->isChecked());
151     id->setDetachAwayEnabled(ui.detachAwayEnabled->isChecked());
152     id->setDetachAwayReason(ui.detachAwayReason->text());
153     id->setDetachAwayReasonEnabled(true);
154     id->setIdent(ui.ident->text());
155     id->setKickReason(ui.kickReason->text());
156     id->setPartReason(ui.partReason->text());
157     id->setQuitReason(ui.quitReason->text());
158 #ifdef HAVE_SSL
159     id->setSslKey(QSslKey(ui.keyTypeLabel->property("sslKey").toByteArray(), (QSsl::KeyAlgorithm)(ui.keyTypeLabel->property("sslKeyType").toInt())));
160     id->setSslCert(QSslCertificate(ui.certOrgLabel->property("sslCert").toByteArray()));
161 #endif
162 }
163
164
165 void IdentityEditWidget::on_addNick_clicked()
166 {
167     QStringList existing;
168     for (int i = 0; i < ui.nicknameList->count(); i++) existing << ui.nicknameList->item(i)->text();
169     NickEditDlg dlg(QString(), existing, this);
170     if (dlg.exec() == QDialog::Accepted) {
171         ui.nicknameList->addItem(dlg.nick());
172         ui.nicknameList->setCurrentRow(ui.nicknameList->count()-1);
173         setWidgetStates();
174         emit widgetHasChanged();
175     }
176 }
177
178
179 void IdentityEditWidget::on_deleteNick_clicked()
180 {
181     // no confirmation, since a nickname is really nothing hard to recreate
182     if (ui.nicknameList->selectedItems().count()) {
183         delete ui.nicknameList->takeItem(ui.nicknameList->row(ui.nicknameList->selectedItems()[0]));
184         ui.nicknameList->setCurrentRow(qMin(ui.nicknameList->currentRow()+1, ui.nicknameList->count()-1));
185         setWidgetStates();
186         emit widgetHasChanged();
187     }
188 }
189
190
191 void IdentityEditWidget::on_renameNick_clicked()
192 {
193     if (!ui.nicknameList->selectedItems().count()) return;
194     QString old = ui.nicknameList->selectedItems()[0]->text();
195     QStringList existing;
196     for (int i = 0; i < ui.nicknameList->count(); i++) existing << ui.nicknameList->item(i)->text();
197     NickEditDlg dlg(old, existing, this);
198     if (dlg.exec() == QDialog::Accepted) {
199         ui.nicknameList->selectedItems()[0]->setText(dlg.nick());
200     }
201 }
202
203
204 void IdentityEditWidget::on_nickUp_clicked()
205 {
206     if (!ui.nicknameList->selectedItems().count()) return;
207     int row = ui.nicknameList->row(ui.nicknameList->selectedItems()[0]);
208     if (row > 0) {
209         ui.nicknameList->insertItem(row-1, ui.nicknameList->takeItem(row));
210         ui.nicknameList->setCurrentRow(row-1);
211         setWidgetStates();
212         emit widgetHasChanged();
213     }
214 }
215
216
217 void IdentityEditWidget::on_nickDown_clicked()
218 {
219     if (!ui.nicknameList->selectedItems().count()) return;
220     int row = ui.nicknameList->row(ui.nicknameList->selectedItems()[0]);
221     if (row < ui.nicknameList->count()-1) {
222         ui.nicknameList->insertItem(row+1, ui.nicknameList->takeItem(row));
223         ui.nicknameList->setCurrentRow(row+1);
224         setWidgetStates();
225         emit widgetHasChanged();
226     }
227 }
228
229
230 void IdentityEditWidget::showAdvanced(bool advanced)
231 {
232     int idx = ui.tabWidget->indexOf(ui.advancedTab);
233     if (advanced) {
234         if (idx != -1)
235             return;  // already added
236         ui.tabWidget->addTab(ui.advancedTab, tr("Advanced"));
237     }
238     else {
239         if (idx == -1)
240             return;  // already removed
241         ui.tabWidget->removeTab(idx);
242     }
243 }
244
245
246 void IdentityEditWidget::setSslState(SslState state)
247 {
248     switch (state) {
249     case NoSsl:
250         ui.keyAndCertSettings->setCurrentIndex(0);
251         break;
252     case UnsecureSsl:
253         ui.keyAndCertSettings->setCurrentIndex(1);
254         break;
255     case AllowSsl:
256         ui.keyAndCertSettings->setCurrentIndex(2);
257         break;
258     }
259 }
260
261
262 #ifdef HAVE_SSL
263 bool IdentityEditWidget::eventFilter(QObject *watched, QEvent *event)
264 {
265     bool isCert = (watched == ui.sslCertGroupBox);
266     switch (event->type()) {
267     case QEvent::DragEnter:
268         sslDragEnterEvent(static_cast<QDragEnterEvent *>(event));
269         return true;
270     case QEvent::Drop:
271         sslDropEvent(static_cast<QDropEvent *>(event), isCert);
272         return true;
273     default:
274         return false;
275     }
276 }
277
278
279 void IdentityEditWidget::sslDragEnterEvent(QDragEnterEvent *event)
280 {
281     if (event->mimeData()->hasFormat("text/uri-list") || event->mimeData()->hasFormat("text/uri")) {
282         event->setDropAction(Qt::CopyAction);
283         event->accept();
284     }
285 }
286
287
288 void IdentityEditWidget::sslDropEvent(QDropEvent *event, bool isCert)
289 {
290     QByteArray rawUris;
291     if (event->mimeData()->hasFormat("text/uri-list"))
292         rawUris = event->mimeData()->data("text/uri-list");
293     else
294         rawUris = event->mimeData()->data("text/uri");
295
296     QTextStream uriStream(rawUris);
297     QString filename = QUrl(uriStream.readLine()).toLocalFile();
298
299     if (isCert) {
300         QSslCertificate cert = certByFilename(filename);
301         if (cert.isValid())
302             showCertState(cert);
303     }
304     else {
305         QSslKey key = keyByFilename(filename);
306         if (!key.isNull())
307             showKeyState(key);
308     }
309     event->accept();
310     emit widgetHasChanged();
311 }
312
313
314 void IdentityEditWidget::on_clearOrLoadKeyButton_clicked()
315 {
316     QSslKey key;
317
318     if (ui.keyTypeLabel->property("sslKey").toByteArray().isEmpty())
319         key = keyByFilename(QFileDialog::getOpenFileName(this, tr("Load a Key"), QDesktopServices::storageLocation(QDesktopServices::HomeLocation)));
320
321     showKeyState(key);
322     emit widgetHasChanged();
323 }
324
325
326 QSslKey IdentityEditWidget::keyByFilename(const QString &filename)
327 {
328     QSslKey key;
329
330     QFile keyFile(filename);
331     keyFile.open(QIODevice::ReadOnly);
332     QByteArray keyRaw = keyFile.read(2 << 20);
333     keyFile.close();
334
335     for (int i = 0; i < 2; i++) {
336         for (int j = 0; j < 2; j++) {
337             key = QSslKey(keyRaw, (QSsl::KeyAlgorithm)j, (QSsl::EncodingFormat)i);
338             if (!key.isNull())
339                 goto returnKey;
340         }
341     }
342 returnKey:
343     return key;
344 }
345
346
347 void IdentityEditWidget::showKeyState(const QSslKey &key)
348 {
349     if (key.isNull()) {
350         ui.keyTypeLabel->setText(tr("No Key loaded"));
351         ui.clearOrLoadKeyButton->setText(tr("Load"));
352     }
353     else {
354         switch (key.algorithm()) {
355         case QSsl::Rsa:
356             ui.keyTypeLabel->setText(tr("RSA"));
357             break;
358         case QSsl::Dsa:
359             ui.keyTypeLabel->setText(tr("DSA"));
360             break;
361         default:
362             ui.keyTypeLabel->setText(tr("No Key loaded"));
363         }
364         ui.clearOrLoadKeyButton->setText(tr("Clear"));
365     }
366     ui.keyTypeLabel->setProperty("sslKey", key.toPem());
367     ui.keyTypeLabel->setProperty("sslKeyType", (int)key.algorithm());
368 }
369
370
371 void IdentityEditWidget::on_clearOrLoadCertButton_clicked()
372 {
373     QSslCertificate cert;
374
375     if (ui.certOrgLabel->property("sslCert").toByteArray().isEmpty())
376         cert = certByFilename(QFileDialog::getOpenFileName(this, tr("Load a Certificate"), QDesktopServices::storageLocation(QDesktopServices::HomeLocation)));
377
378     showCertState(cert);
379     emit widgetHasChanged();
380 }
381
382
383 QSslCertificate IdentityEditWidget::certByFilename(const QString &filename)
384 {
385     QSslCertificate cert;
386     QFile certFile(filename);
387     certFile.open(QIODevice::ReadOnly);
388     QByteArray certRaw = certFile.read(2 << 20);
389     certFile.close();
390
391     for (int i = 0; i < 2; i++) {
392         cert = QSslCertificate(certRaw, (QSsl::EncodingFormat)i);
393         if (cert.isValid())
394             break;
395     }
396     return cert;
397 }
398
399
400 void IdentityEditWidget::showCertState(const QSslCertificate &cert)
401 {
402     if (!cert.isValid()) {
403         ui.certOrgLabel->setText(tr("No Certificate loaded"));
404         ui.certCNameLabel->setText(tr("No Certificate loaded"));
405         ui.clearOrLoadCertButton->setText(tr("Load"));
406     }
407     else {
408         ui.certOrgLabel->setText(cert.subjectInfo(QSslCertificate::Organization));
409         ui.certCNameLabel->setText(cert.subjectInfo(QSslCertificate::CommonName));
410         ui.clearOrLoadCertButton->setText(tr("Clear"));
411     }
412     ui.certOrgLabel->setProperty("sslCert", cert.toPem());
413 }
414
415
416 #endif //HAVE_SSL