File indexing completed on 2024-05-19 05:11:07
0001 /* 0002 SPDX-FileCopyrightText: 2013 Sérgio Martins <iamsergio@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0005 */ 0006 0007 #include "backuper.h" 0008 0009 #include <KCalendarCore/FileStorage> 0010 #include <KCalendarCore/Incidence> 0011 0012 #include <Akonadi/CalendarUtils> 0013 #include <Akonadi/CollectionFetchJob> 0014 #include <Akonadi/CollectionFetchScope> 0015 #include <Akonadi/ItemFetchJob> 0016 #include <Akonadi/ItemFetchScope> 0017 0018 #include <KJob> 0019 #include <KLocalizedString> 0020 #include <QDebug> 0021 #include <QTimeZone> 0022 0023 #include <QCoreApplication> 0024 0025 static void printOut(const QString &message) 0026 { 0027 QTextStream out(stdout); 0028 out << message << "\n"; 0029 } 0030 0031 void Backuper::emitFinished(bool success, const QString &message) 0032 { 0033 if (success) { 0034 printOut( 0035 QLatin1Char('\n') 0036 + i18np("Backup was successful. %1 incidence was saved.", "Backup was successful. %1 incidences were saved.", m_calendar->incidences().count())); 0037 } else { 0038 printOut(message); 0039 } 0040 0041 m_calendar.clear(); 0042 0043 Q_EMIT finished(success, message); 0044 qApp->exit(success ? 0 : -1); // TODO: If we move this class to kdepimlibs, remove this 0045 } 0046 0047 Backuper::Backuper(QObject *parent) 0048 : QObject(parent) 0049 , m_backupInProgress(false) 0050 { 0051 } 0052 0053 void Backuper::backup(const QString &filename, const QList<Akonadi::Collection::Id> &collectionIds) 0054 { 0055 if (filename.isEmpty()) { 0056 emitFinished(false, i18n("File is empty.")); 0057 return; 0058 } 0059 0060 if (m_backupInProgress) { 0061 emitFinished(false, i18n("A backup is already in progress.")); 0062 return; 0063 } 0064 printOut(i18n("Backing up your calendar data...")); 0065 m_calendar = KCalendarCore::MemoryCalendar::Ptr(new KCalendarCore::MemoryCalendar(QTimeZone::systemTimeZone())); 0066 m_requestedCollectionIds = collectionIds; 0067 m_backupInProgress = true; 0068 m_filename = filename; 0069 0070 auto job = new Akonadi::CollectionFetchJob(Akonadi::Collection::root(), Akonadi::CollectionFetchJob::Recursive); 0071 0072 job->fetchScope().setContentMimeTypes(KCalendarCore::Incidence::mimeTypes()); 0073 connect(job, &Akonadi::CollectionFetchJob::result, this, &Backuper::onCollectionsFetched); 0074 job->start(); 0075 } 0076 0077 void Backuper::onCollectionsFetched(KJob *job) 0078 { 0079 if (job->error() == 0) { 0080 const QStringList mimetypes = KCalendarCore::Incidence::mimeTypes(); 0081 QSet<QString> mimeTypeSet = QSet<QString>(mimetypes.begin(), mimetypes.end()); 0082 auto cfj = qobject_cast<Akonadi::CollectionFetchJob *>(job); 0083 const auto collections = cfj->collections(); 0084 for (const Akonadi::Collection &collection : collections) { 0085 if (!m_requestedCollectionIds.isEmpty() && !m_requestedCollectionIds.contains(collection.id())) { 0086 continue; 0087 } 0088 const QStringList contentMimeTypesLst = collection.contentMimeTypes(); 0089 QSet<QString> collectionMimeTypeSet = QSet<QString>(contentMimeTypesLst.begin(), contentMimeTypesLst.end()); 0090 if (!mimeTypeSet.intersect(collectionMimeTypeSet).isEmpty()) { 0091 m_collections << collection; 0092 loadCollection(collection); 0093 } 0094 } 0095 0096 if (m_collections.isEmpty()) { 0097 emitFinished(false, i18n("No data to backup.")); 0098 } 0099 } else { 0100 qCritical() << job->errorString(); 0101 m_backupInProgress = false; 0102 emitFinished(false, job->errorString()); 0103 } 0104 } 0105 0106 void Backuper::loadCollection(const Akonadi::Collection &collection) 0107 { 0108 printOut(i18n("Processing collection %1 (id=%2)...", collection.displayName(), collection.id())); 0109 auto ifj = new Akonadi::ItemFetchJob(collection, this); 0110 ifj->setProperty("collectionId", collection.id()); 0111 ifj->fetchScope().fetchFullPayload(true); 0112 connect(ifj, &Akonadi::ItemFetchJob::result, this, &Backuper::onCollectionLoaded); 0113 m_pendingCollections << collection.id(); 0114 } 0115 0116 void Backuper::onCollectionLoaded(KJob *job) 0117 { 0118 if (job->error()) { 0119 m_backupInProgress = false; 0120 m_calendar.clear(); 0121 emitFinished(false, job->errorString()); 0122 } else { 0123 auto ifj = qobject_cast<Akonadi::ItemFetchJob *>(job); 0124 Akonadi::Collection::Id id = ifj->property("collectionId").toInt(); 0125 Q_ASSERT(id != -1); 0126 const Akonadi::Item::List items = ifj->items(); 0127 m_pendingCollections.removeAll(id); 0128 0129 for (const Akonadi::Item &item : items) { 0130 KCalendarCore::Incidence::Ptr incidence = Akonadi::CalendarUtils::incidence(item); 0131 Q_ASSERT(incidence); 0132 m_calendar->addIncidence(incidence); 0133 } 0134 0135 if (m_pendingCollections.isEmpty()) { // We're done 0136 KCalendarCore::FileStorage storage(m_calendar, m_filename); 0137 bool success = storage.save(); 0138 QString message = success ? QString() : i18n("An error occurred"); 0139 emitFinished(success, message); 0140 } 0141 } 0142 } 0143 0144 #include "moc_backuper.cpp"