1 /*
2    SPDX-FileCopyrightText: 2012-2021 Laurent Montel <montel@kde.org>
3 
4    SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "abstractimportexportjob.h"
8 #include "archivestorage.h"
9 #include "backupresourcefilejobbase.h"
10 #include "backupresourcefilejobimpl.h"
11 #include "importexportprogressindicatorbase.h"
12 #include "storeresourcejob.h"
13 #include "synchronizeresourcejob.h"
14 
15 #include <Akonadi/AgentInstance>
16 #include <PimCommonAkonadi/CreateResource>
17 
18 #include <KLocalizedString>
19 #include <KZip>
20 #include <QTemporaryDir>
21 
22 #include <Akonadi/ServerManager>
23 
24 #include <KConfigGroup>
25 #include <QCoreApplication>
26 #include <QDir>
27 #include <QFile>
28 #include <QStandardPaths>
29 
30 int AbstractImportExportJob::sArchiveVersion = -1;
31 
AbstractImportExportJob(QObject * parent,ArchiveStorage * archiveStorage,Utils::StoredTypes typeSelected,int numberOfStep)32 AbstractImportExportJob::AbstractImportExportJob(QObject *parent, ArchiveStorage *archiveStorage, Utils::StoredTypes typeSelected, int numberOfStep)
33     : QObject(parent)
34     , mTypeSelected(typeSelected)
35     , mArchiveStorage(archiveStorage)
36     , mNumberOfStep(numberOfStep)
37     , mImportExportProgressIndicator(new ImportExportProgressIndicatorBase(this))
38 {
39     mImportExportProgressIndicator->setNumberOfStep(numberOfStep);
40     connect(mImportExportProgressIndicator, &ImportExportProgressIndicatorBase::info, this, &AbstractImportExportJob::info);
41 }
42 
~AbstractImportExportJob()43 AbstractImportExportJob::~AbstractImportExportJob()
44 {
45     delete mCreateResource;
46     delete mTempDir;
47 }
48 
createProgressDialog(const QString & title)49 void AbstractImportExportJob::createProgressDialog(const QString &title)
50 {
51     mImportExportProgressIndicator->createProgressDialog(title);
52     connect(mImportExportProgressIndicator, &ImportExportProgressIndicatorBase::canceled, this, &AbstractImportExportJob::slotTaskCanceled);
53 }
54 
slotTaskCanceled()55 void AbstractImportExportJob::slotTaskCanceled()
56 {
57     Q_EMIT error(i18n("Task Canceled"));
58     Q_EMIT jobFinished();
59 }
60 
wasCanceled() const61 bool AbstractImportExportJob::wasCanceled() const
62 {
63     return mImportExportProgressIndicator->wasCanceled();
64 }
65 
increaseProgressDialog()66 void AbstractImportExportJob::increaseProgressDialog()
67 {
68     mImportExportProgressIndicator->increaseProgressDialog();
69 }
70 
setProgressDialogLabel(const QString & text)71 void AbstractImportExportJob::setProgressDialogLabel(const QString &text)
72 {
73     mImportExportProgressIndicator->setProgressDialogLabel(text);
74 }
75 
importExportProgressIndicator() const76 ImportExportProgressIndicatorBase *AbstractImportExportJob::importExportProgressIndicator() const
77 {
78     return mImportExportProgressIndicator;
79 }
80 
setImportExportProgressIndicator(ImportExportProgressIndicatorBase * importExportProgressIndicator)81 void AbstractImportExportJob::setImportExportProgressIndicator(ImportExportProgressIndicatorBase *importExportProgressIndicator)
82 {
83     delete mImportExportProgressIndicator;
84     mImportExportProgressIndicator = importExportProgressIndicator;
85     mImportExportProgressIndicator->setNumberOfStep(mNumberOfStep);
86 }
87 
archive() const88 KZip *AbstractImportExportJob::archive() const
89 {
90     return mArchiveStorage->archive();
91 }
92 
backupUiRcFile(const QString & configFileName,const QString & application)93 void AbstractImportExportJob::backupUiRcFile(const QString &configFileName, const QString &application)
94 {
95     const QString configrcStr(configFileName);
96     const QString configrc =
97         QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kxmlgui5/") + application + QLatin1Char('/') + configrcStr;
98     if (QFileInfo::exists(configrc)) {
99         backupFile(configrc, Utils::configsPath(), configrcStr);
100     }
101 }
102 
backupConfigFile(const QString & configFileName)103 void AbstractImportExportJob::backupConfigFile(const QString &configFileName)
104 {
105     const QString configrcStr(configFileName);
106     const QString configrc = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1Char('/') + configrcStr;
107     if (QFileInfo::exists(configrc)) {
108         backupFile(configrc, Utils::configsPath(), configrcStr);
109     }
110 }
111 
backupFile(const QString & filename,const QString & path,const QString & storedName)112 void AbstractImportExportJob::backupFile(const QString &filename, const QString &path, const QString &storedName)
113 {
114     if (QFileInfo::exists(filename)) {
115         const bool fileAdded = archive()->addLocalFile(filename, path + storedName);
116         if (fileAdded) {
117             Q_EMIT info(i18n("\"%1\" backup done.", path + storedName));
118         } else {
119             Q_EMIT error(i18n("\"%1\" cannot be exported.", path + storedName));
120         }
121     } else {
122         Q_EMIT error(i18n("\"%1\" does not exist.", filename));
123     }
124 }
125 
mergeConfigMessageBox(const QString & configName) const126 int AbstractImportExportJob::mergeConfigMessageBox(const QString &configName) const
127 {
128     return mImportExportProgressIndicator->mergeConfigMessageBox(configName);
129 }
130 
overwriteConfigMessageBox(const QString & configName) const131 bool AbstractImportExportJob::overwriteConfigMessageBox(const QString &configName) const
132 {
133     return mImportExportProgressIndicator->overwriteConfigMessageBox(configName);
134 }
135 
overwriteDirectory(const QString & path,const KArchiveEntry * entry)136 void AbstractImportExportJob::overwriteDirectory(const QString &path, const KArchiveEntry *entry)
137 {
138     if (QDir(path).exists()) {
139         if (overwriteDirectoryMessageBox(path)) {
140             const auto dirEntry = static_cast<const KArchiveDirectory *>(entry);
141             if (!dirEntry->copyTo(path)) {
142                 qCWarning(PIMDATAEXPORTERCORE_LOG) << "directory cannot overwrite to " << path;
143             }
144         }
145     } else {
146         const auto dirEntry = static_cast<const KArchiveDirectory *>(entry);
147         if (dirEntry->copyTo(path)) {
148             qCWarning(PIMDATAEXPORTERCORE_LOG) << "directory cannot overwrite to " << path;
149         }
150     }
151 }
152 
searchAllFiles(const KArchiveDirectory * dir,const QString & prefix,const QString & searchEntryName)153 void AbstractImportExportJob::searchAllFiles(const KArchiveDirectory *dir, const QString &prefix, const QString &searchEntryName)
154 {
155     const QStringList lst = dir->entries();
156     for (const QString &entryName : lst) {
157         const KArchiveEntry *entry = dir->entry(entryName);
158         if (entry && entry->isDirectory()) {
159             const QString newPrefix = (prefix.isEmpty() ? prefix : prefix + QLatin1Char('/')) + entryName;
160             if (entryName == searchEntryName) {
161                 storeArchiveInfoResources(static_cast<const KArchiveDirectory *>(entry), entryName);
162             } else {
163                 searchAllFiles(static_cast<const KArchiveDirectory *>(entry), newPrefix, searchEntryName);
164             }
165         }
166     }
167 }
168 
storeArchiveInfoResources(const KArchiveDirectory * dir,const QString & prefix)169 void AbstractImportExportJob::storeArchiveInfoResources(const KArchiveDirectory *dir, const QString &prefix)
170 {
171     const QStringList lst = dir->entries();
172     for (const QString &entryName : lst) {
173         const KArchiveEntry *entry = dir->entry(entryName);
174         if (entry && entry->isDirectory()) {
175             const auto resourceDir = static_cast<const KArchiveDirectory *>(entry);
176             const QStringList lst = resourceDir->entries();
177 
178             if (lst.count() >= 2) {
179                 const QString archPath(prefix + QLatin1Char('/') + entryName + QLatin1Char('/'));
180                 ResourceFiles files;
181                 for (const QString &name : lst) {
182                     if (isAConfigFile(name)) {
183                         files.akonadiConfigFile = archPath + name;
184                     } else if (name.startsWith(Utils::prefixAkonadiConfigFile())) {
185                         files.akonadiAgentConfigFile = archPath + name;
186                     } else {
187                         files.akonadiResources = archPath + name;
188                     }
189                 }
190                 files.debug();
191                 mListResourceFile.append(files);
192             } else {
193                 qCWarning(PIMDATAEXPORTERCORE_LOG) << " Problem in archive. number of file " << lst.count();
194             }
195         }
196     }
197     std::sort(mListResourceFile.begin(), mListResourceFile.end());
198 }
199 
isAConfigFile(const QString & name) const200 bool AbstractImportExportJob::isAConfigFile(const QString &name) const
201 {
202     Q_UNUSED(name)
203     // Redefine in subclass
204     return true;
205 }
206 
overwriteDirectoryMessageBox(const QString & directory) const207 bool AbstractImportExportJob::overwriteDirectoryMessageBox(const QString &directory) const
208 {
209     return mImportExportProgressIndicator->overwriteDirectoryMessageBox(directory);
210 }
211 
convertRealPathToCollection(KConfigGroup & group,const QString & currentKey,bool addCollectionPrefix)212 qint64 AbstractImportExportJob::convertRealPathToCollection(KConfigGroup &group, const QString &currentKey, bool addCollectionPrefix)
213 {
214     qint64 colId = -1;
215     if (group.hasKey(currentKey)) {
216         const QString path = group.readEntry(currentKey);
217         if (!path.isEmpty()) {
218             const Akonadi::Collection::Id id = convertPathToId(path);
219             if (id != -1) {
220                 if (addCollectionPrefix) {
221                     group.writeEntry(currentKey, QStringLiteral("c%1").arg(id));
222                 } else {
223                     group.writeEntry(currentKey, id);
224                 }
225             } else {
226                 group.deleteEntry(currentKey);
227             }
228             colId = id;
229         }
230     }
231     return colId;
232 }
233 
convertPathToId(const QString & path)234 Akonadi::Collection::Id AbstractImportExportJob::convertPathToId(const QString &path)
235 {
236     if (path.isEmpty()) {
237         return -1;
238     }
239     Akonadi::Collection::Id val = mHashConvertPathCollectionId.value(path, -1);
240     if (val != -1) {
241         return val;
242     }
243     const Akonadi::Collection::Id id = convertFolderPathToCollectionId(path);
244     if (id != -1) {
245         mHashConvertPathCollectionId.insert(path, id);
246     }
247     return id;
248 }
249 
initializeImportJob()250 void AbstractImportExportJob::initializeImportJob()
251 {
252     if (mTempDir) {
253         qCDebug(PIMDATAEXPORTERCORE_LOG) << " initializeImportJob already called";
254     } else {
255         mTempDir = new QTemporaryDir();
256         mTempDirName = mTempDir->path();
257         mCreateResource = new PimCommon::CreateResource();
258         connect(mCreateResource, &PimCommon::CreateResource::createResourceInfo, this, &AbstractImportExportJob::info);
259         connect(mCreateResource, &PimCommon::CreateResource::createResourceError, this, &AbstractImportExportJob::error);
260     }
261 }
262 
copyToDirectory(const KArchiveEntry * entry,const QString & dest)263 void AbstractImportExportJob::copyToDirectory(const KArchiveEntry *entry, const QString &dest)
264 {
265     const auto subfolderDir = static_cast<const KArchiveDirectory *>(entry);
266     if (!subfolderDir->copyTo(dest)) {
267         qCDebug(PIMDATAEXPORTERCORE_LOG) << "directory cannot copy to " << dest;
268     }
269     Q_EMIT info(i18n("\"%1\" was copied.", dest));
270 }
271 
copyToFile(const KArchiveFile * archivefile,const QString & dest,const QString & filename,const QString & prefix)272 void AbstractImportExportJob::copyToFile(const KArchiveFile *archivefile, const QString &dest, const QString &filename, const QString &prefix)
273 {
274     QDir dir(mTempDirName);
275     const QString copyToDirName(mTempDirName + QLatin1Char('/') + prefix);
276     const bool created = dir.mkpath(copyToDirName);
277     if (!created) {
278         qCWarning(PIMDATAEXPORTERCORE_LOG) << " directory :" << prefix << " not created";
279     }
280 
281     if (!archivefile->copyTo(copyToDirName)) {
282         qCWarning(PIMDATAEXPORTERCORE_LOG) << "copyToFile file " << filename << " can not copy to " << dest;
283     }
284     QFile file;
285     file.setFileName(copyToDirName + QLatin1Char('/') + filename);
286 
287     // QFile doesn't overwrite => remove old file before
288     // qCDebug(PIMDATAEXPORTERCORE_LOG)<<" dest "<<dest;
289     // qCDebug(PIMDATAEXPORTERCORE_LOG)<<" file "<<file.fileName();
290     QFile destination(dest);
291     if (destination.exists()) {
292         destination.remove();
293     }
294     QFileInfo destFileInfo(dest);
295 
296     QDir().mkpath(destFileInfo.path());
297     if (!file.copy(dest)) {
298         mImportExportProgressIndicator->showErrorMessage(i18n("File \"%1\" cannot be copied to \"%2\".", filename, dest), i18n("Copy file"));
299     } else {
300         Q_EMIT info(i18n("\"%1\" was restored.", filename));
301     }
302 }
303 
backupResourceFile(const QString & identifier,const QString & defaultPath)304 void AbstractImportExportJob::backupResourceFile(const QString &identifier, const QString &defaultPath)
305 {
306     auto job = new BackupResourceFileJobImpl(this);
307     job->setDefaultPath(defaultPath);
308     job->setIdentifier(identifier);
309     job->setZip(archive());
310     connect(job, &BackupResourceFileJobImpl::error, this, &AbstractImportExportJob::error);
311     connect(job, &BackupResourceFileJobImpl::info, this, &AbstractImportExportJob::info);
312     job->start();
313 }
314 
315 QStringList
restoreResourceFile(const QString & resourceBaseName,const QString & defaultPath,const QString & storePath,bool overwriteResources)316 AbstractImportExportJob::restoreResourceFile(const QString &resourceBaseName, const QString &defaultPath, const QString &storePath, bool overwriteResources)
317 {
318     QStringList resourceToSync;
319     // TODO fix sync config after created a resource
320     if (!mListResourceFile.isEmpty()) {
321         QDir dir(mTempDirName);
322         dir.mkdir(defaultPath);
323         const QString copyToDirName(mTempDirName + QLatin1Char('/') + defaultPath);
324         if (!QDir().mkpath(copyToDirName)) {
325             qCWarning(PIMDATAEXPORTERCORE_LOG) << " impossible to create :" << copyToDirName;
326         }
327 
328         for (int i = 0, total = mListResourceFile.size(); i < total; ++i) {
329             ResourceFiles value = mListResourceFile.at(i);
330             QMap<QString, QVariant> settings;
331             if (value.akonadiConfigFile.contains(resourceBaseName + QLatin1Char('_'))) {
332                 const KArchiveEntry *fileResouceEntry = mArchiveDirectory->entry(value.akonadiConfigFile);
333                 if (fileResouceEntry && fileResouceEntry->isFile()) {
334                     const auto file = static_cast<const KArchiveFile *>(fileResouceEntry);
335                     if (!file->copyTo(copyToDirName)) {
336                         qCWarning(PIMDATAEXPORTERCORE_LOG)
337                             << "AbstractImportExportJob file " << value.akonadiConfigFile << " can not copy to " << copyToDirName;
338                     }
339                     QString resourceName(file->name());
340 
341                     QString filename(file->name());
342                     // TODO adapt filename otherwise it will use all the time the same filename.
343                     qCDebug(PIMDATAEXPORTERCORE_LOG) << " filename :" << filename;
344 
345                     KSharedConfig::Ptr resourceConfig = KSharedConfig::openConfig(copyToDirName + QLatin1Char('/') + resourceName);
346 
347                     QString newUrl = adaptNewResourceUrl(overwriteResources, resourceConfig, storePath);
348                     const QString dataFile = value.akonadiResources;
349                     const KArchiveEntry *dataResouceEntry = mArchiveDirectory->entry(dataFile);
350                     if (dataResouceEntry && dataResouceEntry->isFile()) {
351                         const auto file = static_cast<const KArchiveFile *>(dataResouceEntry);
352                         if (!file->copyTo(newUrl)) {
353                             qCWarning(PIMDATAEXPORTERCORE_LOG) << "AbstractImportExportJob: file " << dataFile << " can not copy to " << newUrl;
354                         }
355                     }
356                     if (!newUrl.isEmpty()) {
357                         settings.insert(QStringLiteral("Path"), newUrl);
358                     }
359 
360                     const QString agentConfigFile = value.akonadiAgentConfigFile;
361                     if (!agentConfigFile.isEmpty()) {
362                         const KArchiveEntry *akonadiAgentConfigEntry = mArchiveDirectory->entry(agentConfigFile);
363                         if (akonadiAgentConfigEntry->isFile()) {
364                             const auto file = static_cast<const KArchiveFile *>(akonadiAgentConfigEntry);
365                             file->copyTo(copyToDirName);
366                             resourceName = file->name();
367                             const QString configPath = copyToDirName + QLatin1Char('/') + resourceName;
368                             filename = Utils::akonadiAgentName(configPath);
369                         }
370                     }
371 
372                     addSpecificResourceSettings(resourceConfig, resourceBaseName, settings);
373 
374                     const QString newResource = createResource(resourceBaseName, filename, settings);
375                     infoAboutNewResource(newResource);
376                     resourceToSync << newResource;
377                     qCDebug(PIMDATAEXPORTERCORE_LOG) << " newResource" << newResource;
378                 }
379             }
380         }
381         Q_EMIT info(i18n("Resources restored."));
382     } else {
383         Q_EMIT error(i18n("No resources files found."));
384         qDebug() << " resourceBaseName " << resourceBaseName;
385     }
386     return resourceToSync;
387 }
388 
addSpecificResourceSettings(const KSharedConfig::Ptr &,const QString &,QMap<QString,QVariant> &)389 void AbstractImportExportJob::addSpecificResourceSettings(const KSharedConfig::Ptr /*resourceConfig*/ &,
390                                                           const QString & /*resourceName*/,
391                                                           QMap<QString, QVariant> & /*settings*/)
392 {
393     // Redefine it in subclass
394 }
395 
copyArchiveFileTo(const KArchiveFile * file,const QString & destination)396 bool AbstractImportExportJob::copyArchiveFileTo(const KArchiveFile *file, const QString &destination)
397 {
398     const bool result = file->copyTo(destination);
399     if (!result) {
400         qCWarning(PIMDATAEXPORTERCORE_LOG) << "copyArchiveFileTo file " << file->name() << " can not copy to " << destination;
401     }
402     return result;
403 }
404 
extractZipFile(const KArchiveFile * file,const QString & source,const QString & destination,bool isStoredAsZippedArchive)405 void AbstractImportExportJob::extractZipFile(const KArchiveFile *file, const QString &source, const QString &destination, bool isStoredAsZippedArchive)
406 {
407     if (!file->copyTo(source)) {
408         qCWarning(PIMDATAEXPORTERCORE_LOG) << "extractZipFile file " << file->name() << " can not copy to " << source;
409     }
410     QDir dest(destination);
411     if (!dest.exists()) {
412         dest.mkpath(destination);
413     }
414     if (isStoredAsZippedArchive) {
415         QString errorMsg;
416         KZip *zip = Utils::openZip(source + QLatin1Char('/') + file->name(), errorMsg);
417         if (zip) {
418             const KArchiveDirectory *zipDir = zip->directory();
419             const QStringList lst = zipDir->entries();
420             for (const QString &entryName : lst) {
421                 const KArchiveEntry *entry = zipDir->entry(entryName);
422                 if (entry) {
423                     if (entry->isDirectory()) {
424                         const auto dir = static_cast<const KArchiveDirectory *>(entry);
425                         dir->copyTo(destination + QLatin1Char('/') + dir->name(), true);
426                     } else if (entry->isFile()) {
427                         const auto dir = static_cast<const KArchiveFile *>(entry);
428                         dir->copyTo(destination);
429                     }
430                 }
431                 qApp->processEvents();
432             }
433             delete zip;
434         } else {
435             Q_EMIT error(errorMsg);
436         }
437     } else {
438         QFile archiveFile(source + QLatin1Char('/') + file->name());
439         if (!archiveFile.copy(destination + QLatin1Char('/') + file->name())) {
440             Q_EMIT error(i18n("Unable to copy file %1", file->name()));
441         }
442     }
443 }
444 
restoreUiRcFile(const QString & configNameStr,const QString & applicationName)445 void AbstractImportExportJob::restoreUiRcFile(const QString &configNameStr, const QString &applicationName)
446 {
447     const KArchiveEntry *configNameentry = mArchiveDirectory->entry(Utils::configsPath() + configNameStr);
448     if (configNameentry && configNameentry->isFile()) {
449         const auto configNameconfiguration = static_cast<const KArchiveFile *>(configNameentry);
450         const QString configNamerc = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/kxmlgui5/") + applicationName
451             + QLatin1Char('/') + configNameStr;
452         if (QFileInfo::exists(configNamerc)) {
453             if (overwriteConfigMessageBox(configNameStr)) {
454                 copyToFile(configNameconfiguration, configNamerc, configNameStr, Utils::configsPath());
455             }
456         } else {
457             copyToFile(configNameconfiguration, configNamerc, configNameStr, Utils::configsPath());
458         }
459     }
460 }
461 
restoreConfigFile(const QString & configNameStr)462 void AbstractImportExportJob::restoreConfigFile(const QString &configNameStr)
463 {
464     const KArchiveEntry *configNameentry = mArchiveDirectory->entry(Utils::configsPath() + configNameStr);
465     if (configNameentry && configNameentry->isFile()) {
466         const auto configNameconfiguration = static_cast<const KArchiveFile *>(configNameentry);
467         const QString configNamerc = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QLatin1Char('/') + configNameStr;
468         if (QFileInfo::exists(configNamerc)) {
469             // TODO 4.12 allow to merge config.
470             if (overwriteConfigMessageBox(configNameStr)) {
471                 copyToFile(configNameconfiguration, configNamerc, configNameStr, Utils::configsPath());
472             }
473         } else {
474             copyToFile(configNameconfiguration, configNamerc, configNameStr, Utils::configsPath());
475         }
476     }
477 }
478 
infoAboutNewResource(const QString & resourceName)479 void AbstractImportExportJob::infoAboutNewResource(const QString &resourceName)
480 {
481     Q_EMIT info(i18n("Resource \'%1\' created.", resourceName));
482 }
483 
archiveVersion()484 int AbstractImportExportJob::archiveVersion()
485 {
486     return sArchiveVersion;
487 }
488 
setArchiveVersion(int version)489 void AbstractImportExportJob::setArchiveVersion(int version)
490 {
491     sArchiveVersion = version;
492 }
493 
slotSynchronizeInstanceFailed(const QString & instance)494 void AbstractImportExportJob::slotSynchronizeInstanceFailed(const QString &instance)
495 {
496     Q_EMIT error(i18n("Failed to synchronize %1.", instance));
497 }
498 
slotSynchronizeInstanceDone(const QString & name,const QString & identifier)499 void AbstractImportExportJob::slotSynchronizeInstanceDone(const QString &name, const QString &identifier)
500 {
501     Q_EMIT info(i18n("Resource %1 synchronized.", name));
502     Q_EMIT needSynchronizeResource(name, identifier);
503 }
504 
slotAllResourceSynchronized()505 void AbstractImportExportJob::slotAllResourceSynchronized()
506 {
507     Q_EMIT info(i18n("All resources synchronized."));
508     slotNextStep();
509 }
510 
slotNextStep()511 void AbstractImportExportJob::slotNextStep()
512 {
513     // Implement in sub class.
514 }
515 
startSynchronizeResources(const QStringList & listResourceToSync)516 void AbstractImportExportJob::startSynchronizeResources(const QStringList &listResourceToSync)
517 {
518     Q_EMIT info(i18n("Start synchronizing..."));
519     auto job = new SynchronizeResourceJob(this);
520     job->setListResources(listResourceToSync);
521     connect(job, &SynchronizeResourceJob::synchronizationFinished, this, &AbstractImportExportJob::slotAllResourceSynchronized);
522     connect(job, &SynchronizeResourceJob::synchronizationInstanceDone, this, &AbstractImportExportJob::slotSynchronizeInstanceDone);
523     connect(job, &SynchronizeResourceJob::synchronizationInstanceFailed, this, &AbstractImportExportJob::slotSynchronizeInstanceFailed);
524     job->start();
525 }
526 
initializeListStep()527 void AbstractImportExportJob::initializeListStep()
528 {
529     if (mTypeSelected & Utils::MailTransport) {
530         mListStep << Utils::MailTransport;
531     }
532     if (mTypeSelected & Utils::Mails) {
533         mListStep << Utils::Mails;
534     }
535     if (mTypeSelected & Utils::Resources) {
536         mListStep << Utils::Resources;
537     }
538     if (mTypeSelected & Utils::Identity) {
539         mListStep << Utils::Identity;
540     }
541     if (mTypeSelected & Utils::Config) {
542         mListStep << Utils::Config;
543     }
544     if (mTypeSelected & Utils::Data) {
545         mListStep << Utils::Data;
546     }
547 }
548 
storeDirectory(const QString & subDirectory)549 void AbstractImportExportJob::storeDirectory(const QString &subDirectory)
550 {
551     const QDir directoryToStore(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + subDirectory);
552     if (directoryToStore.exists()) {
553         const bool templateDirAdded = archive()->addLocalDirectory(directoryToStore.path(), Utils::dataPath() + subDirectory);
554         if (templateDirAdded) {
555             Q_EMIT info(i18n("Directory \"%1\" added to backup file.", directoryToStore.path()));
556         } else {
557             Q_EMIT error(i18n("Directory \"%1\" cannot be added to backup file.", directoryToStore.path()));
558         }
559     }
560 }
561 
importDataSubdirectory(const QString & subdirectoryRelativePath)562 void AbstractImportExportJob::importDataSubdirectory(const QString &subdirectoryRelativePath)
563 {
564     const KArchiveEntry *themeEntry = mArchiveDirectory->entry(Utils::dataPath() + subdirectoryRelativePath);
565     if (themeEntry && themeEntry->isDirectory()) {
566         const auto themeDir = static_cast<const KArchiveDirectory *>(themeEntry);
567         const QStringList lst = themeDir->entries();
568         for (const QString &entryName : lst) {
569             const KArchiveEntry *entry = themeDir->entry(entryName);
570             if (entry && entry->isDirectory()) {
571                 QString subFolderName = entryName;
572                 const QString topLevelPath =
573                     QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + subdirectoryRelativePath;
574                 QDir themeDirectory(topLevelPath + QStringLiteral("/%1").arg(entryName));
575                 int i = 1;
576                 while (themeDirectory.exists()) {
577                     subFolderName = entryName + QStringLiteral("_%1").arg(i);
578                     themeDirectory = QDir(topLevelPath + QStringLiteral("/%1").arg(subFolderName));
579                     ++i;
580                 }
581                 copyToDirectory(entry, topLevelPath + QStringLiteral("/%1").arg(subFolderName));
582             }
583         }
584     }
585 }
586 
convertCollectionListStrToAkonadiId(const KSharedConfig::Ptr & config,const QString & groupName,const QString & key,bool addCollectionPrefix)587 void AbstractImportExportJob::convertCollectionListStrToAkonadiId(const KSharedConfig::Ptr &config,
588                                                                   const QString &groupName,
589                                                                   const QString &key,
590                                                                   bool addCollectionPrefix)
591 {
592     if (config->hasGroup(groupName)) {
593         KConfigGroup group = config->group(groupName);
594         convertRealPathToCollectionList(group, key, addCollectionPrefix);
595     }
596 }
597 
convertRealPathToCollectionList(KConfigGroup & group,const QString & currentKey,bool addCollectionPrefix)598 void AbstractImportExportJob::convertRealPathToCollectionList(KConfigGroup &group, const QString &currentKey, bool addCollectionPrefix)
599 {
600     if (group.hasKey(currentKey)) {
601         const QStringList listExpension = group.readEntry(currentKey, QStringList());
602         QStringList result;
603         if (!listExpension.isEmpty()) {
604             for (const QString &collection : listExpension) {
605                 const Akonadi::Collection::Id id = convertPathToId(collection);
606                 if (id != -1) {
607                     if (addCollectionPrefix) {
608                         result << QStringLiteral("c%1").arg(id);
609                     } else {
610                         result << QStringLiteral("%1").arg(id);
611                     }
612                 }
613             }
614             if (result.isEmpty()) {
615                 group.deleteEntry(currentKey);
616             } else {
617                 group.writeEntry(currentKey, result);
618             }
619         }
620     }
621 }
622 
setTempDirName(const QString & tempDirName)623 void AbstractImportExportJob::setTempDirName(const QString &tempDirName)
624 {
625     mTempDirName = tempDirName;
626 }
627