File indexing completed on 2024-12-22 05:01:10
0001 /* 0002 identitydialog.cpp 0003 0004 This file is part of KMail, the KDE mail client. 0005 SPDX-FileCopyrightText: 2002 Marc Mutz <mutz@kde.org> 0006 SPDX-FileCopyrightText: 2014-2024 Laurent Montel <montel@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-only 0009 */ 0010 0011 #include "identitydialog.h" 0012 #include "identityaddvcarddialog.h" 0013 #include "identityeditvcarddialog.h" 0014 #include "identityfolderrequester.h" 0015 #include "identityinvalidfolder.h" 0016 0017 #include <QGpgME/Job> 0018 #include <QGpgME/Protocol> 0019 0020 #include <KIdentityManagementCore/IdentityManager> 0021 0022 // other KMail headers: 0023 #include "settings/kmailsettings.h" 0024 #include "xfaceconfigurator.h" 0025 #include <KEditListWidget> 0026 #include <MailCommon/FolderRequester> 0027 0028 #include <MailCommon/MailKernel> 0029 0030 #include "job/addressvalidationjob.h" 0031 #include <MessageComposer/Kleo_Util> 0032 #include <MessageComposer/MessageComposerSettings> 0033 #include <MessageCore/StringUtil> 0034 #include <Sonnet/DictionaryComboBox> 0035 #include <TemplateParser/TemplatesConfiguration> 0036 #include <templateparser/templatesconfiguration_kfg.h> 0037 // other kdepim headers: 0038 #include <KIdentityManagementCore/Identity> 0039 #include <KIdentityManagementWidgets/SignatureConfigurator> 0040 0041 #include <PimCommon/PimUtil> 0042 #include <TextAutoCorrectionWidgets/AutoCorrectionLanguage> 0043 0044 #include <KLineEditEventHandler> 0045 #include <PimCommonAkonadi/AddresseeLineEdit> 0046 // libkleopatra: 0047 #include <Libkleo/DefaultKeyFilter> 0048 #include <Libkleo/DefaultKeyGenerationJob> 0049 #include <Libkleo/KeySelectionCombo> 0050 #include <Libkleo/ProgressDialog> 0051 0052 // gpgme++ 0053 #include <gpgme++/keygenerationresult.h> 0054 0055 #include <KEmailAddress> 0056 #include <MailTransport/Transport> 0057 #include <MailTransport/TransportComboBox> 0058 #include <MailTransport/TransportManager> 0059 using MailTransport::TransportManager; 0060 0061 // other KDE headers: 0062 #include "kmail_debug.h" 0063 #include <KEmailValidator> 0064 #include <KLocalizedString> 0065 #include <KMessageBox> 0066 #include <QComboBox> 0067 #include <QIcon> 0068 #include <QPushButton> 0069 #include <QTabWidget> 0070 0071 // Qt headers: 0072 #include <QCheckBox> 0073 #include <QDir> 0074 #include <QFile> 0075 #include <QFileInfo> 0076 #include <QFormLayout> 0077 #include <QHostInfo> 0078 #include <QLabel> 0079 #include <QToolButton> 0080 #include <QVBoxLayout> 0081 0082 // other headers: 0083 #include <algorithm> 0084 #include <gpgme++/key.h> 0085 #include <iterator> 0086 0087 #include <Akonadi/CollectionFetchJob> 0088 #include <Akonadi/CollectionModifyJob> 0089 #include <Akonadi/EntityDisplayAttribute> 0090 #include <Akonadi/SpecialMailCollections> 0091 #include <QDialogButtonBox> 0092 #include <QGroupBox> 0093 #include <QStandardPaths> 0094 0095 using namespace MailTransport; 0096 using namespace MailCommon; 0097 0098 namespace KMail 0099 { 0100 class KeySelectionCombo : public Kleo::KeySelectionCombo 0101 { 0102 Q_OBJECT 0103 0104 public: 0105 enum KeyType { 0106 SigningKey, 0107 EncryptionKey, 0108 }; 0109 0110 explicit KeySelectionCombo(KeyType keyType, GpgME::Protocol protocol, QWidget *parent); 0111 ~KeySelectionCombo() override; 0112 0113 void setIdentity(const QString &name, const QString &email); 0114 0115 void init() override; 0116 0117 private: 0118 void onCustomItemSelected(const QVariant &type); 0119 QString mEmail; 0120 QString mName; 0121 const KeyType mKeyType; 0122 const GpgME::Protocol mProtocol; 0123 }; 0124 0125 class KeyGenerationJob : public QGpgME::Job 0126 { 0127 Q_OBJECT 0128 0129 public: 0130 explicit KeyGenerationJob(const QString &name, const QString &email, KeySelectionCombo *parent); 0131 ~KeyGenerationJob() override; 0132 0133 void slotCancel() override; 0134 void start(); 0135 0136 private: 0137 void keyGenerated(const GpgME::KeyGenerationResult &result); 0138 const QString mName; 0139 const QString mEmail; 0140 QGpgME::Job *mJob = nullptr; 0141 }; 0142 0143 KeyGenerationJob::KeyGenerationJob(const QString &name, const QString &email, KeySelectionCombo *parent) 0144 : QGpgME::Job(parent) 0145 , mName(name) 0146 , mEmail(email) 0147 { 0148 } 0149 0150 KeyGenerationJob::~KeyGenerationJob() = default; 0151 0152 void KeyGenerationJob::slotCancel() 0153 { 0154 if (mJob) { 0155 mJob->slotCancel(); 0156 } 0157 } 0158 0159 void KeyGenerationJob::start() 0160 { 0161 auto job = new Kleo::DefaultKeyGenerationJob(this); 0162 connect(job, &Kleo::DefaultKeyGenerationJob::result, this, &KeyGenerationJob::keyGenerated); 0163 job->start(mEmail, mName); 0164 mJob = job; 0165 } 0166 0167 void KeyGenerationJob::keyGenerated(const GpgME::KeyGenerationResult &result) 0168 { 0169 mJob = nullptr; 0170 if (result.error()) { 0171 KMessageBox::error(qobject_cast<QWidget *>(parent()), 0172 i18n("Error while generating new key pair: %1", QString::fromUtf8(result.error().asString())), 0173 i18n("Key Generation Error")); 0174 Q_EMIT done(); 0175 return; 0176 } 0177 0178 auto combo = qobject_cast<KeySelectionCombo *>(parent()); 0179 combo->setDefaultKey(QLatin1StringView(result.fingerprint())); 0180 connect(combo, &KeySelectionCombo::keyListingFinished, this, &KeyGenerationJob::done); 0181 combo->refreshKeys(); 0182 } 0183 0184 KeySelectionCombo::KeySelectionCombo(KeyType keyType, GpgME::Protocol protocol, QWidget *parent) 0185 : Kleo::KeySelectionCombo(parent) 0186 , mKeyType(keyType) 0187 , mProtocol(protocol) 0188 { 0189 } 0190 0191 KeySelectionCombo::~KeySelectionCombo() = default; 0192 0193 void KeySelectionCombo::setIdentity(const QString &name, const QString &email) 0194 { 0195 mName = name; 0196 mEmail = email; 0197 setIdFilter(email); 0198 } 0199 0200 void KeySelectionCombo::init() 0201 { 0202 Kleo::KeySelectionCombo::init(); 0203 0204 std::shared_ptr<Kleo::DefaultKeyFilter> keyFilter(new Kleo::DefaultKeyFilter); 0205 keyFilter->setIsOpenPGP(mProtocol == GpgME::OpenPGP ? Kleo::DefaultKeyFilter::Set : Kleo::DefaultKeyFilter::NotSet); 0206 if (mKeyType == SigningKey) { 0207 keyFilter->setCanSign(Kleo::DefaultKeyFilter::Set); 0208 keyFilter->setHasSecret(Kleo::DefaultKeyFilter::Set); 0209 } else { 0210 keyFilter->setCanEncrypt(Kleo::DefaultKeyFilter::Set); 0211 } 0212 setKeyFilter(keyFilter); 0213 prependCustomItem(QIcon(), i18n("No key"), QStringLiteral("no-key")); 0214 if (mProtocol == GpgME::OpenPGP) { 0215 appendCustomItem(QIcon::fromTheme(QStringLiteral("password-generate")), i18n("Generate a new key pair"), QStringLiteral("generate-new-key")); 0216 } 0217 0218 connect(this, &KeySelectionCombo::customItemSelected, this, &KeySelectionCombo::onCustomItemSelected); 0219 } 0220 0221 void KeySelectionCombo::onCustomItemSelected(const QVariant &type) 0222 { 0223 if (type == QLatin1StringView("no-key")) { 0224 return; 0225 } else if (type == QLatin1StringView("generate-new-key")) { 0226 auto job = new KeyGenerationJob(mName, mEmail, this); 0227 auto dlg = new Kleo::ProgressDialog(job, i18n("Generating new key pair..."), parentWidget()); 0228 dlg->setModal(true); 0229 setEnabled(false); 0230 connect(job, &KeyGenerationJob::done, this, [this]() { 0231 setEnabled(true); 0232 }); 0233 job->start(); 0234 } 0235 } 0236 0237 IdentityDialog::IdentityDialog(QWidget *parent) 0238 : QDialog(parent) 0239 { 0240 setWindowTitle(i18nc("@title:window", "Edit Identity")); 0241 auto mainLayout = new QVBoxLayout(this); 0242 0243 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, this); 0244 connect(buttonBox->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &IdentityDialog::slotHelp); 0245 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); 0246 okButton->setDefault(true); 0247 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0248 connect(buttonBox, &QDialogButtonBox::accepted, this, &IdentityDialog::slotAccepted); 0249 connect(buttonBox, &QDialogButtonBox::rejected, this, &IdentityDialog::reject); 0250 0251 // 0252 // Tab Widget: General 0253 // 0254 auto page = new QWidget(this); 0255 mainLayout->addWidget(page); 0256 mainLayout->addWidget(buttonBox); 0257 auto vlay = new QVBoxLayout(page); 0258 vlay->setContentsMargins({}); 0259 mTabWidget = new QTabWidget(page); 0260 mTabWidget->setObjectName(QLatin1StringView("config-identity-tab")); 0261 vlay->addWidget(mTabWidget); 0262 0263 auto tab = new QWidget(mTabWidget); 0264 mTabWidget->addTab(tab, i18nc("@title:tab General identity settings.", "General")); 0265 0266 auto formLayout = new QFormLayout(tab); 0267 0268 // "Name" line edit and label: 0269 mNameEdit = new QLineEdit(tab); 0270 KLineEditEventHandler::catchReturnKey(mNameEdit); 0271 auto label = new QLabel(i18n("&Your name:"), tab); 0272 formLayout->addRow(label, mNameEdit); 0273 label->setBuddy(mNameEdit); 0274 0275 QString msg = i18n( 0276 "<qt><h3>Your name</h3>" 0277 "<p>This field should contain your name as you would like " 0278 "it to appear in the email header that is sent out;</p>" 0279 "<p>if you leave this blank your real name will not " 0280 "appear, only the email address.</p></qt>"); 0281 label->setWhatsThis(msg); 0282 mNameEdit->setWhatsThis(msg); 0283 0284 // "Organization" line edit and label: 0285 mOrganizationEdit = new QLineEdit(tab); 0286 KLineEditEventHandler::catchReturnKey(mOrganizationEdit); 0287 label = new QLabel(i18n("Organi&zation:"), tab); 0288 formLayout->addRow(label, mOrganizationEdit); 0289 label->setBuddy(mOrganizationEdit); 0290 0291 msg = i18n( 0292 "<qt><h3>Organization</h3>" 0293 "<p>This field should have the name of your organization " 0294 "if you would like it to be shown in the email header that " 0295 "is sent out.</p>" 0296 "<p>It is safe (and normal) to leave this blank.</p></qt>"); 0297 label->setWhatsThis(msg); 0298 mOrganizationEdit->setWhatsThis(msg); 0299 0300 // "Email Address" line edit and label: 0301 // (row 3: spacer) 0302 mEmailEdit = new QLineEdit(tab); 0303 KLineEditEventHandler::catchReturnKey(mEmailEdit); 0304 label = new QLabel(i18n("&Email address:"), tab); 0305 formLayout->addRow(label, mEmailEdit); 0306 label->setBuddy(mEmailEdit); 0307 0308 msg = i18n( 0309 "<qt><h3>Email address</h3>" 0310 "<p>This field should have your full email address.</p>" 0311 "<p>This address is the primary one, used for all outgoing mail. " 0312 "If you have more than one address, either create a new identity, " 0313 "or add additional alias addresses in the field below.</p>" 0314 "<p>If you leave this blank, or get it wrong, people " 0315 "will have trouble replying to you.</p></qt>"); 0316 label->setWhatsThis(msg); 0317 mEmailEdit->setWhatsThis(msg); 0318 0319 auto emailValidator = new KEmailValidator(this); 0320 mEmailEdit->setValidator(emailValidator); 0321 0322 // "Email Aliases" string text edit and label: 0323 mAliasEdit = new KEditListWidget(tab); 0324 0325 auto emailValidator1 = new KEmailValidator(this); 0326 mAliasEdit->lineEdit()->setValidator(emailValidator1); 0327 0328 label = new QLabel(i18n("Email a&liases:"), tab); 0329 formLayout->addRow(label, mAliasEdit); 0330 label->setBuddy(mAliasEdit); 0331 0332 msg = i18n( 0333 "<qt><h3>Email aliases</h3>" 0334 "<p>This field contains alias addresses that should also " 0335 "be considered as belonging to this identity (as opposed " 0336 "to representing a different identity).</p>" 0337 "<p>Example:</p>" 0338 "<table>" 0339 "<tr><th>Primary address:</th><td>first.last@example.org</td></tr>" 0340 "<tr><th>Aliases:</th><td>first@example.org<br>last@example.org</td></tr>" 0341 "</table>" 0342 "<p>Type one alias address per line.</p></qt>"); 0343 label->setToolTip(msg); 0344 mAliasEdit->setWhatsThis(msg); 0345 0346 // 0347 // Tab Widget: Cryptography 0348 // 0349 mCryptographyTab = new QWidget(mTabWidget); 0350 mTabWidget->addTab(mCryptographyTab, i18n("Cryptography")); 0351 formLayout = new QFormLayout(mCryptographyTab); 0352 0353 // "OpenPGP Signature Key" requester and label: 0354 mPGPSigningKeyRequester = new KeySelectionCombo(KeySelectionCombo::SigningKey, GpgME::OpenPGP, mCryptographyTab); 0355 msg = i18n( 0356 "<qt><p>The OpenPGP key you choose here will be used " 0357 "to digitally sign messages. You can also use GnuPG keys.</p>" 0358 "<p>You can leave this blank, but KMail will not be able " 0359 "to digitally sign emails using OpenPGP; " 0360 "normal mail functions will not be affected.</p>" 0361 "<p>You can find out more about keys at <a>https://www.gnupg.org</a></p></qt>"); 0362 label = new QLabel(i18n("OpenPGP signing key:"), mCryptographyTab); 0363 label->setBuddy(mPGPSigningKeyRequester); 0364 mPGPSigningKeyRequester->setWhatsThis(msg); 0365 label->setWhatsThis(msg); 0366 0367 auto vbox = new QVBoxLayout; 0368 mPGPSameKey = new QCheckBox(i18n("Use same key for encryption and signing")); 0369 vbox->addWidget(mPGPSigningKeyRequester); 0370 vbox->addWidget(mPGPSameKey); 0371 formLayout->addRow(label, vbox); 0372 0373 connect(mPGPSameKey, &QCheckBox::toggled, this, [this, formLayout, vbox](bool checked) { 0374 mPGPEncryptionKeyRequester->setVisible(!checked); 0375 formLayout->labelForField(mPGPEncryptionKeyRequester)->setVisible(!checked); 0376 const auto label = qobject_cast<QLabel *>(formLayout->labelForField(vbox)); 0377 if (checked) { 0378 label->setText(i18n("OpenPGP key:")); 0379 const auto key = mPGPSigningKeyRequester->currentKey(); 0380 if (!key.isBad()) { 0381 mPGPEncryptionKeyRequester->setCurrentKey(key); 0382 } else if (mPGPSigningKeyRequester->currentData() == QLatin1StringView("no-key")) { 0383 mPGPEncryptionKeyRequester->setCurrentIndex(mPGPSigningKeyRequester->currentIndex()); 0384 } 0385 } else { 0386 label->setText(i18n("OpenPGP signing key:")); 0387 } 0388 }); 0389 connect(mPGPSigningKeyRequester, &KeySelectionCombo::currentKeyChanged, this, [&](const GpgME::Key &key) { 0390 if (mPGPSameKey->isChecked()) { 0391 mPGPEncryptionKeyRequester->setCurrentKey(key); 0392 } 0393 }); 0394 connect(mPGPSigningKeyRequester, &KeySelectionCombo::customItemSelected, this, [&](const QVariant &type) { 0395 if (mPGPSameKey->isChecked() && type == QLatin1StringView("no-key")) { 0396 mPGPEncryptionKeyRequester->setCurrentIndex(mPGPSigningKeyRequester->currentIndex()); 0397 } 0398 }); 0399 0400 // "OpenPGP Encryption Key" requester and label: 0401 mPGPEncryptionKeyRequester = new KeySelectionCombo(KeySelectionCombo::EncryptionKey, GpgME::OpenPGP, mCryptographyTab); 0402 msg = i18n( 0403 "<qt><p>The OpenPGP key you choose here will be used " 0404 "to encrypt messages to yourself and for the \"Attach My Public Key\" " 0405 "feature in the composer. You can also use GnuPG keys.</p>" 0406 "<p>You can leave this blank, but KMail will not be able " 0407 "to encrypt copies of outgoing messages to you using OpenPGP; " 0408 "normal mail functions will not be affected.</p>" 0409 "<p>You can find out more about keys at <a>https://www.gnupg.org</a></p></qt>"); 0410 label = new QLabel(i18n("OpenPGP encryption key:"), mCryptographyTab); 0411 label->setBuddy(mPGPEncryptionKeyRequester); 0412 label->setWhatsThis(msg); 0413 mPGPEncryptionKeyRequester->setWhatsThis(msg); 0414 0415 formLayout->addRow(label, mPGPEncryptionKeyRequester); 0416 0417 // "S/MIME Signature Key" requester and label: 0418 mSMIMESigningKeyRequester = new KeySelectionCombo(KeySelectionCombo::SigningKey, GpgME::CMS, mCryptographyTab); 0419 msg = i18n( 0420 "<qt><p>The S/MIME (X.509) certificate you choose here will be used " 0421 "to digitally sign messages.</p>" 0422 "<p>You can leave this blank, but KMail will not be able " 0423 "to digitally sign emails using S/MIME; " 0424 "normal mail functions will not be affected.</p></qt>"); 0425 label = new QLabel(i18n("S/MIME signing certificate:"), mCryptographyTab); 0426 label->setBuddy(mSMIMESigningKeyRequester); 0427 mSMIMESigningKeyRequester->setWhatsThis(msg); 0428 label->setWhatsThis(msg); 0429 formLayout->addRow(label, mSMIMESigningKeyRequester); 0430 0431 const QGpgME::Protocol *smimeProtocol = QGpgME::smime(); 0432 0433 label->setEnabled(smimeProtocol); 0434 mSMIMESigningKeyRequester->setEnabled(smimeProtocol); 0435 0436 // "S/MIME Encryption Key" requester and label: 0437 mSMIMEEncryptionKeyRequester = new KeySelectionCombo(KeySelectionCombo::EncryptionKey, GpgME::CMS, mCryptographyTab); 0438 msg = i18n( 0439 "<qt><p>The S/MIME certificate you choose here will be used " 0440 "to encrypt messages to yourself and for the \"Attach My Certificate\" " 0441 "feature in the composer.</p>" 0442 "<p>You can leave this blank, but KMail will not be able " 0443 "to encrypt copies of outgoing messages to you using S/MIME; " 0444 "normal mail functions will not be affected.</p></qt>"); 0445 label = new QLabel(i18n("S/MIME encryption certificate:"), mCryptographyTab); 0446 label->setBuddy(mSMIMEEncryptionKeyRequester); 0447 mSMIMEEncryptionKeyRequester->setWhatsThis(msg); 0448 label->setWhatsThis(msg); 0449 0450 formLayout->addRow(label, mSMIMEEncryptionKeyRequester); 0451 0452 label->setEnabled(smimeProtocol); 0453 mSMIMEEncryptionKeyRequester->setEnabled(smimeProtocol); 0454 0455 // "Preferred Crypto Message Format" combobox and label: 0456 mPreferredCryptoMessageFormat = new QComboBox(mCryptographyTab); 0457 QStringList l; 0458 l << Kleo::cryptoMessageFormatToLabel(Kleo::AutoFormat) << Kleo::cryptoMessageFormatToLabel(Kleo::InlineOpenPGPFormat) 0459 << Kleo::cryptoMessageFormatToLabel(Kleo::OpenPGPMIMEFormat) << Kleo::cryptoMessageFormatToLabel(Kleo::SMIMEFormat) 0460 << Kleo::cryptoMessageFormatToLabel(Kleo::SMIMEOpaqueFormat); 0461 mPreferredCryptoMessageFormat->addItems(l); 0462 label = new QLabel(i18nc("preferred format of encrypted messages", "Preferred format:"), mCryptographyTab); 0463 label->setBuddy(mPreferredCryptoMessageFormat); 0464 0465 formLayout->addRow(label, mPreferredCryptoMessageFormat); 0466 0467 mAutocrypt = new QGroupBox(i18n("Enable Autocrypt")); 0468 mAutocrypt->setCheckable(true); 0469 mAutocrypt->setChecked(true); 0470 0471 label = new QLabel(i18n("Autocrypt:"), tab); 0472 formLayout->addRow(label, mAutocrypt); 0473 0474 vlay = new QVBoxLayout(mAutocrypt); 0475 0476 mAutocryptPrefer = new QCheckBox(i18n("Let others know you prefer encryption")); 0477 vlay->addWidget(mAutocryptPrefer); 0478 0479 mOverrideDefault = new QGroupBox(i18n("Overwrite global settings for security defaults")); 0480 mOverrideDefault->setCheckable(true); 0481 mOverrideDefault->setChecked(false); 0482 label = new QLabel(i18n("Overwrite defaults:"), tab); 0483 formLayout->addRow(label, mOverrideDefault); 0484 0485 vlay = new QVBoxLayout(mOverrideDefault); 0486 0487 mAutoSign = new QCheckBox(i18n("Sign messages")); 0488 vlay->addWidget(mAutoSign); 0489 0490 mAutoEncrypt = new QCheckBox(i18n("Encrypt messages when possible")); 0491 vlay->addWidget(mAutoEncrypt); 0492 0493 mWarnNotSign = new QCheckBox(i18n("Warn when trying to send unsigned messages")); 0494 vlay->addWidget(mWarnNotSign); 0495 0496 mWarnNotEncrypt = new QCheckBox(i18n("Warn when trying to send unencrypted messages")); 0497 vlay->addWidget(mWarnNotEncrypt); 0498 0499 // 0500 // Tab Widget: Advanced 0501 // 0502 tab = new QWidget(mTabWidget); 0503 auto advancedMainLayout = new QVBoxLayout(tab); 0504 mIdentityInvalidFolder = new IdentityInvalidFolder(tab); 0505 advancedMainLayout->addWidget(mIdentityInvalidFolder); 0506 mTabWidget->addTab(tab, i18nc("@title:tab Advanced identity settings.", "Advanced")); 0507 formLayout = new QFormLayout; 0508 advancedMainLayout->addLayout(formLayout); 0509 0510 // "Reply-To Address" line edit and label: 0511 mReplyToEdit = new PimCommon::AddresseeLineEdit(tab, true); 0512 mReplyToEdit->setClearButtonEnabled(true); 0513 mReplyToEdit->setObjectName(QLatin1StringView("mReplyToEdit")); 0514 label = new QLabel(i18n("&Reply-To address:"), tab); 0515 label->setBuddy(mReplyToEdit); 0516 formLayout->addRow(label, mReplyToEdit); 0517 msg = i18n( 0518 "<qt><h3>Reply-To addresses</h3>" 0519 "<p>This sets the <tt>Reply-to:</tt> header to contain a " 0520 "different email address to the normal <tt>From:</tt> " 0521 "address.</p>" 0522 "<p>This can be useful when you have a group of people " 0523 "working together in similar roles. For example, you " 0524 "might want any emails sent to have your email in the " 0525 "<tt>From:</tt> field, but any responses to go to " 0526 "a group address.</p>" 0527 "<p>If in doubt, leave this field blank.</p></qt>"); 0528 label->setWhatsThis(msg); 0529 mReplyToEdit->setWhatsThis(msg); 0530 KLineEditEventHandler::catchReturnKey(mReplyToEdit); 0531 0532 // "CC addresses" line edit and label: 0533 mCcEdit = new PimCommon::AddresseeLineEdit(tab, true); 0534 mCcEdit->setClearButtonEnabled(true); 0535 mCcEdit->setObjectName(QLatin1StringView("mCcEdit")); 0536 label = new QLabel(i18n("&CC addresses:"), tab); 0537 label->setBuddy(mCcEdit); 0538 formLayout->addRow(label, mCcEdit); 0539 KLineEditEventHandler::catchReturnKey(mCcEdit); 0540 0541 msg = i18n( 0542 "<qt><h3>CC (Carbon Copy) addresses</h3>" 0543 "<p>The addresses that you enter here will be added to each " 0544 "outgoing mail that is sent with this identity.</p>" 0545 "<p>This is commonly used to send a copy of each sent message to " 0546 "another account of yours.</p>" 0547 "<p>To specify more than one address, use commas to separate " 0548 "the list of CC recipients.</p>" 0549 "<p>If in doubt, leave this field blank.</p></qt>"); 0550 label->setWhatsThis(msg); 0551 mCcEdit->setWhatsThis(msg); 0552 0553 // "BCC addresses" line edit and label: 0554 mBccEdit = new PimCommon::AddresseeLineEdit(tab, true); 0555 mBccEdit->setClearButtonEnabled(true); 0556 mBccEdit->setObjectName(QLatin1StringView("mBccEdit")); 0557 KLineEditEventHandler::catchReturnKey(mBccEdit); 0558 label = new QLabel(i18n("&BCC addresses:"), tab); 0559 label->setBuddy(mBccEdit); 0560 formLayout->addRow(label, mBccEdit); 0561 msg = i18n( 0562 "<qt><h3>BCC (Blind Carbon Copy) addresses</h3>" 0563 "<p>The addresses that you enter here will be added to each " 0564 "outgoing mail that is sent with this identity. They will not " 0565 "be visible to other recipients.</p>" 0566 "<p>This is commonly used to send a copy of each sent message to " 0567 "another account of yours.</p>" 0568 "<p>To specify more than one address, use commas to separate " 0569 "the list of BCC recipients.</p>" 0570 "<p>If in doubt, leave this field blank.</p></qt>"); 0571 label->setWhatsThis(msg); 0572 mBccEdit->setWhatsThis(msg); 0573 0574 // "Dictionary" combo box and label: 0575 mDictionaryCombo = new Sonnet::DictionaryComboBox(tab); 0576 label = new QLabel(i18n("D&ictionary:"), tab); 0577 label->setBuddy(mDictionaryCombo); 0578 formLayout->addRow(label, mDictionaryCombo); 0579 0580 // "Sent-mail Folder" combo box and label: 0581 mFccFolderRequester = new IdentityFolderRequester(tab); 0582 mFccFolderRequester->setSelectFolderTitleDialog(i18n("Select Send-mail Folder")); 0583 mFccFolderRequester->setShowOutbox(false); 0584 mSentMailFolderCheck = new QCheckBox(i18n("Sent-mail &folder:"), tab); 0585 connect(mSentMailFolderCheck, &QCheckBox::toggled, mFccFolderRequester, &MailCommon::FolderRequester::setEnabled); 0586 formLayout->addRow(mSentMailFolderCheck, mFccFolderRequester); 0587 0588 // "Drafts Folder" combo box and label: 0589 mDraftsFolderRequester = new IdentityFolderRequester(tab); 0590 mDraftsFolderRequester->setSelectFolderTitleDialog(i18n("Select Draft Folder")); 0591 mDraftsFolderRequester->setShowOutbox(false); 0592 label = new QLabel(i18n("&Drafts folder:"), tab); 0593 label->setBuddy(mDraftsFolderRequester); 0594 formLayout->addRow(label, mDraftsFolderRequester); 0595 0596 // "Templates Folder" combo box and label: 0597 mTemplatesFolderRequester = new IdentityFolderRequester(tab); 0598 mTemplatesFolderRequester->setSelectFolderTitleDialog(i18n("Select Templates Folder")); 0599 mTemplatesFolderRequester->setShowOutbox(false); 0600 label = new QLabel(i18n("&Templates folder:"), tab); 0601 label->setBuddy(mTemplatesFolderRequester); 0602 formLayout->addRow(label, mTemplatesFolderRequester); 0603 0604 // "Special transport" combobox and label: 0605 mTransportCheck = new QCheckBox(i18n("Outgoing Account:"), tab); 0606 mTransportCombo = new TransportComboBox(tab); 0607 mTransportCombo->setEnabled(false); // since !mTransportCheck->isChecked() 0608 formLayout->addRow(mTransportCheck, mTransportCombo); 0609 0610 connect(mTransportCheck, &QCheckBox::toggled, mTransportCombo, &MailTransport::TransportComboBox::setEnabled); 0611 0612 mAttachMyVCard = new QCheckBox(i18n("Attach my vCard to message"), tab); 0613 mEditVCard = new QPushButton(i18n("Create..."), tab); 0614 connect(mEditVCard, &QPushButton::clicked, this, &IdentityDialog::slotEditVcard); 0615 formLayout->addRow(mAttachMyVCard, mEditVCard); 0616 mAutoCorrectionLanguage = new TextAutoCorrectionWidgets::AutoCorrectionLanguage(tab); 0617 label = new QLabel(i18n("Autocorrection language:"), tab); 0618 label->setBuddy(mAutoCorrectionLanguage); 0619 formLayout->addRow(label, mAutoCorrectionLanguage); 0620 0621 // "default domain" input field: 0622 auto hbox = new QHBoxLayout; 0623 mDefaultDomainEdit = new QLineEdit(tab); 0624 KLineEditEventHandler::catchReturnKey(mDefaultDomainEdit); 0625 mDefaultDomainEdit->setClearButtonEnabled(true); 0626 hbox->addWidget(mDefaultDomainEdit); 0627 auto restoreDefaultDomainName = new QToolButton; 0628 restoreDefaultDomainName->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); 0629 restoreDefaultDomainName->setToolTip(i18n("Restore default domain name")); 0630 hbox->addWidget(restoreDefaultDomainName); 0631 connect(restoreDefaultDomainName, &QToolButton::clicked, this, &IdentityDialog::slotRefreshDefaultDomainName); 0632 label = new QLabel(i18n("Defaul&t domain:"), tab); 0633 label->setBuddy(mDefaultDomainEdit); 0634 formLayout->addRow(label, mDefaultDomainEdit); 0635 0636 // and now: add QWhatsThis: 0637 msg = i18n( 0638 "<qt><p>The default domain is used to complete email " 0639 "addresses that only consist of the user's name." 0640 "</p></qt>"); 0641 label->setWhatsThis(msg); 0642 mDefaultDomainEdit->setWhatsThis(msg); 0643 0644 // the last row is a spacer 0645 0646 // 0647 // Tab Widget: Templates 0648 // 0649 tab = new QWidget(mTabWidget); 0650 vlay = new QVBoxLayout(tab); 0651 0652 auto tlay = new QHBoxLayout(); 0653 vlay->addLayout(tlay); 0654 0655 mCustom = new QCheckBox(i18n("&Use custom message templates for this identity"), tab); 0656 tlay->addWidget(mCustom, Qt::AlignLeft); 0657 0658 mWidget = new TemplateParser::TemplatesConfiguration(tab, QStringLiteral("identity-templates")); 0659 mWidget->setEnabled(false); 0660 0661 // Move the help label outside of the templates configuration widget, 0662 // so that the help can be read even if the widget is not enabled. 0663 tlay->addStretch(9); 0664 tlay->addWidget(mWidget->helpLabel(), Qt::AlignRight); 0665 0666 vlay->addWidget(mWidget); 0667 0668 auto btns = new QHBoxLayout(); 0669 mCopyGlobal = new QPushButton(i18n("&Copy Global Templates"), tab); 0670 mCopyGlobal->setEnabled(false); 0671 btns->addWidget(mCopyGlobal); 0672 vlay->addLayout(btns); 0673 connect(mCustom, &QCheckBox::toggled, mWidget, &TemplateParser::TemplatesConfiguration::setEnabled); 0674 connect(mCustom, &QCheckBox::toggled, mCopyGlobal, &QPushButton::setEnabled); 0675 connect(mCopyGlobal, &QPushButton::clicked, this, &IdentityDialog::slotCopyGlobal); 0676 mTabWidget->addTab(tab, i18n("Templates")); 0677 0678 // 0679 // Tab Widget: Signature 0680 // 0681 mSignatureConfigurator = new KIdentityManagementWidgets::SignatureConfigurator(mTabWidget); 0682 mTabWidget->addTab(mSignatureConfigurator, i18n("Signature")); 0683 0684 // 0685 // Tab Widget: Picture 0686 // 0687 0688 mXFaceConfigurator = new XFaceConfigurator(mTabWidget); 0689 mTabWidget->addTab(mXFaceConfigurator, i18n("Picture")); 0690 0691 resize(KMailSettings::self()->identityDialogSize()); 0692 mNameEdit->setFocus(); 0693 0694 connect(mTabWidget, &QTabWidget::currentChanged, this, &IdentityDialog::slotAboutToShow); 0695 } 0696 0697 IdentityDialog::~IdentityDialog() 0698 { 0699 KMailSettings::self()->setIdentityDialogSize(size()); 0700 } 0701 0702 void IdentityDialog::slotHelp() 0703 { 0704 PimCommon::Util::invokeHelp(QStringLiteral("kmail2/configure-identity.html")); 0705 } 0706 0707 void IdentityDialog::slotAboutToShow(int index) 0708 { 0709 QWidget *w = mTabWidget->widget(index); 0710 if (w == mCryptographyTab) { 0711 // set the configured email address as initial query of the key 0712 // requesters: 0713 const QString name = mNameEdit->text().trimmed(); 0714 const QString email = mEmailEdit->text().trimmed(); 0715 0716 mPGPEncryptionKeyRequester->setIdentity(name, email); 0717 mPGPSigningKeyRequester->setIdentity(name, email); 0718 mSMIMEEncryptionKeyRequester->setIdentity(name, email); 0719 mSMIMESigningKeyRequester->setIdentity(name, email); 0720 } 0721 } 0722 0723 void IdentityDialog::slotCopyGlobal() 0724 { 0725 mWidget->loadFromGlobal(); 0726 } 0727 0728 void IdentityDialog::slotRefreshDefaultDomainName() 0729 { 0730 mDefaultDomainEdit->setText(QHostInfo::localHostName()); 0731 } 0732 0733 void IdentityDialog::slotAccepted() 0734 { 0735 const QStringList aliases = mAliasEdit->items(); 0736 for (const QString &alias : aliases) { 0737 if (alias.trimmed().isEmpty()) { 0738 continue; 0739 } 0740 if (!KEmailAddress::isValidSimpleAddress(alias)) { 0741 const QString errorMsg(KEmailAddress::simpleEmailAddressErrorMsg()); 0742 KMessageBox::error(this, errorMsg, i18n("Invalid Email Alias \"%1\"", alias)); 0743 return; 0744 } 0745 } 0746 0747 // Validate email addresses 0748 const QString email = mEmailEdit->text().trimmed(); 0749 if (email.isEmpty()) { 0750 KMessageBox::error(this, i18n("You must provide an email for this identity."), i18nc("@title:window", "Empty Email Address")); 0751 return; 0752 } 0753 if (!KEmailAddress::isValidSimpleAddress(email)) { 0754 const QString errorMsg(KEmailAddress::simpleEmailAddressErrorMsg()); 0755 KMessageBox::error(this, errorMsg, i18n("Invalid Email Address")); 0756 return; 0757 } 0758 0759 // Check if the 'Reply to' and 'BCC' recipients are valid 0760 const QString recipients = 0761 mReplyToEdit->text().trimmed() + QLatin1StringView(", ") + mBccEdit->text().trimmed() + QLatin1StringView(", ") + mCcEdit->text().trimmed(); 0762 auto job = new AddressValidationJob(recipients, this, this); 0763 // Use default Value 0764 job->setDefaultDomain(mDefaultDomainEdit->text()); 0765 job->setProperty("email", email); 0766 connect(job, &AddressValidationJob::result, this, &IdentityDialog::slotDelayedButtonClicked); 0767 job->start(); 0768 } 0769 0770 bool IdentityDialog::keyMatchesEmailAddress(const GpgME::Key &key, const QString &email_) 0771 { 0772 if (key.isNull()) { 0773 return true; 0774 } 0775 const QString email = email_.trimmed().toLower(); 0776 const auto uids = key.userIDs(); 0777 for (const auto &uid : uids) { 0778 QString em = QString::fromUtf8(uid.email() ? uid.email() : uid.id()); 0779 if (em.isEmpty()) { 0780 continue; 0781 } 0782 if (em[0] == QLatin1Char('<')) { 0783 em = em.mid(1, em.length() - 2); 0784 } 0785 if (em.toLower() == email) { 0786 return true; 0787 } 0788 } 0789 0790 return false; 0791 } 0792 0793 void IdentityDialog::slotDelayedButtonClicked(KJob *job) 0794 { 0795 const AddressValidationJob *validationJob = qobject_cast<AddressValidationJob *>(job); 0796 0797 // Abort if one of the recipient addresses is invalid 0798 if (!validationJob->isValid()) { 0799 return; 0800 } 0801 0802 const QString email = validationJob->property("email").toString(); 0803 0804 const GpgME::Key &pgpSigningKey = mPGPSigningKeyRequester->currentKey(); 0805 const GpgME::Key &pgpEncryptionKey = mPGPEncryptionKeyRequester->currentKey(); 0806 const GpgME::Key &smimeSigningKey = mSMIMESigningKeyRequester->currentKey(); 0807 const GpgME::Key &smimeEncryptionKey = mSMIMEEncryptionKeyRequester->currentKey(); 0808 0809 QString msg; 0810 bool err = false; 0811 if (!keyMatchesEmailAddress(pgpSigningKey, email)) { 0812 msg = i18n( 0813 "One of the configured OpenPGP signing keys does not contain " 0814 "any user ID with the configured email address for this " 0815 "identity (%1).\n" 0816 "This might result in warning messages on the receiving side " 0817 "when trying to verify signatures made with this configuration.", 0818 email); 0819 err = true; 0820 } else if (!keyMatchesEmailAddress(pgpEncryptionKey, email)) { 0821 msg = i18n( 0822 "One of the configured OpenPGP encryption keys does not contain " 0823 "any user ID with the configured email address for this " 0824 "identity (%1).", 0825 email); 0826 err = true; 0827 } else if (!keyMatchesEmailAddress(smimeSigningKey, email)) { 0828 msg = i18n( 0829 "One of the configured S/MIME signing certificates does not contain " 0830 "the configured email address for this " 0831 "identity (%1).\n" 0832 "This might result in warning messages on the receiving side " 0833 "when trying to verify signatures made with this configuration.", 0834 email); 0835 err = true; 0836 } else if (!keyMatchesEmailAddress(smimeEncryptionKey, email)) { 0837 msg = i18n( 0838 "One of the configured S/MIME encryption certificates does not contain " 0839 "the configured email address for this " 0840 "identity (%1).", 0841 email); 0842 err = true; 0843 } 0844 0845 if (err) { 0846 if (KMessageBox::warningContinueCancel(this, 0847 msg, 0848 i18nc("@title:window", "Email Address Not Found in Key/Certificates"), 0849 KStandardGuiItem::cont(), 0850 KStandardGuiItem::cancel(), 0851 QStringLiteral("warn_email_not_in_certificate")) 0852 != KMessageBox::Continue) { 0853 return; 0854 } 0855 } 0856 0857 if (mSignatureConfigurator->isSignatureEnabled() && mSignatureConfigurator->signatureType() == Signature::FromFile) { 0858 QFileInfo file(mSignatureConfigurator->filePath()); 0859 if (!file.isReadable()) { 0860 KMessageBox::error(this, i18n("The signature file is not valid")); 0861 return; 0862 } 0863 } 0864 0865 accept(); 0866 } 0867 0868 bool IdentityDialog::checkFolderExists(const QString &folderID) 0869 { 0870 const Akonadi::Collection folder = CommonKernel->collectionFromId(folderID.toLongLong()); 0871 return folder.isValid(); 0872 } 0873 0874 void IdentityDialog::setIdentity(KIdentityManagementCore::Identity &ident) 0875 { 0876 setWindowTitle(i18nc("@title:window", "Edit Identity \"%1\"", ident.identityName())); 0877 0878 // "General" tab: 0879 mNameEdit->setText(ident.fullName()); 0880 mOrganizationEdit->setText(ident.organization()); 0881 mEmailEdit->setText(ident.primaryEmailAddress()); 0882 mAliasEdit->insertStringList(ident.emailAliases()); 0883 0884 // "Cryptography" tab: 0885 mPGPSigningKeyRequester->setDefaultKey(QLatin1StringView(ident.pgpSigningKey())); 0886 mPGPEncryptionKeyRequester->setDefaultKey(QLatin1StringView(ident.pgpEncryptionKey())); 0887 0888 mPGPSameKey->setChecked(ident.pgpSigningKey() == ident.pgpEncryptionKey()); 0889 0890 mSMIMESigningKeyRequester->setDefaultKey(QLatin1StringView(ident.smimeSigningKey())); 0891 mSMIMEEncryptionKeyRequester->setDefaultKey(QLatin1StringView(ident.smimeEncryptionKey())); 0892 0893 mPreferredCryptoMessageFormat->setCurrentIndex(format2cb(Kleo::stringToCryptoMessageFormat(ident.preferredCryptoMessageFormat()))); 0894 mAutocrypt->setChecked(ident.autocryptEnabled()); 0895 mAutocryptPrefer->setChecked(ident.autocryptPrefer()); 0896 mOverrideDefault->setChecked(ident.encryptionOverride()); 0897 if (!ident.encryptionOverride()) { 0898 mAutoSign->setChecked(ident.pgpAutoSign()); 0899 mAutoEncrypt->setChecked(ident.pgpAutoEncrypt()); 0900 mWarnNotSign->setChecked(ident.warnNotSign()); 0901 mWarnNotEncrypt->setChecked(ident.warnNotEncrypt()); 0902 } else { 0903 mAutoEncrypt->setChecked(MessageComposer::MessageComposerSettings::self()->cryptoAutoEncrypt()); 0904 mAutoSign->setChecked(MessageComposer::MessageComposerSettings::self()->cryptoAutoSign()); 0905 mWarnNotEncrypt->setChecked(MessageComposer::MessageComposerSettings::self()->cryptoWarningUnencrypted()); 0906 mWarnNotSign->setChecked(MessageComposer::MessageComposerSettings::self()->cryptoWarningUnsigned()); 0907 } 0908 0909 // "Advanced" tab: 0910 mReplyToEdit->setText(ident.replyToAddr()); 0911 mBccEdit->setText(ident.bcc()); 0912 mCcEdit->setText(ident.cc()); 0913 const int transportId = ident.transport().isEmpty() ? -1 : ident.transport().toInt(); 0914 const Transport *transport = TransportManager::self()->transportById(transportId, true); 0915 mTransportCheck->setChecked(transportId != -1); 0916 mTransportCombo->setEnabled(transportId != -1); 0917 if (transport) { 0918 mTransportCombo->setCurrentTransport(transport->id()); 0919 } 0920 mDictionaryCombo->setCurrentByDictionaryName(ident.dictionary()); 0921 0922 mSentMailFolderCheck->setChecked(!ident.disabledFcc()); 0923 mFccFolderRequester->setEnabled(mSentMailFolderCheck->isChecked()); 0924 bool foundNoExistingFolder = false; 0925 if (ident.fcc().isEmpty() || !checkFolderExists(ident.fcc())) { 0926 foundNoExistingFolder = true; 0927 mFccFolderRequester->setIsInvalidFolder(CommonKernel->sentCollectionFolder()); 0928 } else { 0929 mFccFolderRequester->setCollection(Akonadi::Collection(ident.fcc().toLongLong())); 0930 } 0931 if (ident.drafts().isEmpty() || !checkFolderExists(ident.drafts())) { 0932 foundNoExistingFolder = true; 0933 mDraftsFolderRequester->setIsInvalidFolder(CommonKernel->draftsCollectionFolder()); 0934 } else { 0935 mDraftsFolderRequester->setCollection(Akonadi::Collection(ident.drafts().toLongLong())); 0936 } 0937 0938 if (ident.templates().isEmpty() || !checkFolderExists(ident.templates())) { 0939 foundNoExistingFolder = true; 0940 mTemplatesFolderRequester->setIsInvalidFolder(CommonKernel->templatesCollectionFolder()); 0941 } else { 0942 mTemplatesFolderRequester->setCollection(Akonadi::Collection(ident.templates().toLongLong())); 0943 } 0944 if (foundNoExistingFolder) { 0945 mIdentityInvalidFolder->setErrorMessage(i18n("Some custom folder for identity does not exist (anymore); therefore, default folders will be used.")); 0946 } 0947 mVcardFilename = ident.vCardFile(); 0948 0949 mAutoCorrectionLanguage->setLanguage(ident.autocorrectionLanguage()); 0950 updateVcardButton(); 0951 if (mVcardFilename.isEmpty()) { 0952 mVcardFilename = 0953 QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1Char('/') + ident.identityName() + QLatin1StringView(".vcf"); 0954 QFileInfo fileInfo(mVcardFilename); 0955 QDir().mkpath(fileInfo.absolutePath()); 0956 } else { 0957 // Convert path. 0958 const QString path = 0959 QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1Char('/') + ident.identityName() + QLatin1StringView(".vcf"); 0960 if (QFileInfo::exists(path) && (mVcardFilename != path)) { 0961 mVcardFilename = path; 0962 } 0963 } 0964 mAttachMyVCard->setChecked(ident.attachVcard()); 0965 QString defaultDomainName = ident.defaultDomainName(); 0966 if (defaultDomainName.isEmpty()) { 0967 defaultDomainName = QHostInfo::localHostName(); 0968 } 0969 mDefaultDomainEdit->setText(defaultDomainName); 0970 0971 // "Templates" tab: 0972 uint identity = ident.uoid(); 0973 QString iid = TemplateParser::TemplatesConfiguration::configIdString(identity); 0974 TemplateParser::Templates t(iid); 0975 mCustom->setChecked(t.useCustomTemplates()); 0976 mWidget->loadFromIdentity(identity); 0977 0978 // "Signature" tab: 0979 mSignatureConfigurator->setImageLocation(ident); 0980 mSignatureConfigurator->setSignature(ident.signature()); 0981 mXFaceConfigurator->setXFace(ident.xface()); 0982 mXFaceConfigurator->setXFaceEnabled(ident.isXFaceEnabled()); 0983 mXFaceConfigurator->setFace(ident.face()); 0984 mXFaceConfigurator->setFaceEnabled(ident.isFaceEnabled()); 0985 } 0986 0987 void IdentityDialog::unregisterSpecialCollection(qint64 colId) 0988 { 0989 // ID is not enough to unregister a special collection, we need the 0990 // resource set as well. 0991 auto fetch = new Akonadi::CollectionFetchJob(Akonadi::Collection(colId), Akonadi::CollectionFetchJob::Base, this); 0992 connect(fetch, &Akonadi::CollectionFetchJob::collectionsReceived, this, [](const Akonadi::Collection::List &cols) { 0993 if (cols.count() != 1) { 0994 return; 0995 } 0996 Akonadi::SpecialMailCollections::self()->unregisterCollection(cols.first()); 0997 }); 0998 } 0999 1000 void IdentityDialog::updateIdentity(KIdentityManagementCore::Identity &ident) 1001 { 1002 // "General" tab: 1003 ident.setFullName(mNameEdit->text()); 1004 ident.setOrganization(mOrganizationEdit->text()); 1005 QString email = mEmailEdit->text().trimmed(); 1006 ident.setPrimaryEmailAddress(email); 1007 const QStringList aliases = mAliasEdit->items(); 1008 QStringList result; 1009 for (const QString &alias : aliases) { 1010 const QString aliasTrimmed = alias.trimmed(); 1011 if (aliasTrimmed.isEmpty()) { 1012 continue; 1013 } 1014 if (aliasTrimmed == email) { 1015 continue; 1016 } 1017 result.append(alias); 1018 } 1019 ident.setEmailAliases(result); 1020 // "Cryptography" tab: 1021 ident.setPGPSigningKey(mPGPSigningKeyRequester->currentKey().primaryFingerprint()); 1022 ident.setPGPEncryptionKey(mPGPEncryptionKeyRequester->currentKey().primaryFingerprint()); 1023 ident.setSMIMESigningKey(mSMIMESigningKeyRequester->currentKey().primaryFingerprint()); 1024 ident.setSMIMEEncryptionKey(mSMIMEEncryptionKeyRequester->currentKey().primaryFingerprint()); 1025 ident.setPreferredCryptoMessageFormat(QLatin1StringView(Kleo::cryptoMessageFormatToString(cb2format(mPreferredCryptoMessageFormat->currentIndex())))); 1026 ident.setAutocryptEnabled(mAutocrypt->isChecked()); 1027 ident.setAutocryptPrefer(mAutocryptPrefer->isChecked()); 1028 ident.setEncryptionOverride(mOverrideDefault->isChecked()); 1029 ident.setPgpAutoSign(mAutoSign->isChecked()); 1030 ident.setPgpAutoEncrypt(mAutoEncrypt->isChecked()); 1031 ident.setWarnNotEncrypt(mWarnNotEncrypt->isChecked()); 1032 ident.setWarnNotEncrypt(mWarnNotEncrypt->isChecked()); 1033 // "Advanced" tab: 1034 ident.setReplyToAddr(mReplyToEdit->text()); 1035 ident.setBcc(mBccEdit->text()); 1036 ident.setCc(mCcEdit->text()); 1037 ident.setTransport(mTransportCheck->isChecked() ? QString::number(mTransportCombo->currentTransportId()) : QString()); 1038 ident.setDictionary(mDictionaryCombo->currentDictionaryName()); 1039 ident.setDisabledFcc(!mSentMailFolderCheck->isChecked()); 1040 Akonadi::Collection collection = mFccFolderRequester->collection(); 1041 if (!ident.fcc().isEmpty()) { 1042 unregisterSpecialCollection(ident.fcc().toLongLong()); 1043 } 1044 if (collection.isValid()) { 1045 ident.setFcc(QString::number(collection.id())); 1046 auto attribute = collection.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing); 1047 attribute->setIconName(QStringLiteral("mail-folder-sent")); 1048 // It will also start a CollectionModifyJob 1049 Akonadi::SpecialMailCollections::self()->registerCollection(Akonadi::SpecialMailCollections::SentMail, collection); 1050 } else { 1051 ident.setFcc(QString()); 1052 } 1053 1054 collection = mDraftsFolderRequester->collection(); 1055 if (!ident.drafts().isEmpty()) { 1056 unregisterSpecialCollection(ident.drafts().toLongLong()); 1057 } 1058 if (collection.isValid()) { 1059 ident.setDrafts(QString::number(collection.id())); 1060 auto attribute = collection.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing); 1061 attribute->setIconName(QStringLiteral("document-properties")); 1062 // It will also start a CollectionModifyJob 1063 Akonadi::SpecialMailCollections::self()->registerCollection(Akonadi::SpecialMailCollections::Drafts, collection); 1064 } else { 1065 ident.setDrafts(QString()); 1066 } 1067 1068 collection = mTemplatesFolderRequester->collection(); 1069 if (ident.templates().isEmpty()) { 1070 unregisterSpecialCollection(ident.templates().toLongLong()); 1071 } 1072 if (collection.isValid()) { 1073 ident.setTemplates(QString::number(collection.id())); 1074 auto attribute = collection.attribute<Akonadi::EntityDisplayAttribute>(Akonadi::Collection::AddIfMissing); 1075 attribute->setIconName(QStringLiteral("document-new")); 1076 // It will also start a CollectionModifyJob 1077 Akonadi::SpecialMailCollections::self()->registerCollection(Akonadi::SpecialMailCollections::Templates, collection); 1078 new Akonadi::CollectionModifyJob(collection); 1079 } else { 1080 ident.setTemplates(QString()); 1081 } 1082 ident.setVCardFile(mVcardFilename); 1083 ident.setAutocorrectionLanguage(mAutoCorrectionLanguage->language()); 1084 updateVcardButton(); 1085 ident.setAttachVcard(mAttachMyVCard->isChecked()); 1086 // Add default ? 1087 ident.setDefaultDomainName(mDefaultDomainEdit->text()); 1088 1089 // "Templates" tab: 1090 uint identity = ident.uoid(); 1091 QString iid = TemplateParser::TemplatesConfiguration::configIdString(identity); 1092 TemplateParser::Templates t(iid); 1093 qCDebug(KMAIL_LOG) << "use custom templates for identity" << identity << ":" << mCustom->isChecked(); 1094 t.setUseCustomTemplates(mCustom->isChecked()); 1095 t.save(); 1096 mWidget->saveToIdentity(identity); 1097 1098 // "Signature" tab: 1099 ident.setSignature(mSignatureConfigurator->signature()); 1100 ident.setXFace(mXFaceConfigurator->xface()); 1101 ident.setXFaceEnabled(mXFaceConfigurator->isXFaceEnabled()); 1102 ident.setFace(mXFaceConfigurator->face()); 1103 ident.setFaceEnabled(mXFaceConfigurator->isFaceEnabled()); 1104 } 1105 1106 void IdentityDialog::slotEditVcard() 1107 { 1108 if (QFileInfo::exists(mVcardFilename)) { 1109 editVcard(mVcardFilename); 1110 } else { 1111 if (!MailCommon::Kernel::self()->kernelIsRegistered()) { 1112 return; 1113 } 1114 KIdentityManagementCore::IdentityManager *manager = KernelIf->identityManager(); 1115 1116 QPointer<IdentityAddVcardDialog> dlg = new IdentityAddVcardDialog(manager->shadowIdentities(), this); 1117 if (dlg->exec()) { 1118 IdentityAddVcardDialog::DuplicateMode mode = dlg->duplicateMode(); 1119 switch (mode) { 1120 case IdentityAddVcardDialog::Empty: 1121 editVcard(mVcardFilename); 1122 break; 1123 case IdentityAddVcardDialog::ExistingEntry: { 1124 KIdentityManagementCore::Identity ident = manager->modifyIdentityForName(dlg->duplicateVcardFromIdentity()); 1125 const QString filename = ident.vCardFile(); 1126 if (!filename.isEmpty()) { 1127 QFile::copy(filename, mVcardFilename); 1128 } 1129 editVcard(mVcardFilename); 1130 break; 1131 } 1132 case IdentityAddVcardDialog::FromExistingVCard: { 1133 const QString filename = dlg->existingVCard().path(); 1134 if (!filename.isEmpty()) { 1135 mVcardFilename = filename; 1136 } 1137 editVcard(mVcardFilename); 1138 break; 1139 } 1140 } 1141 } 1142 delete dlg; 1143 } 1144 } 1145 1146 void IdentityDialog::editVcard(const QString &filename) 1147 { 1148 QPointer<IdentityEditVcardDialog> dlg = new IdentityEditVcardDialog(filename, this); 1149 connect(dlg.data(), &IdentityEditVcardDialog::vcardRemoved, this, &IdentityDialog::slotVCardRemoved); 1150 if (dlg->exec()) { 1151 mVcardFilename = dlg->saveVcard(); 1152 } 1153 updateVcardButton(); 1154 delete dlg; 1155 } 1156 1157 void IdentityDialog::slotVCardRemoved() 1158 { 1159 mVcardFilename.clear(); 1160 } 1161 1162 void IdentityDialog::updateVcardButton() 1163 { 1164 if (mVcardFilename.isEmpty() || !QFileInfo::exists(mVcardFilename)) { 1165 mEditVCard->setText(i18n("Create...")); 1166 } else { 1167 mEditVCard->setText(i18n("Edit...")); 1168 } 1169 } 1170 } 1171 1172 #include "identitydialog.moc" 1173 1174 #include "moc_identitydialog.cpp"