File indexing completed on 2024-05-05 03:52:17

0001 /*
0002     SPDX-FileCopyrightText: 2009-2010 Sebastian Trueg <trueg@kde.org>
0003     SPDX-FileCopyrightText: 2013 Vishesh Handa <me@vhanda.in>
0004     SPDX-FileCopyrightText: 2018-2020 Stefan BrĂ¼ns <bruns@kde.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "kio_timeline.h"
0010 #include "timelinetools.h"
0011 #include "query.h"
0012 #include "resultiterator.h"
0013 #include "../common/udstools.h"
0014 #include <sys/stat.h>
0015 
0016 #include <QCoreApplication>
0017 
0018 #include <KUser>
0019 #include <KFormat>
0020 
0021 #include <KLocalizedString>
0022 
0023 using namespace Baloo;
0024 
0025 // Pseudo plugin class to embed meta data
0026 class KIOPluginForMetaData : public QObject
0027 {
0028     Q_OBJECT
0029     Q_PLUGIN_METADATA(IID "org.kde.kio.worker.timeline" FILE "timeline.json")
0030 };
0031 
0032 namespace
0033 {
0034 KIO::UDSEntry createFolderUDSEntry(const QString& name)
0035 {
0036     KIO::UDSEntry uds;
0037     uds.reserve(5);
0038     uds.fastInsert(KIO::UDSEntry::UDS_NAME, name);
0039     uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0040     uds.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory"));
0041 #ifdef Q_OS_WIN
0042     uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, _S_IREAD );
0043 #else
0044     uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IXUSR);
0045 #endif
0046     uds.fastInsert(KIO::UDSEntry::UDS_USER, KUser().loginName());
0047     return uds;
0048 }
0049 
0050 KIO::UDSEntry createDateFolderUDSEntry(const QString& name, const QString& displayName, const QDate& date)
0051 {
0052     KIO::UDSEntry uds;
0053     uds.reserve(8);
0054     QDateTime dt(date, QTime(0, 0, 0));
0055     uds.fastInsert(KIO::UDSEntry::UDS_NAME, name);
0056     uds.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, displayName);
0057     uds.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
0058     uds.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("inode/directory"));
0059     uds.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, dt.toSecsSinceEpoch());
0060     uds.fastInsert(KIO::UDSEntry::UDS_CREATION_TIME, dt.toSecsSinceEpoch());
0061 #ifdef Q_OS_WIN
0062     uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, _S_IREAD );
0063 #else
0064     uds.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IXUSR);
0065 #endif
0066     uds.fastInsert(KIO::UDSEntry::UDS_USER, KUser().loginName());
0067     return uds;
0068 }
0069 
0070 KIO::UDSEntry createMonthUDSEntry(int month, int year)
0071 {
0072     QString dateString = QDate(year, month, 1).toString(
0073                 i18nc("Month and year used in a tree above the actual days. "
0074                       "Have a look at https://doc.qt.io/qt-5/qdate.html#toString "
0075                       "to see which variables you can use and ask kde-i18n-doc@kde.org if you have "
0076                       "problems understanding how to translate this",
0077                       "MMMM yyyy"));
0078     return createDateFolderUDSEntry(QDate(year, month, 1).toString(QStringLiteral("yyyy-MM")),
0079                                 dateString,
0080                                 QDate(year, month, 1));
0081 }
0082 
0083 KIO::UDSEntry createDayUDSEntry(const QDate& date)
0084 {
0085     KIO::UDSEntry uds = createDateFolderUDSEntry(date.toString(QStringLiteral("yyyy-MM-dd")),
0086                         KFormat().formatRelativeDate(date, QLocale::LongFormat),
0087                         date);
0088 
0089     return uds;
0090 }
0091 
0092 }
0093 
0094 TimelineProtocol::TimelineProtocol(const QByteArray& poolSocket, const QByteArray& appSocket)
0095     : KIO::WorkerBase("timeline", poolSocket, appSocket)
0096 {
0097 }
0098 
0099 TimelineProtocol::~TimelineProtocol()
0100 {
0101 }
0102 
0103 KIO::WorkerResult TimelineProtocol::listDir(const QUrl& url)
0104 {
0105     QUrl canonicalUrl = canonicalizeTimelineUrl(url);
0106     if (url != canonicalUrl) {
0107         redirection(canonicalUrl);
0108         return KIO::WorkerResult::pass();
0109     }
0110 
0111     switch (parseTimelineUrl(url, &m_date, &m_filename)) {
0112     case RootFolder:
0113         listEntry(createFolderUDSEntry(QStringLiteral(".")));
0114         listEntry(createDateFolderUDSEntry(QStringLiteral("today"), i18n("Today"), QDate::currentDate()));
0115         listEntry(createDateFolderUDSEntry(QStringLiteral("calendar"), i18n("Calendar"), QDate::currentDate()));
0116         break;
0117 
0118     case CalendarFolder:
0119         listEntry(createFolderUDSEntry(QStringLiteral(".")));
0120         listThisYearsMonths();
0121         // TODO: add entry for previous years
0122         break;
0123 
0124     case MonthFolder:
0125         listEntry(createFolderUDSEntry(QStringLiteral(".")));
0126         listDays(m_date.month(), m_date.year());
0127         break;
0128 
0129     case DayFolder: {
0130         listEntry(createFolderUDSEntry(QStringLiteral(".")));
0131         Query query;
0132         query.setDateFilter(m_date.year(), m_date.month(), m_date.day());
0133         query.setSortingOption(Query::SortNone);
0134 
0135         UdsFactory udsf;
0136 
0137         ResultIterator it = query.exec();
0138         while (it.next()) {
0139             KIO::UDSEntry uds = udsf.createUdsEntry(it.filePath());
0140             if (uds.count()) {
0141                 listEntry(uds);
0142             }
0143         }
0144         break;
0145     }
0146 
0147     case NoFolder:
0148         return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toString());
0149     }
0150 
0151     return KIO::WorkerResult::pass();
0152 }
0153 
0154 KIO::WorkerResult TimelineProtocol::mimetype(const QUrl& url)
0155 {
0156     QUrl canonicalUrl = canonicalizeTimelineUrl(url);
0157     if (url != canonicalUrl) {
0158         redirection(canonicalUrl);
0159         return KIO::WorkerResult::pass();
0160     }
0161 
0162     switch (parseTimelineUrl(url, &m_date, &m_filename)) {
0163     case RootFolder:
0164     case CalendarFolder:
0165     case MonthFolder:
0166     case DayFolder:
0167         mimetype(QUrl(QLatin1String("inode/directory")));
0168         break;
0169 
0170     case NoFolder:
0171         return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toString());
0172     }
0173 
0174     return KIO::WorkerResult::pass();
0175 }
0176 
0177 KIO::WorkerResult TimelineProtocol::stat(const QUrl& url)
0178 {
0179     QUrl canonicalUrl = canonicalizeTimelineUrl(url);
0180     if (url != canonicalUrl) {
0181         redirection(canonicalUrl);
0182         return KIO::WorkerResult::pass();
0183     }
0184 
0185     switch (parseTimelineUrl(url, &m_date, &m_filename)) {
0186     case RootFolder: {
0187         statEntry(createFolderUDSEntry(QStringLiteral("/")));
0188         break;
0189     }
0190 
0191     case CalendarFolder:
0192         statEntry(createDateFolderUDSEntry(QStringLiteral("calendar"), i18n("Calendar"), QDate::currentDate()));
0193         break;
0194 
0195     case MonthFolder:
0196         statEntry(createMonthUDSEntry(m_date.month(), m_date.year()));
0197         break;
0198 
0199     case DayFolder:
0200         if (m_filename.isEmpty()) {
0201             statEntry(createDayUDSEntry(m_date));
0202         }
0203         break;
0204 
0205     case NoFolder:
0206         return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toString());
0207     }
0208 
0209     return KIO::WorkerResult::pass();
0210 }
0211 
0212 void TimelineProtocol::listDays(int month, int year)
0213 {
0214     const int days = QDate(year, month, 1).daysInMonth();
0215     for (int day = 1; day <= days; ++day) {
0216         QDate date(year, month, day);
0217 
0218         if (date <= QDate::currentDate() && filesInDate(date)) {
0219             listEntry(createDayUDSEntry(date));
0220         }
0221     }
0222 }
0223 
0224 bool TimelineProtocol::filesInDate(const QDate& date)
0225 {
0226     Query query;
0227     query.setLimit(1);
0228     query.setDateFilter(date.year(), date.month(), date.day());
0229     query.setSortingOption(Query::SortNone);
0230 
0231     ResultIterator it = query.exec();
0232     return it.next();
0233 }
0234 
0235 void TimelineProtocol::listThisYearsMonths()
0236 {
0237     Query query;
0238     query.setLimit(1);
0239     query.setSortingOption(Query::SortNone);
0240 
0241     int year = QDate::currentDate().year();
0242     int currentMonth = QDate::currentDate().month();
0243     for (int month = 1; month <= currentMonth; ++month) {
0244         query.setDateFilter(year, month);
0245         ResultIterator it = query.exec();
0246         if (it.next()) {
0247             listEntry(createMonthUDSEntry(month, year));
0248         }
0249     }
0250 }
0251 
0252 extern "C"
0253 {
0254     Q_DECL_EXPORT int kdemain(int argc, char** argv)
0255     {
0256         QCoreApplication app(argc, argv);
0257         app.setApplicationName(QStringLiteral("kio_timeline"));
0258         Baloo::TimelineProtocol worker(argv[2], argv[3]);
0259         worker.dispatchLoop();
0260         return 0;
0261     }
0262 }
0263 
0264 #include "kio_timeline.moc"