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