File indexing completed on 2024-04-21 16:32:41
0001 /* 0002 SPDX-FileCopyrightText: 2001 Shie Erlich <krusader@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2001 Rafi Yanai <krusader@users.sourceforge.net> 0004 SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "krarchandler.h" 0010 0011 // QtCore 0012 #include <QDebug> 0013 #include <QDir> 0014 #include <QFile> 0015 // QtWidgets 0016 #include <QApplication> 0017 0018 #include <KConfigCore/KSharedConfig> 0019 #include <KI18n/KLocalizedString> 0020 #include <KIO/Global> 0021 #include <KIOCore/KProtocolManager> 0022 #include <KWallet/KWallet> 0023 #include <KWidgetsAddons/KMessageBox> 0024 #include <KWidgetsAddons/KPasswordDialog> 0025 #include <utility> 0026 0027 #include "../../plugins/krarc/krlinecountingprocess.h" 0028 #include "../Dialogs/krpleasewait.h" 0029 #include "../defaults.h" 0030 #include "../krglobal.h" 0031 #include "../krservices.h" 0032 #include "kr7zencryptionchecker.h" 0033 0034 static QStringList arcProtocols = QString("tar;bzip;bzip2;lzma;xz;gzip;krarc;zip").split(';'); 0035 0036 QMap<QString, QString> *KrArcHandler::slaveMap = nullptr; 0037 KWallet::Wallet *KrArcHandler::wallet = nullptr; 0038 0039 KrArcHandler::KrArcHandler(QObject *parent) 0040 : QObject(parent) 0041 { 0042 // Reminder: If a mime type is added/removed/modified in that 0043 // member function, it's important to research if the type has to 0044 // be added/removed/modified in the `krarc.protocol` file, or 0045 // in `KrArcBaseManager::getShortTypeFromMime(const QString &mime)` 0046 0047 // Hard-code these proven mimetypes openable by krarc protocol. 0048 // They cannot be listed in krarc.protocol itself 0049 // because it would baffle other file managers (like Dolphin). 0050 krarcArchiveMimetypes = { 0051 QStringLiteral("application/x-deb"), 0052 QStringLiteral("application/x-debian-package"), 0053 QStringLiteral("application/vnd.debian.binary-package"), 0054 QStringLiteral("application/x-java-archive"), 0055 QStringLiteral("application/x-rpm"), 0056 QStringLiteral("application/x-source-rpm"), 0057 QStringLiteral("application/vnd.oasis.opendocument.chart"), 0058 QStringLiteral("application/vnd.oasis.opendocument.database"), 0059 QStringLiteral("application/vnd.oasis.opendocument.formula"), 0060 QStringLiteral("application/vnd.oasis.opendocument.graphics"), 0061 QStringLiteral("application/vnd.oasis.opendocument.presentation"), 0062 QStringLiteral("application/vnd.oasis.opendocument.spreadsheet"), 0063 QStringLiteral("application/vnd.oasis.opendocument.text"), 0064 QStringLiteral("application/vnd.openxmlformats-officedocument.presentationml.presentation"), 0065 QStringLiteral("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"), 0066 QStringLiteral("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), 0067 QStringLiteral("application/x-cbz"), 0068 QStringLiteral("application/vnd.comicbook+zip"), 0069 QStringLiteral("application/x-cbr"), 0070 QStringLiteral("application/vnd.comicbook-rar"), 0071 QStringLiteral("application/epub+zip"), 0072 QStringLiteral("application/x-webarchive"), 0073 QStringLiteral("application/x-plasma"), 0074 QStringLiteral("application/vnd.rar"), 0075 }; 0076 0077 #ifdef KRARC_QUERY_ENABLED 0078 const auto mimetypes = KProtocolInfo::archiveMimetypes("krarc"); 0079 for (const auto &mimetype : mimetypes) 0080 krarcArchiveMimetypes.insert(mimetype); 0081 #endif 0082 } 0083 0084 QStringList KrArcHandler::supportedPackers() 0085 { 0086 QStringList packers; 0087 0088 // we will simply try to find the packers here.. 0089 if (KrServices::cmdExist("tar")) 0090 packers.append("tar"); 0091 if (KrServices::cmdExist("gzip")) 0092 packers.append("gzip"); 0093 if (KrServices::cmdExist("bzip2")) 0094 packers.append("bzip2"); 0095 if (KrServices::cmdExist("lzma")) 0096 packers.append("lzma"); 0097 if (KrServices::cmdExist("xz")) 0098 packers.append("xz"); 0099 if (KrServices::cmdExist("unzip")) 0100 packers.append("unzip"); 0101 if (KrServices::cmdExist("zip")) 0102 packers.append("zip"); 0103 if (KrServices::cmdExist("zip")) 0104 packers.append("cbz"); 0105 if (KrServices::cmdExist("lha")) 0106 packers.append("lha"); 0107 if (KrServices::cmdExist("cpio")) 0108 packers.append("cpio"); 0109 if (KrServices::cmdExist("unrar")) 0110 packers.append("unrar"); 0111 if (KrServices::cmdExist("rar")) 0112 packers.append("rar"); 0113 if (KrServices::cmdExist("rar")) 0114 packers.append("cbr"); 0115 if (KrServices::cmdExist("arj")) 0116 packers.append("arj"); 0117 if (KrServices::cmdExist("unarj")) 0118 packers.append("unarj"); 0119 if (KrServices::cmdExist("unace")) 0120 packers.append("unace"); 0121 if (KrServices::cmdExist("dpkg")) 0122 packers.append("dpkg"); 0123 if (KrServices::cmdExist("7z") || KrServices::cmdExist("7za")) 0124 packers.append("7z"); 0125 if (KrServices::cmdExist("rpm") && KrServices::cmdExist("rpm2cpio")) 0126 packers.append("rpm"); 0127 // qDebug() << "Supported Packers:"; 0128 // QStringList::Iterator it; 0129 // for( it = packers.begin(); it != packers.end(); ++it ) 0130 // qDebug() << *it; 0131 0132 return packers; 0133 } 0134 0135 bool KrArcHandler::arcSupported(QString type) 0136 { 0137 // lst will contain the supported unpacker list... 0138 const KConfigGroup group(krConfig, "Archives"); 0139 const QStringList lst = group.readEntry("Supported Packers", QStringList()); 0140 0141 // Let's notice that in some cases the QString `type` that arrives here 0142 // represents a mimetype, and in some other cases it represents 0143 // a short identifier. 0144 // If `type` is not a short identifier then it's supposed that `type` is a mime type 0145 if (type.length() > maxLenType) { 0146 type = getShortTypeFromMime(type); 0147 } 0148 0149 // clang-format off 0150 return (type == "zip" && lst.contains("unzip")) 0151 || (type == "tar" && lst.contains("tar")) 0152 || (type == "tbz" && lst.contains("tar")) 0153 || (type == "tgz" && lst.contains("tar")) 0154 || (type == "tlz" && lst.contains("tar")) 0155 || (type == "txz" && lst.contains("tar")) 0156 || (type == "tarz" && lst.contains("tar")) 0157 || (type == "gzip" && lst.contains("gzip")) 0158 || (type == "bzip2" && lst.contains("bzip2")) 0159 || (type == "lzma" && lst.contains("lzma")) 0160 || (type == "xz" && lst.contains("xz")) 0161 || (type == "lha" && lst.contains("lha")) 0162 || (type == "ace" && lst.contains("unace")) 0163 || (type == "rpm" && lst.contains("cpio")) 0164 || (type == "cpio" && lst.contains("cpio")) 0165 || (type == "rar" && (lst.contains("unrar") || lst.contains("rar"))) 0166 || (type == "arj" && (lst.contains("unarj") || lst.contains("arj"))) 0167 || (type == "deb" && (lst.contains("dpkg") && lst.contains("tar"))) 0168 || (type == "7z" && lst.contains("7z")); 0169 // clang-format on 0170 } 0171 0172 qulonglong KrArcHandler::arcFileCount(const QString &archive, const QString &type, const QString &password, KrArcObserver *observer) 0173 { 0174 int divideWith = 1; 0175 0176 // first check if supported 0177 if (!arcSupported(type)) 0178 return 0; 0179 0180 // bzip2, gzip, etc. archives contain only one file 0181 if (type == "bzip2" || type == "gzip" || type == "lzma" || type == "xz") 0182 return 1L; 0183 0184 // set the right lister to do the job 0185 QStringList lister; 0186 0187 if (type == "zip") 0188 lister << KrServices::fullPathName("unzip") << "-ZTs"; 0189 else if (type == "tar") 0190 lister << KrServices::fullPathName("tar") << "-tvf"; 0191 else if (type == "tgz") 0192 lister << KrServices::fullPathName("tar") << "-tvzf"; 0193 else if (type == "tarz") 0194 lister << KrServices::fullPathName("tar") << "-tvzf"; 0195 else if (type == "tbz") 0196 lister << KrServices::fullPathName("tar") << "-tjvf"; 0197 else if (type == "tlz") 0198 lister << KrServices::fullPathName("tar") << "--lzma" 0199 << "-tvf"; 0200 else if (type == "txz") 0201 lister << KrServices::fullPathName("tar") << "--xz" 0202 << "-tvf"; 0203 else if (type == "lha") 0204 lister << KrServices::fullPathName("lha") << "l"; 0205 else if (type == "rar") 0206 lister << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "l" 0207 << "-v"; 0208 else if (type == "ace") 0209 lister << KrServices::fullPathName("unace") << "l"; 0210 else if (type == "arj") { 0211 if (KrServices::cmdExist("arj")) { 0212 lister << KrServices::fullPathName("arj") << "v" 0213 << "-y" 0214 << "-v"; 0215 divideWith = 4; 0216 } else { 0217 lister << KrServices::fullPathName("unarj") << "l"; 0218 } 0219 } else if (type == "rpm") 0220 lister << KrServices::fullPathName("rpm") << "--dump" 0221 << "-lpq"; 0222 else if (type == "deb") 0223 lister << KrServices::fullPathName("dpkg") << "-c"; 0224 else if (type == "7z") 0225 lister << find7zExecutable() << "-y" 0226 << "l"; 0227 else 0228 return 0L; 0229 0230 if (!password.isNull()) { 0231 if (type == "arj") 0232 lister << QString("-g%1").arg(password); 0233 if (type == "ace" || type == "rar" || type == "7z") 0234 lister << QString("-p%1").arg(password); 0235 } 0236 0237 // tell the user to wait 0238 observer->subJobStarted(i18n("Counting files in archive"), 0); 0239 0240 // count the number of files in the archive 0241 qulonglong count = 1; 0242 KProcess list; 0243 list << lister << archive; 0244 if (type == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! 0245 list.setStandardInputFile("/dev/ptmx"); 0246 list.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect 0247 list.start(); 0248 // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking 0249 // it would be better to connect to started(), error() and finished() 0250 if (list.waitForStarted()) 0251 while (list.state() == QProcess::Running) { 0252 observer->processEvents(); 0253 if (observer->wasCancelled()) 0254 list.kill(); 0255 }; // busy wait - need to find something better... 0256 0257 observer->subJobStopped(); 0258 0259 if (list.exitStatus() != QProcess::NormalExit || !checkStatus(type, list.exitCode())) { 0260 observer->detailedError(i18n("Failed to list the content of the archive (%1).", archive), QString::fromLocal8Bit(list.readAllStandardError())); 0261 return 0; 0262 } 0263 0264 count = list.readAllStandardOutput().count('\n'); 0265 0266 // make sure you call stopWait after this function return... 0267 // observer->subJobStopped(); 0268 0269 return count / divideWith; 0270 } 0271 0272 bool KrArcHandler::unpack(QString archive, const QString &type, const QString &password, const QString &dest, KrArcObserver *observer) 0273 { 0274 KConfigGroup group(krConfig, "Archives"); 0275 if (group.readEntry("Test Before Unpack", _TestBeforeUnpack)) { 0276 // test first - or be sorry later... 0277 if (type != "rpm" && type != "deb" && !test(archive, type, password, observer, 0)) { 0278 observer->error(i18n("Failed to unpack %1.", archive)); 0279 return false; 0280 } 0281 } 0282 0283 // count the files in the archive 0284 qulonglong count = arcFileCount(archive, type, password, observer); 0285 if (count == 0) 0286 return false; // not supported 0287 if (count == 1) 0288 count = 0; 0289 0290 // choose the right packer for the job 0291 QString cpioName; 0292 QStringList packer; 0293 0294 // set the right packer to do the job 0295 if (type == "zip") 0296 packer << KrServices::fullPathName("unzip") << "-o"; 0297 else if (type == "tar") 0298 packer << KrServices::fullPathName("tar") << "-xvf"; 0299 else if (type == "tgz") 0300 packer << KrServices::fullPathName("tar") << "-xvzf"; 0301 else if (type == "tarz") 0302 packer << KrServices::fullPathName("tar") << "-xvzf"; 0303 else if (type == "tbz") 0304 packer << KrServices::fullPathName("tar") << "-xjvf"; 0305 else if (type == "tlz") 0306 packer << KrServices::fullPathName("tar") << "--lzma" 0307 << "-xvf"; 0308 else if (type == "txz") 0309 packer << KrServices::fullPathName("tar") << "--xz" 0310 << "-xvf"; 0311 else if (type == "gzip") 0312 packer << KrServices::fullPathName("gzip") << "-cd"; 0313 else if (type == "bzip2") 0314 packer << KrServices::fullPathName("bzip2") << "-cdk"; 0315 else if (type == "lzma") 0316 packer << KrServices::fullPathName("lzma") << "-cdk"; 0317 else if (type == "xz") 0318 packer << KrServices::fullPathName("xz") << "-cdk"; 0319 else if (type == "lha") 0320 packer << KrServices::fullPathName("lha") << "xf"; 0321 else if (type == "rar") 0322 packer << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "-y" 0323 << "x"; 0324 else if (type == "ace") 0325 packer << KrServices::fullPathName("unace") << "x"; 0326 else if (type == "arj") { 0327 if (KrServices::cmdExist("arj")) 0328 packer << KrServices::fullPathName("arj") << "-y" 0329 << "-v" 0330 << "x"; 0331 else 0332 packer << KrServices::fullPathName("unarj") << "x"; 0333 } else if (type == "7z") 0334 packer << find7zExecutable() << "-y" 0335 << "x"; 0336 else if (type == "rpm") { 0337 // TODO use QTemporaryFile (setAutoRemove(false) when asynchrone) 0338 cpioName = QDir::tempPath() + QStringLiteral("/contents.cpio"); 0339 0340 KrLinecountingProcess cpio; 0341 cpio << KrServices::fullPathName("rpm2cpio") << archive; 0342 cpio.setStandardOutputFile(cpioName); // TODO maybe no tmpfile but a pipe (setStandardOutputProcess(packer)) 0343 cpio.start(); 0344 if (!cpio.waitForFinished() || cpio.exitStatus() != QProcess::NormalExit || !checkStatus("cpio", cpio.exitCode())) { 0345 observer->detailedError(i18n("Failed to convert rpm (%1) to cpio.", archive), cpio.getErrorMsg()); 0346 return 0; 0347 } 0348 0349 archive = cpioName; 0350 packer << KrServices::fullPathName("cpio") << "--force-local" 0351 << "--no-absolute-filenames" 0352 << "-iuvdF"; 0353 } else if (type == "deb") { 0354 // TODO use QTemporaryFile (setAutoRemove(false) when asynchrone) 0355 cpioName = QDir::tempPath() + QStringLiteral("/contents.tar"); 0356 0357 KrLinecountingProcess dpkg; 0358 dpkg << KrServices::fullPathName("dpkg") << "--fsys-tarfile" << archive; 0359 dpkg.setStandardOutputFile(cpioName); // TODO maybe no tmpfile but a pipe (setStandardOutputProcess(packer)) 0360 dpkg.start(); 0361 if (!dpkg.waitForFinished() || dpkg.exitStatus() != QProcess::NormalExit || !checkStatus("deb", dpkg.exitCode())) { 0362 observer->detailedError(i18n("Failed to convert deb (%1) to tar.", archive), dpkg.getErrorMsg()); 0363 return 0; 0364 } 0365 0366 archive = cpioName; 0367 packer << KrServices::fullPathName("tar") << "xvf"; 0368 } else 0369 return false; 0370 0371 if (!password.isNull()) { 0372 if (type == "zip") 0373 packer << "-P" << password; 0374 if (type == "arj") 0375 packer << QString("-g%1").arg(password); 0376 if (type == "ace" || type == "rar" || type == "7z") 0377 packer << QString("-p%1").arg(password); 0378 } 0379 0380 // unpack the files 0381 KrLinecountingProcess proc; 0382 proc << packer << archive; 0383 if (type == "bzip2" || type == "gzip" || type == "lzma" || type == "xz") { 0384 QString arcname = archive.mid(archive.lastIndexOf("/") + 1); 0385 if (arcname.contains(".")) 0386 arcname = arcname.left(arcname.lastIndexOf(".")); 0387 proc.setStandardOutputFile(dest + '/' + arcname); 0388 } 0389 if (type == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! 0390 proc.setStandardInputFile("/dev/ptmx"); 0391 0392 proc.setWorkingDirectory(dest); 0393 0394 // tell the user to wait 0395 observer->subJobStarted(i18n("Unpacking File(s)"), count); 0396 if (count != 0) { 0397 connect(&proc, &KrLinecountingProcess::newOutputLines, observer, &KrArcObserver::incrementProgress); 0398 if (type == "rpm") 0399 connect(&proc, &KrLinecountingProcess::newErrorLines, observer, &KrArcObserver::incrementProgress); 0400 } 0401 0402 // start the unpacking process 0403 proc.start(); 0404 // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking 0405 // it would be better to connect to started(), error() and finished() 0406 if (proc.waitForStarted()) 0407 while (proc.state() == QProcess::Running) { 0408 observer->processEvents(); 0409 if (observer->wasCancelled()) 0410 proc.kill(); 0411 }; // busy wait - need to find something better... 0412 observer->subJobStopped(); 0413 0414 if (!cpioName.isEmpty()) 0415 QFile(cpioName).remove(); /* remove the cpio file */ 0416 0417 // check the return value 0418 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode())) { 0419 observer->detailedError(i18n("Failed to unpack %1.", archive), observer->wasCancelled() ? i18n("User cancelled.") : proc.getErrorMsg()); 0420 return false; 0421 } 0422 return true; // SUCCESS 0423 } 0424 0425 bool KrArcHandler::test(const QString &archive, const QString &type, const QString &password, KrArcObserver *observer, qulonglong count) 0426 { 0427 // choose the right packer for the job 0428 QStringList packer; 0429 0430 // set the right packer to do the job 0431 if (type == "zip") 0432 packer << KrServices::fullPathName("unzip") << "-t"; 0433 else if (type == "tar") 0434 packer << KrServices::fullPathName("tar") << "-tvf"; 0435 else if (type == "tgz") 0436 packer << KrServices::fullPathName("tar") << "-tvzf"; 0437 else if (type == "tarz") 0438 packer << KrServices::fullPathName("tar") << "-tvzf"; 0439 else if (type == "tbz") 0440 packer << KrServices::fullPathName("tar") << "-tjvf"; 0441 else if (type == "tlz") 0442 packer << KrServices::fullPathName("tar") << "--lzma" 0443 << "-tvf"; 0444 else if (type == "txz") 0445 packer << KrServices::fullPathName("tar") << "--xz" 0446 << "-tvf"; 0447 else if (type == "gzip") 0448 packer << KrServices::fullPathName("gzip") << "-tv"; 0449 else if (type == "bzip2") 0450 packer << KrServices::fullPathName("bzip2") << "-tv"; 0451 else if (type == "lzma") 0452 packer << KrServices::fullPathName("lzma") << "-tv"; 0453 else if (type == "xz") 0454 packer << KrServices::fullPathName("xz") << "-tv"; 0455 else if (type == "rar") 0456 packer << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "t"; 0457 else if (type == "ace") 0458 packer << KrServices::fullPathName("unace") << "t"; 0459 else if (type == "lha") 0460 packer << KrServices::fullPathName("lha") << "t"; 0461 else if (type == "arj") 0462 packer << KrServices::fullPathName(KrServices::cmdExist("arj") ? "arj" : "unarj") << "t"; 0463 else if (type == "cpio") 0464 packer << KrServices::fullPathName("cpio") << "--only-verify-crc" 0465 << "-tvF"; 0466 else if (type == "7z") 0467 packer << find7zExecutable() << "-y" 0468 << "t"; 0469 else 0470 return false; 0471 0472 if (!password.isNull()) { 0473 if (type == "zip") 0474 packer << "-P" << password; 0475 if (type == "arj") 0476 packer << QString("-g%1").arg(password); 0477 if (type == "ace" || type == "rar" || type == "7z") 0478 packer << QString("-p%1").arg(password); 0479 } 0480 0481 // unpack the files 0482 KrLinecountingProcess proc; 0483 proc << packer << archive; 0484 0485 if (type == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! 0486 proc.setStandardInputFile("/dev/ptmx"); 0487 0488 // tell the user to wait 0489 observer->subJobStarted(i18n("Testing Archive"), count); 0490 if (count != 0) 0491 connect(&proc, &KrLinecountingProcess::newOutputLines, observer, &KrArcObserver::incrementProgress); 0492 0493 // start the unpacking process 0494 proc.start(); 0495 // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking 0496 // it would be better to connect to started(), error() and finished() 0497 if (proc.waitForStarted()) 0498 while (proc.state() == QProcess::Running) { 0499 observer->processEvents(); 0500 if (observer->wasCancelled()) 0501 proc.kill(); 0502 }; // busy wait - need to find something better... 0503 observer->subJobStopped(); 0504 0505 // check the return value 0506 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode())) 0507 return false; 0508 0509 return true; // SUCCESS 0510 } 0511 0512 bool KrArcHandler::pack(QStringList fileNames, QString type, const QString &dest, qulonglong count, QMap<QString, QString> extraProps, KrArcObserver *observer) 0513 { 0514 // set the right packer to do the job 0515 QStringList packer; 0516 0517 if (type == "zip") { 0518 packer << KrServices::fullPathName("zip") << "-ry"; 0519 } else if (type == "cbz") { 0520 packer << KrServices::fullPathName("zip") << "-ry"; 0521 type = "zip"; 0522 } else if (type == "tar") { 0523 packer << KrServices::fullPathName("tar") << "-cvf"; 0524 } else if (type == "tar.gz") { 0525 packer << KrServices::fullPathName("tar") << "-cvzf"; 0526 type = "tgz"; 0527 } else if (type == "tar.bz2") { 0528 packer << KrServices::fullPathName("tar") << "-cvjf"; 0529 type = "tbz"; 0530 } else if (type == "tar.lzma") { 0531 packer << KrServices::fullPathName("tar") << "--lzma" 0532 << "-cvf"; 0533 type = "tlz"; 0534 } else if (type == "tar.xz") { 0535 packer << KrServices::fullPathName("tar") << "--xz" 0536 << "-cvf"; 0537 type = "txz"; 0538 } else if (type == "rar") { 0539 packer << KrServices::fullPathName("rar") << "-r" 0540 << "a"; 0541 } else if (type == "cbr") { 0542 packer << KrServices::fullPathName("rar") << "-r" 0543 << "a"; 0544 type = "rar"; 0545 } else if (type == "lha") { 0546 packer << KrServices::fullPathName("lha") << "a"; 0547 } else if (type == "arj") { 0548 packer << KrServices::fullPathName("arj") << "-r" 0549 << "-y" 0550 << "a"; 0551 } else if (type == "7z") { 0552 packer << find7zExecutable() << "-y" 0553 << "a"; 0554 } else 0555 return false; 0556 0557 QString password; 0558 0559 if (extraProps.count("Password") > 0) { 0560 password = extraProps["Password"]; 0561 0562 if (!password.isNull()) { 0563 if (type == "zip") 0564 packer << "-P" << password; 0565 else if (type == "arj") 0566 packer << QString("-g%1").arg(password); 0567 else if (type == "ace" || type == "7z") 0568 packer << QString("-p%1").arg(password); 0569 else if (type == "rar") { 0570 if (extraProps.count("EncryptHeaders") > 0) 0571 packer << QString("-hp%1").arg(password); 0572 else 0573 packer << QString("-p%1").arg(password); 0574 } else 0575 password.clear(); 0576 } 0577 } 0578 0579 if (extraProps.count("VolumeSize") > 0) { 0580 QString sizeStr = extraProps["VolumeSize"]; 0581 KIO::filesize_t size = sizeStr.toLongLong(); 0582 0583 if (size >= 10000) { 0584 if (type == "arj" || type == "rar") 0585 packer << QString("-v%1b").arg(sizeStr); 0586 } 0587 } 0588 0589 if (extraProps.count("CompressionLevel") > 0) { 0590 int level = extraProps["CompressionLevel"].toInt() - 1; 0591 if (level < 0) 0592 level = 0; 0593 if (level > 8) 0594 level = 8; 0595 0596 if (type == "rar") { 0597 static const int rarLevels[] = {0, 1, 2, 2, 3, 3, 4, 4, 5}; 0598 packer << QString("-m%1").arg(rarLevels[level]); 0599 } else if (type == "arj") { 0600 static const int arjLevels[] = {0, 4, 4, 3, 3, 2, 2, 1, 1}; 0601 packer << QString("-m%1").arg(arjLevels[level]); 0602 } else if (type == "zip") { 0603 static const int zipLevels[] = {0, 1, 2, 4, 5, 6, 7, 8, 9}; 0604 packer << QString("-%1").arg(zipLevels[level]); 0605 } else if (type == "7z") { 0606 static const int sevenZipLevels[] = {0, 1, 2, 4, 5, 6, 7, 8, 9}; 0607 packer << QString("-mx%1").arg(sevenZipLevels[level]); 0608 } 0609 } 0610 0611 if (extraProps.count("CommandLineSwitches") > 0) 0612 packer << QString("%1").arg(extraProps["CommandLineSwitches"]); 0613 0614 // prepare to pack 0615 KrLinecountingProcess proc; 0616 proc << packer << dest; 0617 0618 for (auto &fileName : fileNames) { 0619 proc << fileName; 0620 } 0621 0622 // tell the user to wait 0623 observer->subJobStarted(i18n("Packing File(s)"), count); 0624 if (count != 0) 0625 connect(&proc, &KrLinecountingProcess::newOutputLines, observer, &KrArcObserver::incrementProgress); 0626 0627 // start the packing process 0628 proc.start(); 0629 // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking 0630 // it would be better to connect to started(), error() and finished() 0631 if (proc.waitForStarted()) 0632 while (proc.state() == QProcess::Running) { 0633 observer->processEvents(); 0634 if (observer->wasCancelled()) 0635 proc.kill(); 0636 }; // busy wait - need to find something better... 0637 observer->subJobStopped(); 0638 0639 // check the return value 0640 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode())) { 0641 observer->detailedError(i18n("Failed to pack %1.", dest), observer->wasCancelled() ? i18n("User cancelled.") : proc.getErrorMsg()); 0642 return false; 0643 } 0644 0645 KConfigGroup group(krConfig, "Archives"); 0646 if (group.readEntry("Test Archives", _TestArchives) && !test(dest, type, password, observer, count)) { 0647 observer->error(i18n("Failed to pack %1.", dest)); 0648 return false; 0649 } 0650 return true; // SUCCESS 0651 } 0652 0653 bool KrArcHandler::openWallet() 0654 { 0655 if (!wallet) { 0656 // find a suitable parent window 0657 QWidget *actWindow = QApplication::activeWindow(); 0658 if (!actWindow) 0659 actWindow = (QWidget *)QApplication::desktop(); 0660 0661 wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), actWindow->effectiveWinId()); 0662 } 0663 return (wallet != nullptr); 0664 } 0665 0666 QString KrArcHandler::getPassword(const QString &path) 0667 { 0668 QString password; 0669 0670 QString key = "krarc-" + path; 0671 0672 if (!KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::PasswordFolder(), key)) { 0673 if (!KWallet::Wallet::isOpen(KWallet::Wallet::NetworkWallet()) && wallet != nullptr) { 0674 delete wallet; 0675 wallet = nullptr; 0676 } 0677 if (openWallet() && wallet->hasFolder(KWallet::Wallet::PasswordFolder())) { 0678 wallet->setFolder(KWallet::Wallet::PasswordFolder()); 0679 QMap<QString, QString> map; 0680 if (wallet->readMap(key, map) == 0) { 0681 QMap<QString, QString>::const_iterator it = map.constFind("password"); 0682 if (it != map.constEnd()) 0683 password = it.value(); 0684 } 0685 } 0686 } 0687 0688 bool keep = true; 0689 QString user = "archive"; 0690 QPointer<KPasswordDialog> passDlg = new KPasswordDialog(nullptr, KPasswordDialog::ShowKeepPassword); 0691 passDlg->setPrompt(i18n("This archive is encrypted, please supply the password:")), passDlg->setUsername(user); 0692 passDlg->setPassword(password); 0693 if (passDlg->exec() == KPasswordDialog::Accepted) { 0694 password = passDlg->password(); 0695 if (keep) { 0696 if (!KWallet::Wallet::isOpen(KWallet::Wallet::NetworkWallet()) && wallet != nullptr) { 0697 delete wallet; 0698 wallet = nullptr; 0699 } 0700 if (openWallet()) { 0701 bool ok = true; 0702 if (!wallet->hasFolder(KWallet::Wallet::PasswordFolder())) 0703 ok = wallet->createFolder(KWallet::Wallet::PasswordFolder()); 0704 if (ok) { 0705 wallet->setFolder(KWallet::Wallet::PasswordFolder()); 0706 QMap<QString, QString> map; 0707 map.insert("login", "archive"); 0708 map.insert("password", password); 0709 wallet->writeMap(key, map); 0710 } 0711 } 0712 } 0713 delete passDlg; 0714 return password; 0715 } 0716 delete passDlg; 0717 0718 return ""; 0719 } 0720 0721 bool KrArcHandler::isArchive(const QUrl &url) 0722 { 0723 QString protocol = url.scheme(); 0724 if (arcProtocols.indexOf(protocol) != -1) 0725 return true; 0726 else 0727 return false; 0728 } 0729 0730 QString KrArcHandler::getType(bool &encrypted, QString fileName, const QString &mime, bool check7zEncrypted, bool fast) 0731 { 0732 QString result = detectArchive(encrypted, std::move(fileName), check7zEncrypted, fast); 0733 if (result.isNull()) { 0734 // Then the type is based on the mime type 0735 return getShortTypeFromMime(mime); 0736 } 0737 return result; 0738 } 0739 0740 bool KrArcHandler::checkStatus(const QString &type, int exitCode) 0741 { 0742 return KrArcBaseManager::checkStatus(type, exitCode); 0743 } 0744 0745 void KrArcHandler::checkIf7zIsEncrypted(bool &encrypted, QString fileName) 0746 { 0747 // Reminder: If that function is modified, it's important to research if the 0748 // changes must also be applied to `kio_krarcProtocol::checkIf7zIsEncrypted()` 0749 0750 Kr7zEncryptionChecker proc; 0751 // TODO incorporate all this in Kr7zEncryptionChecker 0752 // Note: That command uses information given in a comment from 0753 // https://stackoverflow.com/questions/5248572/how-do-i-know-if-7zip-used-aes256 0754 proc << find7zExecutable() << "l" 0755 << "-slt" << fileName; 0756 proc.start(); 0757 proc.waitForFinished(); 0758 encrypted = proc.isEncrypted(); 0759 } 0760 0761 QString KrArcHandler::registeredProtocol(const QString &mimetype) 0762 { 0763 if (slaveMap == nullptr) { 0764 slaveMap = new QMap<QString, QString>(); 0765 0766 KConfigGroup group(krConfig, "Protocols"); 0767 QStringList protList = group.readEntry("Handled Protocols", QStringList()); 0768 for (auto &it : protList) { 0769 QStringList mimes = group.readEntry(QString("Mimes For %1").arg(it), QStringList()); 0770 for (auto &mime : mimes) 0771 (*slaveMap)[mime] = it; 0772 } 0773 } 0774 QString protocol = (*slaveMap)[mimetype]; 0775 if (protocol.isEmpty()) { 0776 if (krarcArchiveMimetypes.contains(mimetype)) { 0777 return QStringLiteral("krarc"); 0778 } 0779 protocol = KProtocolManager::protocolForArchiveMimetype(mimetype); 0780 } 0781 return protocol; 0782 } 0783 0784 void KrArcHandler::clearProtocolCache() 0785 { 0786 if (slaveMap) 0787 delete slaveMap; 0788 slaveMap = nullptr; 0789 }