1 /*
2 
3   SPDX-FileCopyrightText: 2009-2021 Laurent Montel <montel@kde.org>
4 
5   SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "foldersettings.h"
9 #include "kernel/mailkernel.h"
10 #include "mailcommon_debug.h"
11 #include "util/mailutil.h"
12 #include "util/resourcereadconfigfile.h"
13 #include <Akonadi/CollectionModifyJob>
14 #include <Akonadi/ItemFetchJob>
15 #include <Akonadi/ItemFetchScope>
16 #include <Akonadi/KMime/NewMailNotifierAttribute>
17 #include <PimCommon/PimUtil>
18 
19 using namespace Akonadi;
20 
21 #include <KIdentityManagement/Identity>
22 #include <KIdentityManagement/IdentityManager>
23 
24 #include <QMutex>
25 #include <QMutexLocker>
26 #include <QSharedPointer>
27 
28 namespace MailCommon
29 {
30 static QMutex mapMutex;
31 static QMap<Collection::Id, QSharedPointer<FolderSettings>> fcMap;
32 
forCollection(const Akonadi::Collection & coll,bool writeConfig)33 QSharedPointer<FolderSettings> FolderSettings::forCollection(const Akonadi::Collection &coll, bool writeConfig)
34 {
35     QMutexLocker lock(&mapMutex);
36 
37     QSharedPointer<FolderSettings> sptr = fcMap.value(coll.id());
38 
39     if (!sptr) {
40         sptr = QSharedPointer<FolderSettings>(new FolderSettings(coll, writeConfig));
41         fcMap.insert(coll.id(), sptr);
42     } else {
43         sptr->setCollection(coll);
44         if (!sptr->isWriteConfig() && writeConfig) {
45             sptr->setWriteConfig(true);
46         }
47     }
48 
49     return sptr;
50 }
51 
FolderSettings(const Akonadi::Collection & col,bool writeconfig)52 FolderSettings::FolderSettings(const Akonadi::Collection &col, bool writeconfig)
53     : mCollection(col)
54     , mWriteConfig(writeconfig)
55 {
56     Q_ASSERT(col.isValid());
57     mIdentity = KernelIf->identityManager()->defaultIdentity().uoid();
58 
59     readConfig();
60     connect(KernelIf->identityManager(), qOverload<>(&KIdentityManagement::IdentityManager::changed), this, &FolderSettings::slotIdentitiesChanged);
61 }
62 
~FolderSettings()63 FolderSettings::~FolderSettings()
64 {
65     // qCDebug(MAILCOMMON_LOG)<<" FolderCollection::~FolderCollection"<<this;
66     if (mWriteConfig) {
67         writeConfig();
68     }
69 }
70 
formatMessage() const71 MessageViewer::Viewer::DisplayFormatMessage FolderSettings::formatMessage() const
72 {
73     return mFormatMessage;
74 }
75 
setFormatMessage(MessageViewer::Viewer::DisplayFormatMessage formatMessage)76 void FolderSettings::setFormatMessage(MessageViewer::Viewer::DisplayFormatMessage formatMessage)
77 {
78     mFormatMessage = formatMessage;
79 }
80 
clearCache()81 void FolderSettings::clearCache()
82 {
83     QMutexLocker lock(&mapMutex);
84     fcMap.clear();
85 }
86 
resetHtmlFormat()87 void FolderSettings::resetHtmlFormat()
88 {
89     QMutexLocker lock(&mapMutex);
90     QMap<Collection::Id, QSharedPointer<FolderSettings>>::const_iterator i = fcMap.constBegin();
91     while (i != fcMap.constEnd()) {
92         i.value()->setFormatMessage(MessageViewer::Viewer::UseGlobalSetting);
93         ++i;
94     }
95 }
96 
isWriteConfig() const97 bool FolderSettings::isWriteConfig() const
98 {
99     return mWriteConfig;
100 }
101 
setWriteConfig(bool writeConfig)102 void FolderSettings::setWriteConfig(bool writeConfig)
103 {
104     mWriteConfig = writeConfig;
105 }
106 
name() const107 QString FolderSettings::name() const
108 {
109     return mCollection.name();
110 }
111 
isSystemFolder() const112 bool FolderSettings::isSystemFolder() const
113 {
114     return Kernel::self()->isSystemFolderCollection(mCollection);
115 }
116 
isStructural() const117 bool FolderSettings::isStructural() const
118 {
119     return mCollection.contentMimeTypes().isEmpty();
120 }
121 
isReadOnly() const122 bool FolderSettings::isReadOnly() const
123 {
124     return mCollection.rights() & Akonadi::Collection::ReadOnly;
125 }
126 
canDeleteMessages() const127 bool FolderSettings::canDeleteMessages() const
128 {
129     return mCollection.rights() & Akonadi::Collection::CanDeleteItem;
130 }
131 
canCreateMessages() const132 bool FolderSettings::canCreateMessages() const
133 {
134     return mCollection.rights() & Akonadi::Collection::CanCreateItem;
135 }
136 
count() const137 qint64 FolderSettings::count() const
138 {
139     return mCollection.statistics().count();
140 }
141 
rights() const142 Akonadi::Collection::Rights FolderSettings::rights() const
143 {
144     return mCollection.rights();
145 }
146 
statistics() const147 Akonadi::CollectionStatistics FolderSettings::statistics() const
148 {
149     return mCollection.statistics();
150 }
151 
setCollection(const Akonadi::Collection & collection)152 void FolderSettings::setCollection(const Akonadi::Collection &collection)
153 {
154     mCollection = collection;
155 }
156 
slotIdentitiesChanged()157 void FolderSettings::slotIdentitiesChanged()
158 {
159     uint defaultIdentity = KernelIf->identityManager()->defaultIdentity().uoid();
160     // The default identity may have changed, therefore set it again if necessary
161     if (mUseDefaultIdentity) {
162         mIdentity = defaultIdentity;
163     }
164 
165     // Fall back to the default identity if the one used currently is invalid
166     if (KernelIf->identityManager()->identityForUoid(mIdentity).isNull()) {
167         mIdentity = defaultIdentity;
168         mUseDefaultIdentity = true;
169     }
170 }
171 
configGroupName(const Akonadi::Collection & col)172 QString FolderSettings::configGroupName(const Akonadi::Collection &col)
173 {
174     return QStringLiteral("Folder-%1").arg(QString::number(col.id()));
175 }
176 
readConfig()177 void FolderSettings::readConfig()
178 {
179     KConfigGroup configGroup(KernelIf->config(), configGroupName(mCollection));
180     mMailingListEnabled = configGroup.readEntry("MailingListEnabled", false);
181     mMailingList.readConfig(configGroup);
182 
183     mUseDefaultIdentity = configGroup.readEntry("UseDefaultIdentity", true);
184     uint defaultIdentity = KernelIf->identityManager()->defaultIdentity().uoid();
185     mIdentity = configGroup.readEntry("Identity", defaultIdentity);
186     slotIdentitiesChanged();
187 
188     mPutRepliesInSameFolder = configGroup.readEntry("PutRepliesInSameFolder", false);
189     mHideInSelectionDialog = configGroup.readEntry("HideInSelectionDialog", false);
190 
191     if (configGroup.hasKey(QStringLiteral("IgnoreNewMail"))) {
192         if (configGroup.readEntry(QStringLiteral("IgnoreNewMail"), false)) {
193             // migrate config.
194             auto *newMailNotifierAttr = mCollection.attribute<Akonadi::NewMailNotifierAttribute>(Akonadi::Collection::AddIfMissing);
195             newMailNotifierAttr->setIgnoreNewMail(true);
196             new Akonadi::CollectionModifyJob(mCollection, this);
197             // TODO verify if it works;
198         }
199         configGroup.deleteEntry("IgnoreNewMail");
200     }
201 
202     const QString shortcut(configGroup.readEntry("Shortcut"));
203     if (!shortcut.isEmpty()) {
204         QKeySequence sc(shortcut);
205         setShortcut(sc);
206     }
207 
208     mFormatMessage = static_cast<MessageViewer::Viewer::DisplayFormatMessage>(
209         configGroup.readEntry("displayFormatOverride", static_cast<int>(MessageViewer::Viewer::UseGlobalSetting)));
210 
211     mFolderHtmlLoadExtPreference = configGroup.readEntry("htmlLoadExternalOverride", false);
212 }
213 
isValid() const214 bool FolderSettings::isValid() const
215 {
216     return mCollection.isValid();
217 }
218 
writeConfig() const219 void FolderSettings::writeConfig() const
220 {
221     const QString res = resource();
222     KConfigGroup configGroup(KernelIf->config(), configGroupName(mCollection));
223 
224     if (mMailingListEnabled) {
225         configGroup.writeEntry("MailingListEnabled", mMailingListEnabled);
226     } else {
227         configGroup.deleteEntry("MailingListEnabled");
228     }
229     mMailingList.writeConfig(configGroup);
230 
231     if (!mUseDefaultIdentity) {
232         configGroup.writeEntry("UseDefaultIdentity", mUseDefaultIdentity);
233         uint defaultIdentityId = -1;
234 
235         if (PimCommon::Util::isImapResource(res)) {
236             MailCommon::ResourceReadConfigFile resourceFile(res);
237             KConfigGroup grp = resourceFile.group(QStringLiteral("cache"));
238             if (grp.isValid()) {
239                 defaultIdentityId = grp.readEntry(QStringLiteral("AccountIdentity"), -1);
240             }
241         } else {
242             defaultIdentityId = KernelIf->identityManager()->defaultIdentity().uoid();
243         }
244 
245         if (mIdentity != defaultIdentityId) {
246             configGroup.writeEntry("Identity", mIdentity);
247         } else {
248             configGroup.deleteEntry("Identity");
249         }
250     } else {
251         configGroup.deleteEntry("Identity");
252         configGroup.deleteEntry("UseDefaultIdentity");
253     }
254 
255     if (mPutRepliesInSameFolder) {
256         configGroup.writeEntry("PutRepliesInSameFolder", mPutRepliesInSameFolder);
257     } else {
258         configGroup.deleteEntry("PutRepliesInSameFolder");
259     }
260     if (mHideInSelectionDialog) {
261         configGroup.writeEntry("HideInSelectionDialog", mHideInSelectionDialog);
262     } else {
263         configGroup.deleteEntry("HideInSelectionDialog");
264     }
265 
266     if (!mShortcut.isEmpty()) {
267         configGroup.writeEntry("Shortcut", mShortcut.toString());
268     } else {
269         configGroup.deleteEntry("Shortcut");
270     }
271 
272     if (mFormatMessage != MessageViewer::Viewer::Unknown) {
273         if (mFormatMessage == MessageViewer::Viewer::UseGlobalSetting) {
274             configGroup.deleteEntry("displayFormatOverride");
275         } else {
276             configGroup.writeEntry("displayFormatOverride", static_cast<int>(mFormatMessage));
277         }
278     }
279     if (mFolderHtmlLoadExtPreference) {
280         configGroup.writeEntry("htmlLoadExternalOverride", mFolderHtmlLoadExtPreference);
281     } else {
282         configGroup.deleteEntry("htmlLoadExternalOverride");
283     }
284 }
285 
setShortcut(const QKeySequence & sc)286 void FolderSettings::setShortcut(const QKeySequence &sc)
287 {
288     mShortcut = sc;
289 }
290 
shortcut() const291 const QKeySequence &FolderSettings::shortcut() const
292 {
293     return mShortcut;
294 }
295 
setUseDefaultIdentity(bool useDefaultIdentity)296 void FolderSettings::setUseDefaultIdentity(bool useDefaultIdentity)
297 {
298     if (mUseDefaultIdentity != useDefaultIdentity) {
299         mUseDefaultIdentity = useDefaultIdentity;
300         if (mUseDefaultIdentity) {
301             mIdentity = KernelIf->identityManager()->defaultIdentity().uoid();
302         }
303         KernelIf->syncConfig();
304     }
305 }
306 
useDefaultIdentity() const307 bool FolderSettings::useDefaultIdentity() const
308 {
309     return mUseDefaultIdentity;
310 }
311 
setIdentity(uint identity)312 void FolderSettings::setIdentity(uint identity)
313 {
314     if (mIdentity != identity) {
315         mIdentity = identity;
316         KernelIf->syncConfig();
317     }
318 }
319 
resource() const320 QString FolderSettings::resource() const
321 {
322     const QString resource = mCollection.resource();
323     if (resource.isEmpty()) {
324         const Collection col = CommonKernel->collectionFromId(mCollection.id());
325         Q_ASSERT(col.isValid());
326         Q_ASSERT(!col.resource().isEmpty());
327         return col.resource();
328     }
329     return resource;
330 }
331 
folderHtmlLoadExtPreference() const332 bool FolderSettings::folderHtmlLoadExtPreference() const
333 {
334     return mFolderHtmlLoadExtPreference;
335 }
336 
setFolderHtmlLoadExtPreference(bool folderHtmlLoadExtPreference)337 void FolderSettings::setFolderHtmlLoadExtPreference(bool folderHtmlLoadExtPreference)
338 {
339     mFolderHtmlLoadExtPreference = folderHtmlLoadExtPreference;
340 }
341 
fallBackIdentity() const342 uint FolderSettings::fallBackIdentity() const
343 {
344     int identityId = -1;
345     MailCommon::ResourceReadConfigFile resourceFile(resource());
346     KConfigGroup grp = resourceFile.group(QStringLiteral("cache"));
347     if (grp.isValid()) {
348         const bool useDefault = grp.readEntry(QStringLiteral("UseDefaultIdentity"), true);
349         if (useDefault) {
350             return mIdentity;
351         }
352         const int remoteAccountIdent = grp.readEntry(QStringLiteral("AccountIdentity"), -1);
353         if (remoteAccountIdent > 0) {
354             identityId = remoteAccountIdent;
355         }
356     }
357     if (identityId != -1 && !KernelIf->identityManager()->identityForUoid(identityId).isNull()) {
358         return identityId;
359     }
360     return mIdentity;
361 }
362 
identity() const363 uint FolderSettings::identity() const
364 {
365     if (mUseDefaultIdentity) {
366         return fallBackIdentity();
367     }
368     return mIdentity;
369 }
370 
mailingListPostAddress() const371 QString FolderSettings::mailingListPostAddress() const
372 {
373     if (mMailingList.features() & MailingList::Post) {
374         QList<QUrl> post = mMailingList.postUrls();
375         QList<QUrl>::const_iterator end(post.constEnd());
376         for (QList<QUrl>::const_iterator it = post.constBegin(); it != end; ++it) {
377             // We check for isEmpty because before 3.3 postAddress was just an
378             // email@kde.org and that leaves protocol() field in the qurl class
379             const QString protocol = (*it).scheme();
380             if (protocol == QLatin1String("mailto") || protocol.isEmpty()) {
381                 return (*it).path();
382             }
383         }
384     }
385     return QString();
386 }
387 
setMailingListEnabled(bool enabled)388 void FolderSettings::setMailingListEnabled(bool enabled)
389 {
390     if (mMailingListEnabled != enabled) {
391         mMailingListEnabled = enabled;
392         writeConfig();
393     }
394 }
395 
isMailingListEnabled() const396 bool FolderSettings::isMailingListEnabled() const
397 {
398     return mMailingListEnabled;
399 }
400 
setMailingList(const MailingList & mlist)401 void FolderSettings::setMailingList(const MailingList &mlist)
402 {
403     if (mMailingList == mlist) {
404         return;
405     }
406 
407     mMailingList = mlist;
408     writeConfig();
409 }
410 
mailingList() const411 MessageCore::MailingList FolderSettings::mailingList() const
412 {
413     return mMailingList;
414 }
415 
putRepliesInSameFolder() const416 bool FolderSettings::putRepliesInSameFolder() const
417 {
418     return mPutRepliesInSameFolder;
419 }
420 
setPutRepliesInSameFolder(bool b)421 void FolderSettings::setPutRepliesInSameFolder(bool b)
422 {
423     mPutRepliesInSameFolder = b;
424 }
425 
hideInSelectionDialog() const426 bool FolderSettings::hideInSelectionDialog() const
427 {
428     return mHideInSelectionDialog;
429 }
430 
setHideInSelectionDialog(bool hide)431 void FolderSettings::setHideInSelectionDialog(bool hide)
432 {
433     mHideInSelectionDialog = hide;
434 }
435 }
436