File indexing completed on 2024-12-22 04:56:53
0001 /* 0002 SPDX-FileCopyrightText: 2006 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "akonadiworker.h" 0008 0009 #include <Akonadi/Collection> 0010 #include <Akonadi/CollectionDeleteJob> 0011 #include <Akonadi/CollectionFetchJob> 0012 #include <Akonadi/EntityDisplayAttribute> 0013 #include <Akonadi/ItemDeleteJob> 0014 #include <Akonadi/ItemFetchJob> 0015 #include <Akonadi/ItemFetchScope> 0016 0017 #include "akonadiworker_debug.h" 0018 0019 #include <KAboutData> 0020 #include <KLocalizedString> 0021 #include <QApplication> 0022 #include <QCommandLineOption> 0023 #include <QCommandLineParser> 0024 0025 #ifdef Q_OS_WIN 0026 // see kio/core/src/kioglobal_p.h 0027 #define S_IRUSR 0400 0028 #define S_IRGRP 0040 0029 #define S_IROTH 0004 0030 #endif 0031 0032 // Pseudo plugin class to embed meta data 0033 class KIOPluginForMetaData : public QObject 0034 { 0035 Q_OBJECT 0036 Q_PLUGIN_METADATA(IID "org.kde.kio.worker.akonadi" FILE "akonadi.json") 0037 }; 0038 0039 extern "C" { 0040 int Q_DECL_EXPORT kdemain(int argc, char **argv); 0041 } 0042 0043 int kdemain(int argc, char **argv) 0044 { 0045 QApplication app(argc, argv); 0046 KAboutData aboutData(QStringLiteral("kio_akonadi"), QString(), QStringLiteral("0")); 0047 QCommandLineParser parser; 0048 KAboutData::setApplicationData(aboutData); 0049 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("+protocol"), i18n("Protocol name"))); 0050 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("+pool"), i18n("Socket name"))); 0051 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("+app"), i18n("Socket name"))); 0052 0053 aboutData.setupCommandLine(&parser); 0054 parser.process(app); 0055 aboutData.processCommandLine(&parser); 0056 0057 AkonadiWorker worker(parser.positionalArguments().at(1).toLocal8Bit(), parser.positionalArguments().at(2).toLocal8Bit()); 0058 worker.dispatchLoop(); 0059 0060 return 0; 0061 } 0062 0063 using namespace Akonadi; 0064 0065 AkonadiWorker::AkonadiWorker(const QByteArray &pool_socket, const QByteArray &app_socket) 0066 : KIO::WorkerBase("akonadi", pool_socket, app_socket) 0067 { 0068 qCDebug(AKONADIWORKER_LOG) << "kio_akonadi starting up"; 0069 } 0070 0071 AkonadiWorker::~AkonadiWorker() 0072 { 0073 qCDebug(AKONADIWORKER_LOG) << "kio_akonadi shutting down"; 0074 } 0075 0076 KIO::WorkerResult AkonadiWorker::get(const QUrl &url) 0077 { 0078 const Item item = Item::fromUrl(url); 0079 auto job = new ItemFetchJob(item); 0080 job->fetchScope().fetchFullPayload(); 0081 0082 if (!job->exec()) { 0083 return KIO::WorkerResult::fail(KIO::ERR_INTERNAL, job->errorString()); 0084 } 0085 0086 if (job->items().count() != 1) { 0087 return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, i18n("No such item.")); 0088 } else { 0089 const Item itemJob = job->items().at(0); 0090 const QByteArray tmp = itemJob.payloadData(); 0091 data(tmp); 0092 data(QByteArray()); 0093 return KIO::WorkerResult::pass(); 0094 } 0095 } 0096 0097 KIO::WorkerResult AkonadiWorker::stat(const QUrl &url) 0098 { 0099 qCDebug(AKONADIWORKER_LOG) << url; 0100 0101 // Stats for a collection 0102 if (Collection::fromUrl(url).isValid()) { 0103 Collection collection = Collection::fromUrl(url); 0104 0105 if (collection != Collection::root()) { 0106 // Check that the collection exists. 0107 auto job = new CollectionFetchJob(collection, CollectionFetchJob::Base); 0108 if (!job->exec()) { 0109 return KIO::WorkerResult::fail(KIO::ERR_INTERNAL, job->errorString()); 0110 } 0111 0112 if (job->collections().count() != 1) { 0113 return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, i18n("No such item.")); 0114 } 0115 0116 collection = job->collections().at(0); 0117 } 0118 0119 statEntry(entryForCollection(collection)); 0120 return KIO::WorkerResult::pass(); 0121 } 0122 // Stats for an item 0123 else if (Item::fromUrl(url).isValid()) { 0124 auto job = new ItemFetchJob(Item::fromUrl(url)); 0125 0126 if (!job->exec()) { 0127 return KIO::WorkerResult::fail(KIO::ERR_INTERNAL, job->errorString()); 0128 } 0129 0130 if (job->items().count() != 1) { 0131 return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, i18n("No such item.")); 0132 } 0133 0134 const Item item = job->items().at(0); 0135 statEntry(entryForItem(item)); 0136 return KIO::WorkerResult::pass(); 0137 } 0138 return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toString()); 0139 } 0140 0141 KIO::WorkerResult AkonadiWorker::del(const QUrl &url, bool isFile) 0142 { 0143 qCDebug(AKONADIWORKER_LOG) << url; 0144 0145 if (!isFile) { // It's a directory 0146 Collection collection = Collection::fromUrl(url); 0147 auto job = new CollectionDeleteJob(collection); 0148 if (!job->exec()) { 0149 return KIO::WorkerResult::fail(KIO::ERR_INTERNAL, job->errorString()); 0150 } 0151 return KIO::WorkerResult::pass(); 0152 } else { // It's a file 0153 auto job = new ItemDeleteJob(Item::fromUrl(url)); 0154 if (!job->exec()) { 0155 return KIO::WorkerResult::fail(KIO::ERR_INTERNAL, job->errorString()); 0156 } 0157 return KIO::WorkerResult::pass(); 0158 } 0159 } 0160 0161 KIO::WorkerResult AkonadiWorker::listDir(const QUrl &url) 0162 { 0163 qCDebug(AKONADIWORKER_LOG) << url; 0164 0165 if (!Collection::fromUrl(url).isValid()) { 0166 return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, i18n("No such collection.")); 0167 } 0168 0169 // Fetching collections 0170 Collection collection = Collection::fromUrl(url); 0171 if (!collection.isValid()) { 0172 return KIO::WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, i18n("No such collection.")); 0173 } 0174 auto job = new CollectionFetchJob(collection, CollectionFetchJob::FirstLevel); 0175 if (!job->exec()) { 0176 return KIO::WorkerResult::fail(KIO::ERR_CANNOT_ENTER_DIRECTORY, job->errorString()); 0177 } 0178 0179 const Collection::List collections = job->collections(); 0180 for (const Collection &col : collections) { 0181 listEntry(entryForCollection(col)); 0182 } 0183 0184 // Fetching items 0185 if (collection != Collection::root()) { 0186 auto fjob = new ItemFetchJob(collection); 0187 if (!fjob->exec()) { 0188 return KIO::WorkerResult::fail(KIO::ERR_INTERNAL, job->errorString()); 0189 } 0190 const Item::List items = fjob->items(); 0191 totalSize(collections.count() + items.count()); 0192 for (const Item &item : items) { 0193 listEntry(entryForItem(item)); 0194 } 0195 } 0196 0197 return KIO::WorkerResult::pass(); 0198 } 0199 0200 KIO::UDSEntry AkonadiWorker::entryForItem(const Akonadi::Item &item) 0201 { 0202 KIO::UDSEntry entry; 0203 entry.reserve(7); 0204 entry.fastInsert(KIO::UDSEntry::UDS_NAME, QString::number(item.id())); 0205 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, item.mimeType()); 0206 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); 0207 entry.fastInsert(KIO::UDSEntry::UDS_URL, item.url().url()); 0208 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, item.size()); 0209 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH); 0210 entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, item.modificationTime().toSecsSinceEpoch()); 0211 return entry; 0212 } 0213 0214 KIO::UDSEntry AkonadiWorker::entryForCollection(const Akonadi::Collection &collection) 0215 { 0216 KIO::UDSEntry entry; 0217 entry.reserve(7); 0218 entry.fastInsert(KIO::UDSEntry::UDS_NAME, collection.name()); 0219 entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, Collection::mimeType()); 0220 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0221 entry.fastInsert(KIO::UDSEntry::UDS_URL, collection.url().url()); 0222 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH); 0223 if (const auto attr = collection.attribute<EntityDisplayAttribute>()) { 0224 if (!attr->iconName().isEmpty()) { 0225 entry.fastInsert(KIO::UDSEntry::UDS_ICON_NAME, attr->iconName()); 0226 } 0227 if (!attr->displayName().isEmpty()) { 0228 entry.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, attr->displayName()); 0229 } 0230 } 0231 return entry; 0232 } 0233 0234 #include "akonadiworker.moc"