Make it compiles when deprecated method are disabled. Add more find package
[kdepim.git] / kmail / src / identity / identitydialog.cpp
blob6692232c0e7682af040af7dd7f8936e98965f1e7
1 /*
2 identitydialog.cpp
4 This file is part of KMail, the KDE mail client.
5 Copyright (c) 2002 Marc Mutz <mutz@kde.org>
6 Copyright (c) 2014-2016 Laurent Montel <montel@kde.org>
8 KMail is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License, version 2, as
10 published by the Free Software Foundation.
12 KMail is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 In addition, as a special exception, the copyright holders give
22 permission to link the code of this program with any edition of
23 the Qt library by Trolltech AS, Norway (or with modified versions
24 of Qt that use the same license as Qt), and distribute linked
25 combinations including the two. You must obey the GNU General
26 Public License in all respects for all of the code used other than
27 Qt. If you modify this file, you may extend this exception to
28 your version of the file, but you are not obligated to do so. If
29 you do not wish to do so, delete this exception statement from
30 your version.
33 #include "identitydialog.h"
34 #include "identityeditvcarddialog.h"
35 #include "identityaddvcarddialog.h"
36 #include "identityinvalidfolder.h"
37 #include "identityfolderrequester.h"
39 #include "MessageComposer/MessageComposerSettings"
41 #include <KIdentityManagement/kidentitymanagement/identitymanager.h>
43 // other KMail headers:
44 #include "xfaceconfigurator.h"
45 #include <KEditListWidget>
46 #include "mailcommon/folderrequester.h"
47 #ifndef KCM_KPIMIDENTITIES_STANDALONE
48 #include "settings/kmailsettings.h"
49 #include "kmkernel.h"
50 #endif
52 #include "mailcommon/mailkernel.h"
54 #include "job/addressvalidationjob.h"
55 #include "MessageComposer/Kleo_Util"
56 #include <MessageCore/StringUtil>
57 #include "TemplateParser/TemplatesConfiguration"
58 #include "templatesconfiguration_kfg.h"
59 // other kdepim headers:
60 #include <KIdentityManagement/kidentitymanagement/identity.h>
61 #include <KIdentityManagement/kidentitymanagement/signatureconfigurator.h>
63 #include "PimCommon/AutoCorrectionLanguage"
64 #include <PimCommon/PimUtil>
66 #include <Libkdepim/AddresseeLineEdit>
67 // libkleopatra:
68 #include <Libkleo/KeySelectionCombo>
69 #include <Libkleo/CryptoBackendFactory>
70 #include <Libkleo/DefaultKeyFilter>
71 #include <Libkleo/DefaultKeyGenerationJob>
72 #include <Libkleo/ProgressDialog>
74 // gpgme++
75 #include <gpgme++/keygenerationresult.h>
77 #include <KEmailAddress>
78 #include <Libkdepim/EmailValidator>
79 #include <MailTransport/mailtransport/transport.h>
80 #include <MailTransport/mailtransport/transportmanager.h>
81 #include <MailTransport/mailtransport/transportcombobox.h>
82 using MailTransport::TransportManager;
84 // other KDE headers:
85 #include <KLocalizedString>
86 #include <kmessagebox.h>
87 #include <kfileitem.h>
88 #include <qurl.h>
89 #include "kmail_debug.h"
90 #include <QPushButton>
91 #include <kcombobox.h>
92 #include <QTabWidget>
93 #include <QIcon>
94 #include <sonnet/dictionarycombobox.h>
95 #include <KHelpClient>
97 // Qt headers:
98 #include <QLabel>
99 #include <QCheckBox>
100 #include <QVBoxLayout>
101 #include <QGridLayout>
102 #include <QFile>
103 #include <QHostInfo>
104 #include <QToolButton>
105 #include <QFileInfo>
106 #include <QDir>
108 // other headers:
109 #include <gpgme++/key.h>
110 #include <iterator>
111 #include <algorithm>
113 #include <AkonadiCore/entitydisplayattribute.h>
114 #include <AkonadiCore/collectionmodifyjob.h>
115 #include <QStandardPaths>
116 #include <KConfigGroup>
117 #include <QDialogButtonBox>
119 using namespace KPIM;
120 using namespace MailTransport;
121 using namespace MailCommon;
123 namespace KMail
126 class KeySelectionCombo : public Kleo::KeySelectionCombo
128 Q_OBJECT
130 public:
131 enum KeyType {
132 SigningKey,
133 EncryptionKey
136 KeySelectionCombo(KeyType keyType, GpgME::Protocol protocol, QWidget *parent);
137 ~KeySelectionCombo();
139 void setIdentity(const QString &name, const QString &email);
141 void init() Q_DECL_OVERRIDE;
143 private Q_SLOTS:
144 void onCustomItemSelected(const QVariant &type);
146 private:
147 QString mEmail;
148 QString mName;
149 KeyType mKeyType;
150 GpgME::Protocol mProtocol;
153 class KeyGenerationJob : public Kleo::Job
155 Q_OBJECT
157 public:
158 KeyGenerationJob(const QString &name, const QString &email, KeySelectionCombo *parent);
159 ~KeyGenerationJob();
161 void slotCancel() Q_DECL_OVERRIDE;
162 void start();
164 private Q_SLOTS:
165 void keyGenerated(const GpgME::KeyGenerationResult &result);
167 private:
168 QString mName;
169 QString mEmail;
170 Kleo::Job *mJob;
173 KeyGenerationJob::KeyGenerationJob(const QString &name, const QString &email, KeySelectionCombo *parent)
174 : Kleo::Job(parent)
175 , mName(name)
176 , mEmail(email)
177 , mJob(Q_NULLPTR)
181 KeyGenerationJob::~KeyGenerationJob()
185 void KeyGenerationJob::slotCancel()
187 if (mJob) {
188 mJob->slotCancel();
192 void KeyGenerationJob::start()
194 auto job = new Kleo::DefaultKeyGenerationJob(this);
195 connect(job, &Kleo::DefaultKeyGenerationJob::result,
196 this, &KeyGenerationJob::keyGenerated);
197 job->start(mEmail, mName);
198 mJob = job;
201 void KeyGenerationJob::keyGenerated(const GpgME::KeyGenerationResult &result)
203 mJob = Q_NULLPTR;
204 if (result.error()) {
205 KMessageBox::error(qobject_cast<QWidget *>(parent()),
206 i18n("Error while generating new key pair: %1", QString::fromUtf8(result.error().asString())),
207 i18n("Key Generation Error"));
208 Q_EMIT done();
209 return;
212 KeySelectionCombo *combo = qobject_cast<KeySelectionCombo *>(parent());
213 combo->setDefaultKey(QLatin1String(result.fingerprint()));
214 connect(combo, &KeySelectionCombo::keyListingFinished,
215 this, &KeyGenerationJob::done);
216 combo->refreshKeys();
219 KeySelectionCombo::KeySelectionCombo(KeyType keyType, GpgME::Protocol protocol, QWidget *parent)
220 : Kleo::KeySelectionCombo(parent)
221 , mKeyType(keyType)
222 , mProtocol(protocol)
226 KeySelectionCombo::~KeySelectionCombo()
230 void KeySelectionCombo::setIdentity(const QString &name, const QString &email)
232 mName = name;
233 mEmail = email;
234 setIdFilter(email);
237 void KeySelectionCombo::init()
239 Kleo::KeySelectionCombo::init();
241 boost::shared_ptr<Kleo::DefaultKeyFilter> keyFilter(new Kleo::DefaultKeyFilter);
242 keyFilter->setIsOpenPGP(mProtocol == GpgME::OpenPGP ? Kleo::DefaultKeyFilter::Set : Kleo::DefaultKeyFilter::NotSet);
243 if (mKeyType == SigningKey) {
244 keyFilter->setCanSign(Kleo::DefaultKeyFilter::Set);
245 } else {
246 keyFilter->setCanEncrypt(Kleo::DefaultKeyFilter::Set);
248 keyFilter->setHasSecret(Kleo::DefaultKeyFilter::Set);
249 setKeyFilter(keyFilter);
250 prependCustomItem(QIcon(), i18n("No key"), QStringLiteral("no-key"));
251 if (mProtocol == GpgME::OpenPGP) {
252 appendCustomItem(QIcon::fromTheme(QStringLiteral("password-generate")),
253 i18n("Generate a new key pair"), QStringLiteral("generate-new-key"));
256 connect(this, &KeySelectionCombo::customItemSelected,
257 this, &KeySelectionCombo::onCustomItemSelected);
260 void KeySelectionCombo::onCustomItemSelected(const QVariant &type)
262 if (type == QLatin1String("no-key")) {
263 return;
264 } else if (type == QLatin1String("generate-new-key")) {
265 auto job = new KeyGenerationJob(mName, mEmail, this);
266 new Kleo::ProgressDialog(job, i18n("Generating new key pair..."), parentWidget());
267 setEnabled(false);
268 connect(job, &KeyGenerationJob::done,
269 this, [this]() {
270 setEnabled(true);
272 job->start();
276 IdentityDialog::IdentityDialog(QWidget *parent)
277 : QDialog(parent)
279 setWindowTitle(i18n("Edit Identity"));
280 QVBoxLayout *mainLayout = new QVBoxLayout(this);
282 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help);
283 connect(buttonBox->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &IdentityDialog::slotHelp);
284 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
285 okButton->setDefault(true);
286 okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
287 connect(buttonBox, &QDialogButtonBox::accepted, this, &IdentityDialog::slotAccepted);
288 connect(buttonBox, &QDialogButtonBox::rejected, this, &IdentityDialog::reject);
290 // tmp. vars:
291 QWidget *tab;
292 QLabel *label;
293 int row;
294 QGridLayout *glay;
295 QString msg;
298 // Tab Widget: General
300 row = -1;
301 QWidget *page = new QWidget(this);
302 mainLayout->addWidget(page);
303 mainLayout->addWidget(buttonBox);
304 QVBoxLayout *vlay = new QVBoxLayout(page);
305 vlay->setMargin(0);
306 mTabWidget = new QTabWidget(page);
307 mTabWidget->setObjectName(QStringLiteral("config-identity-tab"));
308 vlay->addWidget(mTabWidget);
310 tab = new QWidget(mTabWidget);
311 mTabWidget->addTab(tab, i18nc("@title:tab General identity settings.", "General"));
312 glay = new QGridLayout(tab);
313 glay->setRowStretch(3, 1);
314 glay->setColumnStretch(1, 1);
316 // "Name" line edit and label:
317 ++row;
318 mNameEdit = new KLineEdit(tab);
319 glay->addWidget(mNameEdit, row, 1);
320 label = new QLabel(i18n("&Your name:"), tab);
321 label->setBuddy(mNameEdit);
322 glay->addWidget(label, row, 0);
323 msg = i18n("<qt><h3>Your name</h3>"
324 "<p>This field should contain your name as you would like "
325 "it to appear in the email header that is sent out;</p>"
326 "<p>if you leave this blank your real name will not "
327 "appear, only the email address.</p></qt>");
328 label->setWhatsThis(msg);
329 mNameEdit->setWhatsThis(msg);
331 // "Organization" line edit and label:
332 ++row;
333 mOrganizationEdit = new KLineEdit(tab);
334 glay->addWidget(mOrganizationEdit, row, 1);
335 label = new QLabel(i18n("Organi&zation:"), tab);
336 label->setBuddy(mOrganizationEdit);
337 glay->addWidget(label, row, 0);
338 msg = i18n("<qt><h3>Organization</h3>"
339 "<p>This field should have the name of your organization "
340 "if you would like it to be shown in the email header that "
341 "is sent out.</p>"
342 "<p>It is safe (and normal) to leave this blank.</p></qt>");
343 label->setWhatsThis(msg);
344 mOrganizationEdit->setWhatsThis(msg);
346 // "Email Address" line edit and label:
347 // (row 3: spacer)
348 ++row;
349 mEmailEdit = new KLineEdit(tab);
350 glay->addWidget(mEmailEdit, row, 1);
351 label = new QLabel(i18n("&Email address:"), tab);
352 label->setBuddy(mEmailEdit);
353 glay->addWidget(label, row, 0);
354 msg = i18n("<qt><h3>Email address</h3>"
355 "<p>This field should have your full email address.</p>"
356 "<p>This address is the primary one, used for all outgoing mail. "
357 "If you have more than one address, either create a new identity, "
358 "or add additional alias addresses in the field below.</p>"
359 "<p>If you leave this blank, or get it wrong, people "
360 "will have trouble replying to you.</p></qt>");
361 label->setWhatsThis(msg);
362 mEmailEdit->setWhatsThis(msg);
364 KPIM::EmailValidator *emailValidator = new KPIM::EmailValidator(this);
365 mEmailEdit->setValidator(emailValidator);
367 // "Email Aliases" string text edit and label:
368 ++row;
369 mAliasEdit = new KEditListWidget(tab);
371 KPIM::EmailValidator *emailValidator1 = new KPIM::EmailValidator(this);
372 mAliasEdit->lineEdit()->setValidator(emailValidator1);
374 glay->addWidget(mAliasEdit, row, 1);
375 label = new QLabel(i18n("Email a&liases:"), tab);
376 label->setBuddy(mAliasEdit);
377 glay->addWidget(label, row, 0, Qt::AlignTop);
378 msg = i18n("<qt><h3>Email aliases</h3>"
379 "<p>This field contains alias addresses that should also "
380 "be considered as belonging to this identity (as opposed "
381 "to representing a different identity).</p>"
382 "<p>Example:</p>"
383 "<table>"
384 "<tr><th>Primary address:</th><td>first.last@example.org</td></tr>"
385 "<tr><th>Aliases:</th><td>first@example.org<br>last@example.org</td></tr>"
386 "</table>"
387 "<p>Type one alias address per line.</p></qt>");
388 label->setToolTip(msg);
389 mAliasEdit->setWhatsThis(msg);
392 // Tab Widget: Cryptography
394 row = -1;
395 mCryptographyTab = tab = new QWidget(mTabWidget);
396 mTabWidget->addTab(tab, i18n("Cryptography"));
397 glay = new QGridLayout(tab);
398 glay->setColumnStretch(1, 1);
400 // "OpenPGP Signature Key" requester and label:
401 ++row;
402 mPGPSigningKeyRequester = new KeySelectionCombo(KeySelectionCombo::SigningKey, GpgME::OpenPGP, tab);
403 msg = i18n("<qt><p>The OpenPGP key you choose here will be used "
404 "to digitally sign messages. You can also use GnuPG keys.</p>"
405 "<p>You can leave this blank, but KMail will not be able "
406 "to digitally sign emails using OpenPGP; "
407 "normal mail functions will not be affected.</p>"
408 "<p>You can find out more about keys at <a>http://www.gnupg.org</a></p></qt>");
409 label = new QLabel(i18n("OpenPGP signing key:"), tab);
410 label->setBuddy(mPGPSigningKeyRequester);
411 mPGPSigningKeyRequester->setWhatsThis(msg);
412 label->setWhatsThis(msg);
414 glay->addWidget(label, row, 0);
415 glay->addWidget(mPGPSigningKeyRequester, row, 1);
417 // "OpenPGP Encryption Key" requester and label:
418 ++row;
419 mPGPEncryptionKeyRequester = new KeySelectionCombo(KeySelectionCombo::EncryptionKey, GpgME::OpenPGP, tab);
420 msg = i18n("<qt><p>The OpenPGP key you choose here will be used "
421 "to encrypt messages to yourself and for the \"Attach My Public Key\" "
422 "feature in the composer. You can also use GnuPG keys.</p>"
423 "<p>You can leave this blank, but KMail will not be able "
424 "to encrypt copies of outgoing messages to you using OpenPGP; "
425 "normal mail functions will not be affected.</p>"
426 "<p>You can find out more about keys at <a>http://www.gnupg.org</a></p></qt>");
427 label = new QLabel(i18n("OpenPGP encryption key:"), tab);
428 label->setBuddy(mPGPEncryptionKeyRequester);
429 mPGPEncryptionKeyRequester->setWhatsThis(msg);
430 label->setWhatsThis(msg);
432 glay->addWidget(label, row, 0);
433 glay->addWidget(mPGPEncryptionKeyRequester, row, 1);
435 // "S/MIME Signature Key" requester and label:
436 ++row;
437 mSMIMESigningKeyRequester = new KeySelectionCombo(KeySelectionCombo::SigningKey, GpgME::CMS, tab);
438 msg = i18n("<qt><p>The S/MIME (X.509) certificate you choose here will be used "
439 "to digitally sign messages.</p>"
440 "<p>You can leave this blank, but KMail will not be able "
441 "to digitally sign emails using S/MIME; "
442 "normal mail functions will not be affected.</p></qt>");
443 label = new QLabel(i18n("S/MIME signing certificate:"), tab);
444 label->setBuddy(mSMIMESigningKeyRequester);
445 mSMIMESigningKeyRequester->setWhatsThis(msg);
446 label->setWhatsThis(msg);
447 glay->addWidget(label, row, 0);
448 glay->addWidget(mSMIMESigningKeyRequester, row, 1);
450 const Kleo::CryptoBackend::Protocol *smimeProtocol
451 = Kleo::CryptoBackendFactory::instance()->smime();
453 label->setEnabled(smimeProtocol);
454 mSMIMESigningKeyRequester->setEnabled(smimeProtocol);
456 // "S/MIME Encryption Key" requester and label:
457 ++row;
458 mSMIMEEncryptionKeyRequester = new KeySelectionCombo(KeySelectionCombo::EncryptionKey, GpgME::CMS, tab);
459 msg = i18n("<qt><p>The S/MIME certificate you choose here will be used "
460 "to encrypt messages to yourself and for the \"Attach My Certificate\" "
461 "feature in the composer.</p>"
462 "<p>You can leave this blank, but KMail will not be able "
463 "to encrypt copies of outgoing messages to you using S/MIME; "
464 "normal mail functions will not be affected.</p></qt>");
465 label = new QLabel(i18n("S/MIME encryption certificate:"), tab);
466 label->setBuddy(mSMIMEEncryptionKeyRequester);
467 mSMIMEEncryptionKeyRequester->setWhatsThis(msg);
468 label->setWhatsThis(msg);
470 glay->addWidget(label, row, 0);
471 glay->addWidget(mSMIMEEncryptionKeyRequester, row, 1);
473 label->setEnabled(smimeProtocol);
474 mSMIMEEncryptionKeyRequester->setEnabled(smimeProtocol);
476 // "Preferred Crypto Message Format" combobox and label:
477 ++row;
478 mPreferredCryptoMessageFormat = new KComboBox(tab);
479 mPreferredCryptoMessageFormat->setEditable(false);
480 QStringList l;
481 l << Kleo::cryptoMessageFormatToLabel(Kleo::AutoFormat)
482 << Kleo::cryptoMessageFormatToLabel(Kleo::InlineOpenPGPFormat)
483 << Kleo::cryptoMessageFormatToLabel(Kleo::OpenPGPMIMEFormat)
484 << Kleo::cryptoMessageFormatToLabel(Kleo::SMIMEFormat)
485 << Kleo::cryptoMessageFormatToLabel(Kleo::SMIMEOpaqueFormat);
486 mPreferredCryptoMessageFormat->addItems(l);
487 label = new QLabel(i18nc("preferred format of encrypted messages", "Preferred format:"), tab);
488 label->setBuddy(mPreferredCryptoMessageFormat);
490 glay->addWidget(label, row, 0);
491 glay->addWidget(mPreferredCryptoMessageFormat, row, 1);
493 ++row;
494 mAutoSign = new QCheckBox(i18n("Automatically sign messages"));
495 glay->addWidget(mAutoSign, row, 0);
497 ++row;
498 mAutoEncrypt = new QCheckBox(i18n("Automatically encrypt messages when possible"));
499 glay->addWidget(mAutoEncrypt, row, 0);
501 ++row;
502 glay->setRowStretch(row, 1);
505 // Tab Widget: Advanced
507 row = -1;
508 tab = new QWidget(mTabWidget);
509 QVBoxLayout *advancedMainLayout = new QVBoxLayout(tab);
510 mIdentityInvalidFolder = new IdentityInvalidFolder(tab);
511 advancedMainLayout->addWidget(mIdentityInvalidFolder);
512 mTabWidget->addTab(tab, i18nc("@title:tab Advanced identity settings.", "Advanced"));
513 glay = new QGridLayout;
514 advancedMainLayout->addLayout(glay);
515 // the last (empty) row takes all the remaining space
516 glay->setColumnStretch(1, 1);
518 // "Reply-To Address" line edit and label:
519 ++row;
520 mReplyToEdit = new KPIM::AddresseeLineEdit(tab, true);
521 mReplyToEdit->setClearButtonShown(true);
522 mReplyToEdit->setObjectName(QStringLiteral("mReplyToEdit"));
523 glay->addWidget(mReplyToEdit, row, 1);
524 label = new QLabel(i18n("&Reply-To address:"), tab);
525 label->setBuddy(mReplyToEdit);
526 glay->addWidget(label, row, 0);
527 msg = i18n("<qt><h3>Reply-To addresses</h3>"
528 "<p>This sets the <tt>Reply-to:</tt> header to contain a "
529 "different email address to the normal <tt>From:</tt> "
530 "address.</p>"
531 "<p>This can be useful when you have a group of people "
532 "working together in similar roles. For example, you "
533 "might want any emails sent to have your email in the "
534 "<tt>From:</tt> field, but any responses to go to "
535 "a group address.</p>"
536 "<p>If in doubt, leave this field blank.</p></qt>");
537 label->setWhatsThis(msg);
538 mReplyToEdit->setWhatsThis(msg);
540 // "CC addresses" line edit and label:
541 ++row;
542 mCcEdit = new KPIM::AddresseeLineEdit(tab, true);
543 mCcEdit->setClearButtonShown(true);
544 mCcEdit->setObjectName(QStringLiteral("mCcEdit"));
545 glay->addWidget(mCcEdit, row, 1);
546 label = new QLabel(i18n("&CC addresses:"), tab);
547 label->setBuddy(mCcEdit);
548 glay->addWidget(label, row, 0);
549 msg = i18n("<qt><h3>CC (Carbon Copy) addresses</h3>"
550 "<p>The addresses that you enter here will be added to each "
551 "outgoing mail that is sent with this identity.</p>"
552 "<p>This is commonly used to send a copy of each sent message to "
553 "another account of yours.</p>"
554 "<p>To specify more than one address, use commas to separate "
555 "the list of CC recipients.</p>"
556 "<p>If in doubt, leave this field blank.</p></qt>");
557 label->setWhatsThis(msg);
558 mCcEdit->setWhatsThis(msg);
560 // "BCC addresses" line edit and label:
561 ++row;
562 mBccEdit = new KPIM::AddresseeLineEdit(tab, true);
563 mBccEdit->setClearButtonShown(true);
564 mBccEdit->setObjectName(QStringLiteral("mBccEdit"));
565 glay->addWidget(mBccEdit, row, 1);
566 label = new QLabel(i18n("&BCC addresses:"), tab);
567 label->setBuddy(mBccEdit);
568 glay->addWidget(label, row, 0);
569 msg = i18n("<qt><h3>BCC (Blind Carbon Copy) addresses</h3>"
570 "<p>The addresses that you enter here will be added to each "
571 "outgoing mail that is sent with this identity. They will not "
572 "be visible to other recipients.</p>"
573 "<p>This is commonly used to send a copy of each sent message to "
574 "another account of yours.</p>"
575 "<p>To specify more than one address, use commas to separate "
576 "the list of BCC recipients.</p>"
577 "<p>If in doubt, leave this field blank.</p></qt>");
578 label->setWhatsThis(msg);
579 mBccEdit->setWhatsThis(msg);
581 // "Dictionary" combo box and label:
582 ++row;
583 mDictionaryCombo = new Sonnet::DictionaryComboBox(tab);
584 glay->addWidget(mDictionaryCombo, row, 1);
585 label = new QLabel(i18n("D&ictionary:"), tab);
586 label->setBuddy(mDictionaryCombo);
587 glay->addWidget(label, row, 0);
589 // "Sent-mail Folder" combo box and label:
590 ++row;
591 mFccFolderRequester = new IdentityFolderRequester(tab);
592 mFccFolderRequester->setShowOutbox(false);
593 glay->addWidget(mFccFolderRequester, row, 1);
594 mSentMailFolderCheck = new QCheckBox(i18n("Sent-mail &folder:"), tab);
595 glay->addWidget(mSentMailFolderCheck, row, 0);
596 connect(mSentMailFolderCheck, &QCheckBox::toggled, mFccFolderRequester, &MailCommon::FolderRequester::setEnabled);
598 // "Drafts Folder" combo box and label:
599 ++row;
600 mDraftsFolderRequester = new IdentityFolderRequester(tab);
601 mDraftsFolderRequester->setShowOutbox(false);
602 glay->addWidget(mDraftsFolderRequester, row, 1);
603 label = new QLabel(i18n("&Drafts folder:"), tab);
604 label->setBuddy(mDraftsFolderRequester);
605 glay->addWidget(label, row, 0);
607 // "Templates Folder" combo box and label:
608 ++row;
609 mTemplatesFolderRequester = new IdentityFolderRequester(tab);
610 mTemplatesFolderRequester->setShowOutbox(false);
611 glay->addWidget(mTemplatesFolderRequester, row, 1);
612 label = new QLabel(i18n("&Templates folder:"), tab);
613 label->setBuddy(mTemplatesFolderRequester);
614 glay->addWidget(label, row, 0);
616 // "Special transport" combobox and label:
617 ++row;
618 mTransportCheck = new QCheckBox(i18n("Outgoing Account:"), tab);
619 glay->addWidget(mTransportCheck, row, 0);
620 mTransportCombo = new TransportComboBox(tab);
621 mTransportCombo->setEnabled(false); // since !mTransportCheck->isChecked()
622 glay->addWidget(mTransportCombo, row, 1);
623 connect(mTransportCheck, &QCheckBox::toggled, mTransportCombo, &MailTransport::TransportComboBox::setEnabled);
625 ++row;
626 mAttachMyVCard = new QCheckBox(i18n("Attach my vCard to message"), tab);
627 glay->addWidget(mAttachMyVCard, row, 0);
628 mEditVCard = new QPushButton(i18n("Create..."), tab);
629 connect(mEditVCard, &QPushButton::clicked, this, &IdentityDialog::slotEditVcard);
630 glay->addWidget(mEditVCard, row, 1);
632 ++row;
633 mAutoCorrectionLanguage = new PimCommon::AutoCorrectionLanguage(tab);
634 glay->addWidget(mAutoCorrectionLanguage, row, 1);
635 label = new QLabel(i18n("Autocorrection language:"), tab);
636 label->setBuddy(mAutoCorrectionLanguage);
637 glay->addWidget(label, row, 0);
639 // "default domain" input field:
640 ++row;
641 QHBoxLayout *hbox = new QHBoxLayout;
642 mDefaultDomainEdit = new KLineEdit(tab);
643 mDefaultDomainEdit->setClearButtonShown(true);
644 hbox->addWidget(mDefaultDomainEdit);
645 QToolButton *restoreDefaultDomainName = new QToolButton;
646 restoreDefaultDomainName->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
647 restoreDefaultDomainName->setToolTip(i18n("Restore default domain name"));
648 hbox->addWidget(restoreDefaultDomainName);
649 connect(restoreDefaultDomainName, &QToolButton::clicked, this, &IdentityDialog::slotRefreshDefaultDomainName);
650 glay->addLayout(hbox, row, 1);
651 label = new QLabel(i18n("Defaul&t domain:"), tab);
652 label->setBuddy(mDefaultDomainEdit);
653 glay->addWidget(label, row, 0);
655 // and now: add QWhatsThis:
656 msg = i18n("<qt><p>The default domain is used to complete email "
657 "addresses that only consist of the user's name."
658 "</p></qt>");
659 label->setWhatsThis(msg);
660 mDefaultDomainEdit->setWhatsThis(msg);
662 ++row;
663 glay->setRowStretch(row, 1);
665 // the last row is a spacer
668 // Tab Widget: Templates
670 tab = new QWidget(mTabWidget);
671 vlay = new QVBoxLayout(tab);
673 QHBoxLayout *tlay = new QHBoxLayout();
674 vlay->addLayout(tlay);
676 mCustom = new QCheckBox(i18n("&Use custom message templates for this identity"), tab);
677 tlay->addWidget(mCustom, Qt::AlignLeft);
679 mWidget = new TemplateParser::TemplatesConfiguration(tab, QStringLiteral("identity-templates"));
680 mWidget->setEnabled(false);
682 // Move the help label outside of the templates configuration widget,
683 // so that the help can be read even if the widget is not enabled.
684 tlay->addStretch(9);
685 tlay->addWidget(mWidget->helpLabel(), Qt::AlignRight);
687 vlay->addWidget(mWidget);
689 QHBoxLayout *btns = new QHBoxLayout();
690 mCopyGlobal = new QPushButton(i18n("&Copy Global Templates"), tab);
691 mCopyGlobal->setEnabled(false);
692 btns->addWidget(mCopyGlobal);
693 vlay->addLayout(btns);
694 connect(mCustom, &QCheckBox::toggled, mWidget, &TemplateParser::TemplatesConfiguration::setEnabled);
695 connect(mCustom, &QCheckBox::toggled, mCopyGlobal, &QPushButton::setEnabled);
696 connect(mCopyGlobal, &QPushButton::clicked, this, &IdentityDialog::slotCopyGlobal);
697 mTabWidget->addTab(tab, i18n("Templates"));
700 // Tab Widget: Signature
702 mSignatureConfigurator = new KIdentityManagement::SignatureConfigurator(mTabWidget);
703 mTabWidget->addTab(mSignatureConfigurator, i18n("Signature"));
706 // Tab Widget: Picture
709 mXFaceConfigurator = new XFaceConfigurator(mTabWidget);
710 mTabWidget->addTab(mXFaceConfigurator, i18n("Picture"));
712 #ifndef KCM_KPIMIDENTITIES_STANDALONE
713 resize(KMailSettings::self()->identityDialogSize());
714 #endif
715 mNameEdit->setFocus();
717 connect(mTabWidget, &QTabWidget::currentChanged, this, &IdentityDialog::slotAboutToShow);
720 IdentityDialog::~IdentityDialog()
722 #ifndef KCM_KPIMIDENTITIES_STANDALONE
723 KMailSettings::self()->setIdentityDialogSize(size());
724 #endif
727 void IdentityDialog::slotHelp()
729 PimCommon::Util::invokeHelp(QStringLiteral("kmail/configure-identity.html"));
732 void IdentityDialog::slotAboutToShow(int index)
734 QWidget *w = mTabWidget->widget(index);
735 if (w == mCryptographyTab) {
736 // set the configured email address as initial query of the key
737 // requesters:
738 const QString name = mNameEdit->text().trimmed();
739 const QString email = mEmailEdit->text().trimmed();
741 mPGPEncryptionKeyRequester->setIdentity(name, email);
742 mPGPSigningKeyRequester->setIdentity(name, email);
743 mSMIMEEncryptionKeyRequester->setIdentity(name, email);
744 mSMIMESigningKeyRequester->setIdentity(name, email);
748 void IdentityDialog::slotCopyGlobal()
750 mWidget->loadFromGlobal();
753 void IdentityDialog::slotRefreshDefaultDomainName()
755 mDefaultDomainEdit->setText(QHostInfo::localHostName());
758 void IdentityDialog::slotAccepted()
760 const QStringList aliases = mAliasEdit->items();
761 foreach (const QString &alias, aliases) {
762 if (!KEmailAddress::isValidSimpleAddress(alias)) {
763 const QString errorMsg(KEmailAddress::simpleEmailAddressErrorMsg());
764 KMessageBox::sorry(this, errorMsg, i18n("Invalid Email Alias \"%1\"", alias));
765 return;
769 // Validate email addresses
770 const QString email = mEmailEdit->text().trimmed();
771 if (!KEmailAddress::isValidSimpleAddress(email)) {
772 const QString errorMsg(KEmailAddress::simpleEmailAddressErrorMsg());
773 KMessageBox::sorry(this, errorMsg, i18n("Invalid Email Address"));
774 return;
777 // Check if the 'Reply to' and 'BCC' recipients are valid
778 const QString recipients = mReplyToEdit->text().trimmed() + QLatin1String(", ") + mBccEdit->text().trimmed() + QLatin1String(", ") + mCcEdit->text().trimmed();
779 AddressValidationJob *job = new AddressValidationJob(recipients, this, this);
780 //Use default Value
781 job->setDefaultDomain(mDefaultDomainEdit->text());
782 job->setProperty("email", email);
783 connect(job, &AddressValidationJob::result, this, &IdentityDialog::slotDelayedButtonClicked);
784 job->start();
787 bool IdentityDialog::keyMatchesEmailAddress(const GpgME::Key &key, const QString &email_)
789 if (key.isNull()) {
790 return true;
792 const QString email = email_.trimmed().toLower();
793 const auto uids = key.userIDs();
794 for (const auto &uid : uids) {
795 QString em = QString::fromUtf8(uid.email() ? uid.email() : uid.id());
796 if (em.isEmpty()) {
797 continue;
799 if (em[0] == QLatin1Char('<')) {
800 em = em.mid(1, em.length() - 2);
802 if (em.toLower() == email) {
803 return true;
807 return false;
810 void IdentityDialog::slotDelayedButtonClicked(KJob *job)
812 const AddressValidationJob *validationJob = qobject_cast<AddressValidationJob *>(job);
814 // Abort if one of the recipient addresses is invalid
815 if (!validationJob->isValid()) {
816 return;
819 const QString email = validationJob->property("email").toString();
821 const GpgME::Key &pgpSigningKey = mPGPSigningKeyRequester->currentKey();
822 const GpgME::Key &pgpEncryptionKey = mPGPEncryptionKeyRequester->currentKey();
823 const GpgME::Key &smimeSigningKey = mSMIMESigningKeyRequester->currentKey();
824 const GpgME::Key &smimeEncryptionKey = mSMIMEEncryptionKeyRequester->currentKey();
826 QString msg;
827 bool err = false;
828 if (!keyMatchesEmailAddress(pgpSigningKey, email)) {
829 msg = i18n("One of the configured OpenPGP signing keys does not contain "
830 "any user ID with the configured email address for this "
831 "identity (%1).\n"
832 "This might result in warning messages on the receiving side "
833 "when trying to verify signatures made with this configuration.", email);
834 err = true;
835 } else if (!keyMatchesEmailAddress(pgpEncryptionKey, email)) {
836 msg = i18n("One of the configured OpenPGP encryption keys does not contain "
837 "any user ID with the configured email address for this "
838 "identity (%1).", email);
839 err = true;
840 } else if (!keyMatchesEmailAddress(smimeSigningKey, email)) {
841 msg = i18n("One of the configured S/MIME signing certificates does not contain "
842 "the configured email address for this "
843 "identity (%1).\n"
844 "This might result in warning messages on the receiving side "
845 "when trying to verify signatures made with this configuration.", email);
846 err = true;
847 } else if (!keyMatchesEmailAddress(smimeEncryptionKey, email)) {
848 msg = i18n("One of the configured S/MIME encryption certificates does not contain "
849 "the configured email address for this "
850 "identity (%1).", email);
851 err = true;
854 if (err) {
855 if (KMessageBox::warningContinueCancel(this, msg,
856 i18n("Email Address Not Found in Key/Certificates"),
857 KStandardGuiItem::cont(),
858 KStandardGuiItem::cancel(),
859 QStringLiteral("warn_email_not_in_certificate"))
860 != KMessageBox::Continue) {
861 return;
865 if (mSignatureConfigurator->isSignatureEnabled() &&
866 mSignatureConfigurator->signatureType() == Signature::FromFile) {
867 QFileInfo file(mSignatureConfigurator->filePath());
868 if (!file.isReadable()) {
869 KMessageBox::error(this, i18n("The signature file is not valid"));
870 return;
874 accept();
877 bool IdentityDialog::checkFolderExists(const QString &folderID)
879 const Akonadi::Collection folder = CommonKernel->collectionFromId(folderID.toLongLong());
880 return folder.isValid();
883 void IdentityDialog::setIdentity(KIdentityManagement::Identity &ident)
886 setWindowTitle(i18n("Edit Identity \"%1\"", ident.identityName()));
888 // "General" tab:
889 mNameEdit->setText(ident.fullName());
890 mOrganizationEdit->setText(ident.organization());
891 mEmailEdit->setText(ident.primaryEmailAddress());
892 mAliasEdit->insertStringList(ident.emailAliases());
894 // "Cryptography" tab:
895 mPGPSigningKeyRequester->setDefaultKey(QLatin1String(ident.pgpSigningKey()));
896 mPGPEncryptionKeyRequester->setDefaultKey(QLatin1String(ident.pgpEncryptionKey()));
897 mSMIMESigningKeyRequester->setDefaultKey(QLatin1String(ident.smimeSigningKey()));
898 mSMIMEEncryptionKeyRequester->setDefaultKey(QLatin1String(ident.smimeEncryptionKey()));
900 mPreferredCryptoMessageFormat->setCurrentIndex(format2cb(
901 Kleo::stringToCryptoMessageFormat(ident.preferredCryptoMessageFormat())));
902 mAutoSign->setChecked(ident.pgpAutoSign());
903 mAutoEncrypt->setChecked(ident.pgpAutoEncrypt());
905 // "Advanced" tab:
906 mReplyToEdit->setText(ident.replyToAddr());
907 mBccEdit->setText(ident.bcc());
908 mCcEdit->setText(ident.cc());
909 const int transportId = ident.transport().isEmpty() ? -1 : ident.transport().toInt();
910 const Transport *transport = TransportManager::self()->transportById(transportId, true);
911 mTransportCheck->setChecked(transportId != -1);
912 mTransportCombo->setEnabled(transportId != -1);
913 if (transport) {
914 mTransportCombo->setCurrentTransport(transport->id());
916 mDictionaryCombo->setCurrentByDictionaryName(ident.dictionary());
918 mSentMailFolderCheck->setChecked(!ident.disabledFcc());
919 mFccFolderRequester->setEnabled(mSentMailFolderCheck->isChecked());
920 bool foundNoExistingFolder = false;
921 if (ident.fcc().isEmpty() ||
922 !checkFolderExists(ident.fcc())) {
923 foundNoExistingFolder = true;
924 mFccFolderRequester->setIsInvalidFolder();
925 mFccFolderRequester->setCollection(CommonKernel->sentCollectionFolder());
926 } else {
927 mFccFolderRequester->setCollection(Akonadi::Collection(ident.fcc().toLongLong()));
929 if (ident.drafts().isEmpty() ||
930 !checkFolderExists(ident.drafts())) {
931 foundNoExistingFolder = true;
932 mDraftsFolderRequester->setIsInvalidFolder();
933 mDraftsFolderRequester->setCollection(CommonKernel->draftsCollectionFolder());
934 } else {
935 mDraftsFolderRequester->setCollection(Akonadi::Collection(ident.drafts().toLongLong()));
938 if (ident.templates().isEmpty() ||
939 !checkFolderExists(ident.templates())) {
940 foundNoExistingFolder = true;
941 mTemplatesFolderRequester->setIsInvalidFolder();
942 mTemplatesFolderRequester->setCollection(CommonKernel->templatesCollectionFolder());
944 } else {
945 mTemplatesFolderRequester->setCollection(Akonadi::Collection(ident.templates().toLongLong()));
947 if (foundNoExistingFolder) {
948 mIdentityInvalidFolder->setErrorMessage(i18n("Some custom folder for identity does not exist (anymore); therefore, default folders will be used."));
950 mVcardFilename = ident.vCardFile();
952 mAutoCorrectionLanguage->setLanguage(ident.autocorrectionLanguage());
953 updateVcardButton();
954 if (mVcardFilename.isEmpty()) {
955 mVcardFilename = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + ident.identityName() + QLatin1String(".vcf");
956 QFileInfo fileInfo(mVcardFilename);
957 QDir().mkpath(fileInfo.absolutePath());
958 } else {
959 //Convert path.
960 const QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + ident.identityName() + QLatin1String(".vcf");
961 if (QFile(path).exists() && (mVcardFilename != path)) {
962 mVcardFilename = path;
965 mAttachMyVCard->setChecked(ident.attachVcard());
966 QString defaultDomainName = ident.defaultDomainName();
967 if (defaultDomainName.isEmpty()) {
968 defaultDomainName = QHostInfo::localHostName();
970 mDefaultDomainEdit->setText(defaultDomainName);
972 // "Templates" tab:
973 uint identity = ident.uoid();
974 QString iid = TemplateParser::TemplatesConfiguration::configIdString(identity);
975 TemplateParser::Templates t(iid);
976 mCustom->setChecked(t.useCustomTemplates());
977 mWidget->loadFromIdentity(identity);
979 // "Signature" tab:
980 mSignatureConfigurator->setImageLocation(ident);
981 mSignatureConfigurator->setSignature(ident.signature());
982 mXFaceConfigurator->setXFace(ident.xface());
983 mXFaceConfigurator->setXFaceEnabled(ident.isXFaceEnabled());
986 void IdentityDialog::updateIdentity(KIdentityManagement::Identity &ident)
988 // "General" tab:
989 ident.setFullName(mNameEdit->text());
990 ident.setOrganization(mOrganizationEdit->text());
991 QString email = mEmailEdit->text();
992 ident.setPrimaryEmailAddress(email);
993 ident.setEmailAliases(mAliasEdit->items());
994 // "Cryptography" tab:
995 ident.setPGPSigningKey(mPGPSigningKeyRequester->currentKey().primaryFingerprint());
996 ident.setPGPEncryptionKey(mPGPEncryptionKeyRequester->currentKey().primaryFingerprint());
997 ident.setSMIMESigningKey(mSMIMESigningKeyRequester->currentKey().primaryFingerprint());
998 ident.setSMIMEEncryptionKey(mSMIMEEncryptionKeyRequester->currentKey().primaryFingerprint());
999 ident.setPreferredCryptoMessageFormat(
1000 QLatin1String(Kleo::cryptoMessageFormatToString(cb2format(mPreferredCryptoMessageFormat->currentIndex()))));
1001 ident.setPgpAutoSign(mAutoSign->isChecked());
1002 ident.setPgpAutoEncrypt(mAutoEncrypt->isChecked());
1003 // "Advanced" tab:
1004 ident.setReplyToAddr(mReplyToEdit->text());
1005 ident.setBcc(mBccEdit->text());
1006 ident.setCc(mCcEdit->text());
1007 ident.setTransport(mTransportCheck->isChecked() ? QString::number(mTransportCombo->currentTransportId())
1008 : QString());
1009 ident.setDictionary(mDictionaryCombo->currentDictionaryName());
1010 ident.setDisabledFcc(!mSentMailFolderCheck->isChecked());
1011 Akonadi::Collection collection = mFccFolderRequester->collection();
1012 if (collection.isValid()) {
1013 ident.setFcc(QString::number(collection.id()));
1014 Akonadi::EntityDisplayAttribute *attribute = collection.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
1015 attribute->setIconName(QStringLiteral("mail-folder-sent"));
1016 new Akonadi::CollectionModifyJob(collection);
1017 } else {
1018 ident.setFcc(QString());
1021 collection = mDraftsFolderRequester->collection();
1022 if (collection.isValid()) {
1023 ident.setDrafts(QString::number(collection.id()));
1024 Akonadi::EntityDisplayAttribute *attribute = collection.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
1025 attribute->setIconName(QStringLiteral("document-properties"));
1026 new Akonadi::CollectionModifyJob(collection);
1027 } else {
1028 ident.setDrafts(QString());
1031 collection = mTemplatesFolderRequester->collection();
1032 if (collection.isValid()) {
1033 ident.setTemplates(QString::number(collection.id()));
1034 Akonadi::EntityDisplayAttribute *attribute = collection.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing);
1035 attribute->setIconName(QStringLiteral("document-new"));
1036 new Akonadi::CollectionModifyJob(collection);
1037 } else {
1038 ident.setTemplates(QString());
1040 ident.setVCardFile(mVcardFilename);
1041 ident.setAutocorrectionLanguage(mAutoCorrectionLanguage->language());
1042 updateVcardButton();
1043 ident.setAttachVcard(mAttachMyVCard->isChecked());
1044 //Add default ?
1045 ident.setDefaultDomainName(mDefaultDomainEdit->text());
1047 // "Templates" tab:
1048 uint identity = ident.uoid();
1049 QString iid = TemplateParser::TemplatesConfiguration::configIdString(identity);
1050 TemplateParser::Templates t(iid);
1051 qCDebug(KMAIL_LOG) << "use custom templates for identity" << identity << ":" << mCustom->isChecked();
1052 t.setUseCustomTemplates(mCustom->isChecked());
1053 t.save();
1054 mWidget->saveToIdentity(identity);
1056 // "Signature" tab:
1057 ident.setSignature(mSignatureConfigurator->signature());
1058 ident.setXFace(mXFaceConfigurator->xface());
1059 ident.setXFaceEnabled(mXFaceConfigurator->isXFaceEnabled());
1062 void IdentityDialog::slotEditVcard()
1064 if (QFile(mVcardFilename).exists()) {
1065 editVcard(mVcardFilename);
1066 } else {
1067 if (!MailCommon::Kernel::self()->kernelIsRegistered()) {
1068 return;
1070 KIdentityManagement::IdentityManager *manager = KernelIf->identityManager();
1072 QPointer<IdentityAddVcardDialog> dlg = new IdentityAddVcardDialog(manager->shadowIdentities(), this);
1073 if (dlg->exec()) {
1074 IdentityAddVcardDialog::DuplicateMode mode = dlg->duplicateMode();
1075 switch (mode) {
1076 case IdentityAddVcardDialog::Empty: {
1077 editVcard(mVcardFilename);
1078 break;
1080 case IdentityAddVcardDialog::ExistingEntry: {
1081 KIdentityManagement::Identity ident = manager->modifyIdentityForName(dlg->duplicateVcardFromIdentity());
1082 const QString filename = ident.vCardFile();
1083 if (!filename.isEmpty()) {
1084 QFile::copy(filename, mVcardFilename);
1086 editVcard(mVcardFilename);
1087 break;
1089 case IdentityAddVcardDialog::FromExistingVCard: {
1090 const QString filename = dlg->existingVCard().path();
1091 if (!filename.isEmpty()) {
1092 mVcardFilename = filename;
1094 editVcard(mVcardFilename);
1095 break;
1099 delete dlg;
1103 void IdentityDialog::editVcard(const QString &filename)
1105 QPointer<IdentityEditVcardDialog> dlg = new IdentityEditVcardDialog(filename, this);
1106 connect(dlg.data(), &IdentityEditVcardDialog::vcardRemoved, this, &IdentityDialog::slotVCardRemoved);
1107 if (dlg->exec()) {
1108 mVcardFilename = dlg->saveVcard();
1110 updateVcardButton();
1111 delete dlg;
1114 void IdentityDialog::slotVCardRemoved()
1116 mVcardFilename.clear();
1119 void IdentityDialog::updateVcardButton()
1121 if (mVcardFilename.isEmpty() || !QFile(mVcardFilename).exists()) {
1122 mEditVCard->setText(i18n("Create..."));
1123 } else {
1124 mEditVCard->setText(i18n("Edit..."));
1130 #include "identitydialog.moc"