File indexing completed on 2024-05-26 04:37:15
0001 /* SPDX-License-Identifier: LGPL-2.0-or-later 0002 */ 0003 0004 #include <stdio.h> 0005 #include <stdlib.h> 0006 #include <sys/stat.h> 0007 0008 #include "kio_mits_debug.h" 0009 #include <QCoreApplication> 0010 #include <QMimeDatabase> 0011 #include <QMimeType> 0012 0013 #include <QBitArray> 0014 #include <QDir> 0015 #include <QFile> 0016 #include <QVector> 0017 0018 #include "libchmurlfactory.h" 0019 #include "msits.h" 0020 0021 using namespace KIO; 0022 0023 // Pseudo plugin class to embed meta data 0024 class KIOPluginForMetaData : public QObject 0025 { 0026 Q_OBJECT 0027 Q_PLUGIN_METADATA(IID "org.kde.kio.slave.ms-its.json" FILE "ms-its.json") 0028 }; 0029 0030 extern "C" { 0031 int Q_DECL_EXPORT kdemain(int argc, char **argv) 0032 { 0033 qCDebug(KIO_MITS_LOG) << "*** kio_msits Init"; 0034 0035 QCoreApplication app(argc, argv); 0036 app.setApplicationName(QStringLiteral("kio_msits")); 0037 0038 if (argc != 4) { 0039 qCDebug(KIO_MITS_LOG) << "Usage: kio_msits protocol domain-socket1 domain-socket2"; 0040 exit(-1); 0041 } 0042 0043 ProtocolMSITS slave(argv[2], argv[3]); 0044 slave.dispatchLoop(); 0045 0046 qCDebug(KIO_MITS_LOG) << "*** kio_msits Done"; 0047 return 0; 0048 } 0049 } 0050 0051 ProtocolMSITS::ProtocolMSITS(const QByteArray &pool_socket, const QByteArray &app_socket) 0052 : SlaveBase("kio_msits", pool_socket, app_socket) 0053 { 0054 m_chmFile = nullptr; 0055 } 0056 0057 ProtocolMSITS::~ProtocolMSITS() 0058 { 0059 if (!m_chmFile) { 0060 return; 0061 } 0062 0063 chm_close(m_chmFile); 0064 m_chmFile = nullptr; 0065 } 0066 0067 // A simple stat() wrapper 0068 static bool isDirectory(const QString &filename) 0069 { 0070 return filename.endsWith(QLatin1Char('/')); 0071 } 0072 0073 void ProtocolMSITS::get(const QUrl &url) 0074 { 0075 QString htmdata, fileName; 0076 chmUnitInfo ui; 0077 QByteArray buf; 0078 0079 qCDebug(KIO_MITS_LOG) << "kio_msits::get() " << url.path(); 0080 0081 if (!parseLoadAndLookup(url, fileName)) { 0082 return; // error() has been called by parseLoadAndLookup 0083 } 0084 0085 qCDebug(KIO_MITS_LOG) << "kio_msits::get: parseLoadAndLookup returned " << fileName; 0086 0087 if (LCHMUrlFactory::handleFileType(url.path(), htmdata)) { 0088 buf = htmdata.toUtf8(); 0089 qCDebug(KIO_MITS_LOG) << "Using special handling for image pages: " << htmdata; 0090 } else { 0091 if (isDirectory(fileName)) { 0092 error(KIO::ERR_IS_DIRECTORY, url.toString()); 0093 return; 0094 } 0095 0096 if (!ResolveObject(fileName, &ui)) { 0097 qCDebug(KIO_MITS_LOG) << "kio_msits::get: could not resolve filename " << fileName; 0098 error(KIO::ERR_DOES_NOT_EXIST, url.toString()); 0099 return; 0100 } 0101 0102 buf.resize(ui.length); 0103 0104 if (RetrieveObject(&ui, (unsigned char *)buf.data(), 0, ui.length) == 0) { 0105 qCDebug(KIO_MITS_LOG) << "kio_msits::get: could not retrieve filename " << fileName; 0106 error(KIO::ERR_NO_CONTENT, url.toString()); 0107 return; 0108 } 0109 } 0110 0111 totalSize(buf.size()); 0112 0113 QMimeDatabase db; 0114 QMimeType result = db.mimeTypeForFileNameAndData(fileName, buf); 0115 qCDebug(KIO_MITS_LOG) << "Emitting mimetype " << result.name(); 0116 0117 mimeType(result.name()); 0118 0119 data(buf); 0120 processedSize(buf.size()); 0121 0122 finished(); 0123 } 0124 0125 bool ProtocolMSITS::parseLoadAndLookup(const QUrl &url, QString &abspath) 0126 { 0127 qCDebug(KIO_MITS_LOG) << "ProtocolMSITS::parseLoadAndLookup (const KUrl&) " << url.path(); 0128 0129 int pos = url.path().indexOf(QStringLiteral("::")); 0130 0131 if (pos == -1) { 0132 error(KIO::ERR_MALFORMED_URL, url.toString()); 0133 return false; 0134 } 0135 0136 QString filename = url.path().left(pos); 0137 abspath = url.path().mid(pos + 2); // skip :: 0138 0139 // Some buggy apps add ms-its:/ to the path as well 0140 if (abspath.startsWith(QLatin1String("ms-its:"))) { 0141 abspath = abspath.mid(7); 0142 } 0143 0144 qCDebug(KIO_MITS_LOG) << "ProtocolMSITS::parseLoadAndLookup: filename " << filename << ", path " << abspath; 0145 0146 if (filename.isEmpty()) { 0147 error(KIO::ERR_MALFORMED_URL, url.toString()); 0148 return false; 0149 } 0150 0151 // If the file has been already loaded, nothing to do. 0152 if (m_chmFile && filename == m_openedFile) { 0153 return true; 0154 } 0155 0156 qCDebug(KIO_MITS_LOG) << "Opening a new CHM file " << QFile::encodeName(QDir::toNativeSeparators(filename)); 0157 0158 // First try to open a temporary file 0159 chmFile *tmpchm; 0160 0161 if ((tmpchm = chm_open(QFile::encodeName(QDir::toNativeSeparators(filename)).constData())) == nullptr) { 0162 error(KIO::ERR_CANNOT_READ, url.toString()); 0163 return false; 0164 } 0165 0166 // Replace an existing file by a new one 0167 if (m_chmFile) { 0168 chm_close(m_chmFile); 0169 } 0170 0171 m_chmFile = tmpchm; 0172 m_openedFile = filename; 0173 0174 qCDebug(KIO_MITS_LOG) << "A CHM file " << filename << " has beed opened successfully"; 0175 return true; 0176 } 0177 0178 /* 0179 * Shamelessly stolen from a KDE KIO tutorial 0180 */ 0181 static void app_entry(UDSEntry &e, unsigned int uds, const QString &str) 0182 { 0183 e.fastInsert(uds, str); 0184 } 0185 0186 // appends an int with the UDS-ID uds 0187 static void app_entry(UDSEntry &e, unsigned int uds, long l) 0188 { 0189 e.fastInsert(uds, l); 0190 } 0191 0192 // internal function 0193 // fills a directory item with its name and size 0194 static void app_dir(UDSEntry &e, const QString &name) 0195 { 0196 e.clear(); 0197 app_entry(e, KIO::UDSEntry::UDS_NAME, name); 0198 app_entry(e, KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); 0199 app_entry(e, KIO::UDSEntry::UDS_SIZE, 1); 0200 } 0201 0202 // internal function 0203 // fills a file item with its name and size 0204 static void app_file(UDSEntry &e, const QString &name, size_t size) 0205 { 0206 e.clear(); 0207 app_entry(e, KIO::UDSEntry::UDS_NAME, name); 0208 app_entry(e, KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG); 0209 app_entry(e, KIO::UDSEntry::UDS_SIZE, size); 0210 } 0211 0212 void ProtocolMSITS::stat(const QUrl &url) 0213 { 0214 QString fileName; 0215 chmUnitInfo ui; 0216 0217 qCDebug(KIO_MITS_LOG) << "kio_msits::stat (const KUrl& url) " << url.path(); 0218 0219 if (!parseLoadAndLookup(url, fileName)) { 0220 return; // error() has been called by parseLoadAndLookup 0221 } 0222 0223 if (!ResolveObject(fileName, &ui)) { 0224 error(KIO::ERR_DOES_NOT_EXIST, url.toString()); 0225 return; 0226 } 0227 0228 qCDebug(KIO_MITS_LOG) << "kio_msits::stat: adding an entry for " << fileName; 0229 UDSEntry entry; 0230 0231 if (isDirectory(fileName)) { 0232 app_dir(entry, fileName); 0233 } else { 0234 app_file(entry, fileName, ui.length); 0235 } 0236 0237 statEntry(entry); 0238 0239 finished(); 0240 } 0241 0242 // A local CHMLIB enumerator 0243 static int chmlib_enumerator(struct chmFile *, struct chmUnitInfo *ui, void *context) 0244 { 0245 ((QVector<QString> *)context)->push_back(QString::fromLocal8Bit(ui->path)); 0246 return CHM_ENUMERATOR_CONTINUE; 0247 } 0248 0249 void ProtocolMSITS::listDir(const QUrl &url) 0250 { 0251 QString filepath; 0252 0253 qCDebug(KIO_MITS_LOG) << "kio_msits::listDir (const KUrl& url) " << url.path(); 0254 0255 if (!parseLoadAndLookup(url, filepath)) { 0256 return; // error() has been called by parseLoadAndLookup 0257 } 0258 0259 filepath += QLatin1Char('/'); 0260 0261 if (!isDirectory(filepath)) { 0262 error(KIO::ERR_CANNOT_ENTER_DIRECTORY, url.path()); 0263 return; 0264 } 0265 0266 qCDebug(KIO_MITS_LOG) << "kio_msits::listDir: enumerating directory " << filepath; 0267 0268 QVector<QString> listing; 0269 0270 if (chm_enumerate_dir(m_chmFile, filepath.toLocal8Bit().constData(), CHM_ENUMERATE_NORMAL | CHM_ENUMERATE_FILES | CHM_ENUMERATE_DIRS, chmlib_enumerator, &listing) != 1) { 0271 error(KIO::ERR_CANNOT_ENTER_DIRECTORY, url.path()); 0272 return; 0273 } 0274 0275 UDSEntry entry; 0276 int striplength = filepath.length(); 0277 0278 for (const QString &iListing : std::as_const(listing)) { 0279 // Strip the directory name 0280 const QString ename = iListing.mid(striplength); 0281 0282 if (isDirectory(ename)) { 0283 app_dir(entry, ename); 0284 } else { 0285 app_file(entry, ename, 0); 0286 } 0287 } 0288 0289 finished(); 0290 } 0291 0292 #include "msits.moc"