8static const char configKeyDefaultIdentity[] =
"Default Identity";
10#include "identitymanager.h"
13#include <KEmailAddress>
15#include "kidentitymanagementcore_debug.h"
17#include <KConfigGroup>
18#include <KEMailSettings>
19#include <KLocalizedString>
20#include <KSharedConfig>
23#include <QDBusConnection>
25#include <QRandomGenerator>
27#include <QRegularExpression>
30#include "identitymanageradaptor.h"
32namespace KIdentityManagementCore
34static QString newDBusObjectName()
36 static int s_count = 0;
37 QString
name(QStringLiteral(
"/KIDENTITYMANAGER_IdentityManager"));
39 name += QLatin1Char(
'_');
50class IdentityManagerPrivate
53 IdentityManagerPrivate(KIdentityManagementCore::IdentityManager *);
54 ~IdentityManagerPrivate();
55 void writeConfig()
const;
56 void readConfig(KConfig *config);
57 void createDefaultIdentity();
58 [[nodiscard]] QStringList groupList(KConfig *config)
const;
59 void slotIdentitiesChanged(
const QString &
id);
60 KConfig *mConfig =
nullptr;
62 QList<Identity> mIdentities;
63 QList<Identity> shadowIdentities;
66 [[nodiscard]]
int newUoid();
68 bool mReadOnly =
true;
69 KIdentityManagementCore::IdentityManager *
const q;
72IdentityManagerPrivate::IdentityManagerPrivate(KIdentityManagementCore::IdentityManager *manager)
77void IdentityManagerPrivate::writeConfig()
const
82 mConfig->deleteGroup(*group);
85 IdentityManager::ConstIterator
end = mIdentities.constEnd();
86 for (IdentityManager::ConstIterator it = mIdentities.constBegin(); it != end; ++it, ++i) {
87 KConfigGroup cg(mConfig, QStringLiteral(
"Identity #%1").arg(i));
88 (*it).writeConfig(cg);
89 if ((*it).isDefault()) {
91 KConfigGroup general(mConfig, QStringLiteral(
"General"));
92 general.writeEntry(configKeyDefaultIdentity, (*it).uoid());
96 es.
setSetting(KEMailSettings::RealName, (*it).fullName());
97 es.
setSetting(KEMailSettings::EmailAddress, (*it).primaryEmailAddress());
98 es.
setSetting(KEMailSettings::Organization, (*it).organization());
99 es.
setSetting(KEMailSettings::ReplyToAddress, (*it).replyToAddr());
105void IdentityManagerPrivate::readConfig(
KConfig *config)
114 KConfigGroup general(config, QStringLiteral(
"General"));
115 uint defaultIdentity = general.readEntry(configKeyDefaultIdentity, 0);
116 bool haveDefault =
false;
121 identity.readConfig(configGroup);
123 if (!identity.isNull() && !identity.primaryEmailAddress().isEmpty()) {
124 if (!haveDefault && identity.uoid() == defaultIdentity) {
126 identity.setIsDefault(
true);
129 mIdentities << identity;
132 if (mIdentities.isEmpty()) {
133 mIdentities << Identity();
136 qCDebug(KIDENTITYMANAGEMENT_LOG) <<
"IdentityManager: There was no default identity."
137 <<
"Marking first one as default.";
138 mIdentities.first().setIsDefault(
true);
140 std::sort(mIdentities.begin(), mIdentities.end());
142 shadowIdentities = mIdentities;
145void IdentityManagerPrivate::createDefaultIdentity()
152 q->createDefaultIdentity(fullName, emailAddress);
158 emailAddress = emailSettings.
getSetting(KEMailSettings::EmailAddress);
161 q->newFromControlCenter(
i18nc(
"use default address from control center",
"Default"));
172 KConfigGroup general(mConfig, QStringLiteral(
"General"));
173 QString defaultdomain = general.readEntry(
"Default domain");
174 if (!defaultdomain.
isEmpty()) {
177 emailAddress.
clear();
186 QString name(
i18nc(
"Default name for new email accounts/identities.",
"Unnamed"));
193 name = idName.
mid(pos + 1, -1);
207 shadowIdentities << Identity(name, fullName, emailAddress);
210 shadowIdentities.
last().setIsDefault(
true);
211 shadowIdentities.
last().setUoid(newUoid());
213 mIdentities = shadowIdentities;
222int IdentityManagerPrivate::newUoid()
228 usedUOIDs.
reserve(mIdentities.count() + (q->hasPendingChanges() ? shadowIdentities.count() : 0));
231 usedUOIDs << (*it).uoid();
234 if (q->hasPendingChanges()) {
239 usedUOIDs << (*it).uoid();
251void IdentityManagerPrivate::slotIdentitiesChanged(
const QString &
id)
253 qCDebug(KIDENTITYMANAGEMENT_LOG) <<
" KIdentityManagementCore::IdentityManager::slotIdentitiesChanged :" << id;
255 if (
id != ourIdentifier) {
256 mConfig->reparseConfiguration();
257 Q_ASSERT(!q->hasPendingChanges());
259 Q_EMIT q->needToReloadIdentitySettings();
261 Q_EMIT q->identitiesWereChanged();
265Q_GLOBAL_STATIC(IdentityManager, s_self)
267IdentityManager *IdentityManager::self()
272IdentityManager::IdentityManager(
bool readonly,
QObject *parent,
const char *name)
274 , d(new IdentityManagerPrivate(this))
277 new IdentityManagerAdaptor(
this);
279 const QString dbusPath = newDBusObjectName();
281 const QString dbusInterface = QStringLiteral(
"org.kde.pim.IdentityManager");
285 d->mReadOnly = readonly;
286 d->mConfig =
new KConfig(QStringLiteral(
"emailidentities"));
287 if (!d->mConfig->isConfigWritable(
true)) {
288 qCWarning(KIDENTITYMANAGEMENT_LOG) <<
"impossible to write on this file";
290 d->readConfig(d->mConfig);
292 if (d->mIdentities.isEmpty()) {
293 qCDebug(KIDENTITYMANAGEMENT_LOG) <<
"IdentityManager: No identity found. Creating default.";
294 d->createDefaultIdentity();
300 bool needCommit =
false;
301 if (kmailConf->hasGroup(QStringLiteral(
"Composer"))) {
303 if (composerGroup.
hasKey(QStringLiteral(
"pgp-auto-sign"))) {
304 const bool pgpAutoSign = composerGroup.
readEntry(QStringLiteral(
"pgp-auto-sign"),
false);
307 it->setPgpAutoSign(pgpAutoSign);
309 composerGroup.
deleteEntry(QStringLiteral(
"pgp-auto-sign"));
310 composerGroup.
sync();
314 if (kmailConf->hasGroup(QStringLiteral(
"General"))) {
316 if (generalGroup.
hasKey(QStringLiteral(
"Default domain"))) {
317 QString defaultDomain = generalGroup.
readEntry(QStringLiteral(
"Default domain"));
323 it->setDefaultDomainName(defaultDomain);
325 generalGroup.
deleteEntry(QStringLiteral(
"Default domain"));
336 if (
KEMailSettings().getSetting(KEMailSettings::EmailAddress).isEmpty()) {
341IdentityManager::~IdentityManager()
343 if (hasPendingChanges()) {
344 qCWarning(KIDENTITYMANAGEMENT_LOG) <<
"IdentityManager: There were uncommitted changes!";
352 while (identities().contains(result)) {
354 "%1: name; %2: number appended to it to make it unique "
355 "among a list of names",
364bool IdentityManager::isUnique(
const QString &name)
const
366 return !identities().
contains(name);
369void IdentityManager::commit()
372 if (!hasPendingChanges() || d->mReadOnly) {
377 seenUOIDs.
reserve(d->mIdentities.count());
380 seenUOIDs << (*it).uoid();
386 const int index = seenUOIDs.
indexOf((*it).uoid());
388 uint uoid = seenUOIDs.
at(index);
389 const Identity &orig = identityForUoid(uoid);
392 qCDebug(KIDENTITYMANAGEMENT_LOG) <<
"emitting changed() for identity" << uoid;
394 Q_EMIT identityChanged(*it);
395 changedUOIDs << uoid;
400 qCDebug(KIDENTITYMANAGEMENT_LOG) <<
"emitting added() for identity" << (*it).uoid();
405 d->mIdentities = d->shadowIdentities;
411 qCDebug(KIDENTITYMANAGEMENT_LOG) <<
"emitting deleted() for identity" << (*it);
426 Q_EMIT identitiesWereChanged();
430 Q_EMIT identitiesChanged(ourIdentifier);
433void IdentityManager::rollback()
435 d->shadowIdentities = d->mIdentities;
438void IdentityManager::saveIdentity(
const Identity &ident)
440 const auto existing = std::find_if(modifyBegin(), modifyEnd(), [ident](
const auto &existingIdentity) {
441 return existingIdentity.uoid() == ident.uoid();
444 if (existing != modifyEnd()) {
445 d->shadowIdentities.replace(existing - modifyBegin(), ident);
447 d->shadowIdentities << ident;
453bool IdentityManager::hasPendingChanges()
const
455 return d->mIdentities != d->shadowIdentities;
461 result.
reserve(d->mIdentities.count());
464 result << (*it).identityName();
469QStringList IdentityManager::shadowIdentities()
const
472 result.
reserve(d->shadowIdentities.count());
475 result << (*it).identityName();
480void IdentityManager::sort()
482 std::sort(d->shadowIdentities.begin(), d->shadowIdentities.end());
485IdentityManager::ConstIterator IdentityManager::begin()
const
487 return d->mIdentities.constBegin();
490IdentityManager::ConstIterator IdentityManager::end()
const
492 return d->mIdentities.constEnd();
495IdentityManager::Iterator IdentityManager::modifyBegin()
497 return d->shadowIdentities.begin();
500IdentityManager::Iterator IdentityManager::modifyEnd()
502 return d->shadowIdentities.end();
505const Identity &IdentityManager::identityForUoid(uint uoid)
const
508 if ((*it).uoid() == uoid) {
512 return Identity::null();
515const Identity &IdentityManager::identityForUoidOrDefault(uint uoid)
const
517 const Identity &ident = identityForUoid(uoid);
518 if (ident.isNull()) {
519 return defaultIdentity();
525const Identity &IdentityManager::identityForAddress(
const QString &addresses)
const
528 for (
const QString &fullAddress : addressList) {
531 const Identity &identity = *it;
532 if (identity.matchesEmailAddress(addrSpec)) {
537 return Identity::null();
540bool IdentityManager::thatIsMe(
const QString &addressList)
const
542 return !identityForAddress(addressList).isNull();
545Identity &IdentityManager::modifyIdentityForName(
const QString &name)
547 for (
Iterator it = modifyBegin(); it != modifyEnd(); ++it) {
548 if ((*it).identityName() == name) {
553 qCWarning(KIDENTITYMANAGEMENT_LOG) <<
"IdentityManager::modifyIdentityForName() used as"
554 <<
"newFromScratch() replacement!" <<
Qt::endl
555 <<
" name == \"" <<
name <<
"\"";
556 return newFromScratch(name);
559Identity &IdentityManager::modifyIdentityForUoid(uint uoid)
561 for (
Iterator it = modifyBegin(); it != modifyEnd(); ++it) {
562 if ((*it).uoid() == uoid) {
567 qCWarning(KIDENTITYMANAGEMENT_LOG) <<
"IdentityManager::identityForUoid() used as"
568 <<
"newFromScratch() replacement!" <<
Qt::endl
569 <<
" uoid == \"" << uoid <<
"\"";
570 return newFromScratch(
i18n(
"Unnamed"));
573const Identity &IdentityManager::defaultIdentity()
const
576 if ((*it).isDefault()) {
581 if (d->mIdentities.isEmpty()) {
582 qCritical() <<
"IdentityManager: No default identity found!";
584 qCWarning(KIDENTITYMANAGEMENT_LOG) <<
"IdentityManager: No default identity found!";
589bool IdentityManager::setAsDefault(uint uoid)
595 if ((*it).uoid() == uoid) {
606 for (
Iterator it = modifyBegin(); it != modifyEnd(); ++it) {
607 (*it).setIsDefault((*it).uoid() == uoid);
615bool IdentityManager::removeIdentity(
const QString &name)
617 if (d->shadowIdentities.size() <= 1) {
621 for (
Iterator it = modifyBegin(); it != modifyEnd(); ++it) {
622 if ((*it).identityName() == name) {
623 bool removedWasDefault = (*it).isDefault();
624 d->shadowIdentities.erase(it);
625 if (removedWasDefault && !d->shadowIdentities.isEmpty()) {
626 d->shadowIdentities.first().setIsDefault(
true);
634bool IdentityManager::removeIdentityForced(
const QString &name)
636 for (
Iterator it = modifyBegin(); it != modifyEnd(); ++it) {
637 if ((*it).identityName() == name) {
638 bool removedWasDefault = (*it).isDefault();
639 d->shadowIdentities.erase(it);
640 if (removedWasDefault && !d->shadowIdentities.isEmpty()) {
641 d->shadowIdentities.first().setIsDefault(
true);
649Identity &IdentityManager::newFromScratch(
const QString &name)
651 return newFromExisting(Identity(name));
654Identity &IdentityManager::newFromControlCenter(
const QString &name)
659 return newFromExisting(Identity(name,
663 es.
getSetting(KEMailSettings::ReplyToAddress)));
666Identity &IdentityManager::newFromExisting(
const Identity &other,
const QString &name)
668 d->shadowIdentities << other;
669 Identity &result = d->shadowIdentities.
last();
670 result.setIsDefault(
false);
671 result.setUoid(d->newUoid());
673 result.setIdentityName(name);
681 for (ConstIterator it = begin(); it != end(); ++it) {
682 lst << (*it).primaryEmailAddress();
683 if (!(*it).emailAliases().isEmpty()) {
684 lst << (*it).emailAliases();
694void KIdentityManagementCore::IdentityManager::slotRollback()
699IdentityManagerPrivate::~IdentityManagerPrivate()
704#include "moc_identitymanager.cpp"
KConfigGroup group(const QString &group)
void deleteEntry(const char *key, WriteConfigFlags pFlags=Normal)
bool hasKey(const char *key) const
QString readEntry(const char *key, const char *aDefault=nullptr) const
QStringList groupList() const override
QString getSetting(KEMailSettings::Setting s) const
void setProfile(const QString &s)
void setSetting(KEMailSettings::Setting s, const QString &v)
QString defaultProfileName() const
QStringList allEmails() const
Returns the list of all email addresses (only name@host) from all identities.
virtual void createDefaultIdentity(QString &, QString &)
This is called when no identity has been defined, so we need to create a default one.
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QVariant property(UserProperty which) const
QString loginName() const
KCODECS_EXPORT QStringList splitAddressList(const QString &aStr)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QString fullName(const PartType &type)
char * toString(const EngineQuery &query)
QString name(StandardAction id)
const QList< QKeySequence > & begin()
const QList< QKeySequence > & end()
QCA_EXPORT void setProperty(const QString &name, const QVariant &value)
QByteArray toLower() const const
bool connect(const QString &service, const QString &path, const QString &interface, const QString &name, QObject *receiver, const char *slot)
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
const_reference at(qsizetype i) const const
const_iterator constBegin() const const
const_iterator constEnd() const const
bool contains(const AT &value) const const
qsizetype indexOf(const AT &value, qsizetype from) const const
bool isEmpty() const const
qsizetype removeAll(const AT &t)
void reserve(qsizetype size)
double bounded(double highest)
QRandomGenerator * global()
QString arg(Args &&... args) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool isNull() const const
QString last(qsizetype n) const const
QString mid(qsizetype position, qsizetype n) const const
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString toUpper() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QStringList filter(QStringView str, Qt::CaseSensitivity cs) const const
QTextStream & endl(QTextStream &stream)
QString toString() const const