File indexing completed on 2024-05-12 05:10:35

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 #include "calendarjanitor.h"
0009 #include "options.h"
0010 
0011 #include "console-version.h"
0012 
0013 #include <KAboutData>
0014 #include <KLocalizedString>
0015 
0016 #include <QCommandLineOption>
0017 #include <QCommandLineParser>
0018 #include <QCoreApplication>
0019 #include <QString>
0020 #include <QTextStream>
0021 #include <qglobal.h>
0022 
0023 #ifdef Q_OS_UNIX
0024 #include <fcntl.h>
0025 #include <sys/stat.h>
0026 #include <sys/types.h>
0027 #include <unistd.h>
0028 #endif
0029 
0030 #ifndef COMPILE_WITH_UNITY_CMAKE_SUPPORT
0031 static void printOut(const QString &message)
0032 {
0033     QTextStream out(stdout);
0034     out << message << "\n";
0035 }
0036 #endif
0037 
0038 static void printCollectionsUsage()
0039 {
0040     printOut(i18n("Error while parsing %1", QStringLiteral("--collections")));
0041     printOut(i18n("Example usage: %1", QStringLiteral("--collections 90,23,40")));
0042 }
0043 
0044 static void silenceStderr()
0045 {
0046 #ifdef Q_OS_UNIX
0047     if (qgetenv("KDE_CALENDARJANITOR_DEBUG") != "1") {
0048         // krazy:cond=syscalls since UNIX-only code
0049         // Disable stderr so we can actually read what's going on
0050         int fd = ::open("/dev/null", O_WRONLY);
0051         ::dup2(fd, 2);
0052         ::close(fd);
0053         // krazy:endcond=syscalls
0054     }
0055 #endif
0056 }
0057 
0058 int main(int argv, char *argc[])
0059 {
0060     KLocalizedString::setApplicationDomain(QByteArrayLiteral("calendarjanitor"));
0061     KAboutData aboutData(QStringLiteral("calendarjanitor"), i18n("CalendarJanitor"), QStringLiteral(KDEPIM_VERSION));
0062     aboutData.setLicense(KAboutLicense::GPL_V2, KAboutLicense::OrLaterVersions);
0063     aboutData.addAuthor(i18n("Sérgio Martins"), i18n("Maintainer"), QStringLiteral("iamsergiogmail.com"));
0064     aboutData.setShortDescription(i18n("A command line interface to report and fix errors in your calendar data"));
0065 
0066     QCoreApplication app(argv, argc);
0067 
0068     QCommandLineParser parser;
0069     QCommandLineOption colsOpt(QStringLiteral("collections"), i18n("Comma-separated list of collection ids to scan"), QStringLiteral("ids"));
0070     QCommandLineOption fixOpt(QStringLiteral("fix"), i18n("Fix broken incidences"));
0071     QCommandLineOption backupOpt(QStringLiteral("backup"), i18n("Backup your calendar"), QStringLiteral("output.ics"));
0072     QCommandLineOption stripOldAlarmsOpt(QStringLiteral("strip-old-alarms"), i18n("Delete alarms older than 365 days"));
0073     parser.addOptions({colsOpt, fixOpt, backupOpt, stripOldAlarmsOpt});
0074     aboutData.setupCommandLine(&parser);
0075 
0076     parser.process(app);
0077     aboutData.processCommandLine(&parser);
0078 
0079     Options janitorOptions;
0080     if (parser.isSet(colsOpt)) {
0081         QString option = parser.value(colsOpt);
0082         const QStringList collections = option.split(QLatin1Char(','));
0083         QList<Akonadi::Collection::Id> ids;
0084         for (const QString &collection : collections) {
0085             bool ok = false;
0086             int num = collection.toInt(&ok);
0087             if (ok) {
0088                 ids << num;
0089             } else {
0090                 printCollectionsUsage();
0091                 return -1;
0092             }
0093 
0094             if (ids.isEmpty()) {
0095                 printCollectionsUsage();
0096                 return -1;
0097             } else {
0098                 janitorOptions.setCollections(ids);
0099             }
0100         }
0101     }
0102 
0103     if (parser.isSet(fixOpt) && parser.isSet(backupOpt)) {
0104         printOut(i18n("--fix is incompatible with --backup"));
0105         return -1;
0106     }
0107 
0108     if (parser.isSet(stripOldAlarmsOpt) && parser.isSet(backupOpt)) {
0109         printOut(i18n("--strip-old-alarms is incompatible with --backup"));
0110         return -1;
0111     }
0112 
0113     if (parser.isSet(stripOldAlarmsOpt) && parser.isSet(fixOpt)) {
0114         printOut(i18n("--strip-old-alarms is incompatible with --fix"));
0115         return -1;
0116     }
0117 
0118     silenceStderr(); // Switching off mobile phones, movie is about to start
0119 
0120     janitorOptions.setStripOldAlarms(parser.isSet(stripOldAlarmsOpt));
0121 
0122     QString backupFile;
0123     if (parser.isSet(fixOpt)) {
0124         janitorOptions.setAction(Options::ActionScanAndFix);
0125         printOut(i18n("Running in fix mode."));
0126     } else if (parser.isSet(backupOpt)) {
0127         backupFile = parser.value(backupOpt);
0128         if (backupFile.isEmpty()) {
0129             printOut(i18n("Please specify a output file."));
0130             return -1;
0131         }
0132         janitorOptions.setAction(Options::ActionBackup);
0133     } else {
0134         printOut(i18n("Running in scan only mode."));
0135         janitorOptions.setAction(Options::ActionScan);
0136     }
0137 
0138     switch (janitorOptions.action()) {
0139     case Options::ActionBackup: {
0140         auto backuper = new Backuper();
0141         backuper->backup(backupFile, janitorOptions.collections());
0142         break;
0143     }
0144     case Options::ActionScan:
0145     case Options::ActionScanAndFix: {
0146         auto janitor = new CalendarJanitor(janitorOptions);
0147         janitor->start();
0148         break;
0149     }
0150     default:
0151         Q_ASSERT(false);
0152     }
0153 
0154     return app.exec();
0155 }