File indexing completed on 2024-05-05 05:13:00

0001 /*
0002     This file is part of Akregator.
0003 
0004     SPDX-FileCopyrightText: 2008 Frank Osterfeld <osterfeld@kde.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0007 */
0008 
0009 #include "loadfeedlistcommand.h"
0010 
0011 #include "feedlist.h"
0012 
0013 #include <KLocalizedString>
0014 #include <KMessageBox>
0015 
0016 #include <QDateTime>
0017 #include <QDomDocument>
0018 #include <QFile>
0019 #include <QFileInfo>
0020 #include <QPointer>
0021 #include <QRandomGenerator>
0022 #include <QString>
0023 #include <QTimer>
0024 
0025 #include <cassert>
0026 
0027 using namespace Akregator;
0028 using namespace Akregator::Backend;
0029 
0030 class Akregator::LoadFeedListCommandPrivate
0031 {
0032     LoadFeedListCommand *const q;
0033 
0034 public:
0035     explicit LoadFeedListCommandPrivate(LoadFeedListCommand *qq)
0036         : q(qq)
0037     {
0038     }
0039 
0040     void handleDocument(const QDomDocument &doc);
0041     [[nodiscard]] QString createBackup(const QString &path, bool *ok);
0042     void emitResult(const QSharedPointer<FeedList> &list);
0043     void doLoad();
0044 
0045     QString fileName;
0046     QDomDocument defaultFeedList;
0047     Storage *storage = nullptr;
0048 };
0049 
0050 void LoadFeedListCommandPrivate::emitResult(const QSharedPointer<FeedList> &list)
0051 {
0052     Q_EMIT q->result(list);
0053     q->done();
0054 }
0055 
0056 void LoadFeedListCommandPrivate::handleDocument(const QDomDocument &doc)
0057 {
0058     QSharedPointer<FeedList> feedList(new FeedList(storage));
0059     if (!feedList->readFromOpml(doc)) {
0060         bool backupCreated;
0061         const QString backupFile = createBackup(fileName, &backupCreated);
0062         const QString msg = backupCreated ? i18n(
0063                                 "<qt>The standard feed list is corrupted (invalid OPML). "
0064                                 "A backup was created:<p><b>%1</b></p></qt>",
0065                                 backupFile)
0066                                           : i18n(
0067                                               "<qt>The standard feed list is corrupted (invalid OPML). "
0068                                               "Could not create a backup.</qt>");
0069 
0070         QPointer<QObject> that(q);
0071         KMessageBox::error(q->parentWidget(), msg, i18nc("@title:window", "OPML Parsing Error"));
0072         if (!that) {
0073             return;
0074         }
0075         feedList.reset();
0076     }
0077     emitResult(feedList);
0078 }
0079 
0080 QString LoadFeedListCommandPrivate::createBackup(const QString &path, bool *ok)
0081 {
0082     const QString backup = path + QLatin1StringView("-backup.") + QString::number(QDateTime::currentDateTimeUtc().toSecsSinceEpoch());
0083 
0084     const bool copied = QFile::copy(path, backup);
0085     if (ok) {
0086         *ok = copied;
0087     }
0088     return backup;
0089 }
0090 
0091 LoadFeedListCommand::LoadFeedListCommand(QObject *parent)
0092     : Command(parent)
0093     , d(new LoadFeedListCommandPrivate(this))
0094 {
0095 }
0096 
0097 LoadFeedListCommand::~LoadFeedListCommand() = default;
0098 
0099 void LoadFeedListCommand::setFileName(const QString &fileName)
0100 {
0101     d->fileName = fileName;
0102 }
0103 
0104 void LoadFeedListCommand::setDefaultFeedList(const QDomDocument &doc)
0105 {
0106     d->defaultFeedList = doc;
0107 }
0108 
0109 void LoadFeedListCommand::setStorage(Backend::Storage *s)
0110 {
0111     d->storage = s;
0112 }
0113 
0114 void LoadFeedListCommand::doStart()
0115 {
0116     QTimer::singleShot(QRandomGenerator::global()->bounded(400), this, [this]() {
0117         d->doLoad();
0118     });
0119 }
0120 
0121 void LoadFeedListCommand::doAbort()
0122 {
0123 }
0124 
0125 void LoadFeedListCommandPrivate::doLoad()
0126 {
0127     Q_ASSERT(storage);
0128     Q_ASSERT(!fileName.isNull());
0129     Q_EMIT q->progress(0, i18n("Opening Feed List..."));
0130 
0131     QDomDocument doc;
0132 
0133     if (!QFileInfo::exists(fileName)) {
0134         handleDocument(defaultFeedList);
0135         return;
0136     }
0137 
0138     QFile file(fileName);
0139 
0140     if (!file.open(QIODevice::ReadOnly)) {
0141         QPointer<QObject> that(q);
0142         KMessageBox::error(q->parentWidget(),
0143                            i18n("<qt>Could not open feed list (%1) for reading.</qt>", file.fileName()),
0144                            i18nc("@title:window", "Read Error"));
0145         if (that) {
0146             handleDocument(defaultFeedList);
0147         }
0148         return;
0149     }
0150 
0151     const auto result = doc.setContent(&file);
0152     if (!result) {
0153         bool backupCreated = false;
0154         const QString backupFile = createBackup(fileName, &backupCreated);
0155         const QString title = i18nc("error message window caption", "XML Parsing Error");
0156         const QString details = xi18n(
0157             "<qt><p>XML parsing error in line %1, "
0158             "column %2 of %3:</p><p>%4</p></qt>",
0159             QString::number(result.errorLine),
0160             QString::number(result.errorColumn),
0161             fileName,
0162             result.errorMessage);
0163         const QString msg = backupCreated ? i18n(
0164                                 "<qt>The standard feed list is corrupted (invalid XML). "
0165                                 "A backup was created:<p><b>%1</b></p></qt>",
0166                                 backupFile)
0167                                           : i18n(
0168                                               "<qt>The standard feed list is corrupted (invalid XML). "
0169                                               "Could not create a backup.</qt>");
0170 
0171         QPointer<QObject> that(q);
0172 
0173         KMessageBox::detailedError(q->parentWidget(), msg, details, title);
0174 
0175         if (that) {
0176             handleDocument(defaultFeedList);
0177         }
0178         return;
0179     }
0180 
0181     handleDocument(doc);
0182 }
0183 
0184 #include "moc_loadfeedlistcommand.cpp"