File indexing completed on 2024-05-12 05:50:21
0001 /* 0002 * SPDX-FileCopyrightText: 2009 Harald Hvaal <haraldhv@stud.ntnu.no> 0003 * SPDX-FileCopyrightText: 2010-2011, 2014 Raphael Kubo da Costa <rakuco@FreeBSD.org> 0004 * SPDX-FileCopyrightText: 2015-2016 Ragnar Thomsen <rthomsen6@gmail.com> 0005 * SPDX-FileCopyrightText: 2016 Vladyslav Batyrenko <mvlabat@gmail.com> 0006 * 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 * 0009 */ 0010 0011 #include "cliplugin.h" 0012 #include "archiveentry.h" 0013 #include "ark_debug.h" 0014 0015 #include <QDateTime> 0016 0017 #include <KLocalizedString> 0018 #include <KPluginFactory> 0019 0020 using namespace Kerfuffle; 0021 0022 K_PLUGIN_CLASS_WITH_JSON(CliPlugin, "kerfuffle_clirar.json") 0023 0024 CliPlugin::CliPlugin(QObject *parent, const QVariantList &args) 0025 : CliInterface(parent, args) 0026 , m_parseState(ParseStateTitle) 0027 , m_isUnrar5(false) 0028 , m_isPasswordProtected(false) 0029 , m_isSolid(false) 0030 , m_isRAR5(false) 0031 , m_isLocked(false) 0032 , m_remainingIgnoreLines(1) // The first line of UNRAR output is empty. 0033 , m_linesComment(0) 0034 { 0035 qCDebug(ARK) << "Loaded cli_rar plugin"; 0036 0037 // Empty lines are needed for parsing output of unrar. 0038 setListEmptyLines(true); 0039 0040 setupCliProperties(); 0041 } 0042 0043 CliPlugin::~CliPlugin() 0044 { 0045 } 0046 0047 void CliPlugin::resetParsing() 0048 { 0049 m_parseState = ParseStateTitle; 0050 m_remainingIgnoreLines = 1; 0051 m_unrarVersion.clear(); 0052 m_comment.clear(); 0053 m_numberOfVolumes = 0; 0054 } 0055 0056 void CliPlugin::setupCliProperties() 0057 { 0058 qCDebug(ARK) << "Setting up parameters..."; 0059 0060 m_cliProps->setProperty("captureProgress", true); 0061 0062 m_cliProps->setProperty("addProgram", QStringLiteral("rar")); 0063 m_cliProps->setProperty("addSwitch", QStringList({QStringLiteral("a")})); 0064 0065 m_cliProps->setProperty("deleteProgram", QStringLiteral("rar")); 0066 m_cliProps->setProperty("deleteSwitch", QStringLiteral("d")); 0067 0068 m_cliProps->setProperty("extractProgram", QStringLiteral("unrar")); 0069 m_cliProps->setProperty("extractSwitch", QStringList{QStringLiteral("x"), QStringLiteral("-kb"), QStringLiteral("-p-")}); 0070 m_cliProps->setProperty("extractSwitchNoPreserve", QStringList{QStringLiteral("e"), QStringLiteral("-kb"), QStringLiteral("-p-")}); 0071 0072 m_cliProps->setProperty("listProgram", QStringLiteral("unrar")); 0073 m_cliProps->setProperty("listSwitch", QStringList{QStringLiteral("vt"), QStringLiteral("-v")}); 0074 0075 m_cliProps->setProperty("moveProgram", QStringLiteral("rar")); 0076 m_cliProps->setProperty("moveSwitch", QStringLiteral("rn")); 0077 0078 m_cliProps->setProperty("testProgram", QStringLiteral("unrar")); 0079 m_cliProps->setProperty("testSwitch", QStringLiteral("t")); 0080 0081 m_cliProps->setProperty("commentSwitch", QStringList{QStringLiteral("c"), QStringLiteral("-z$CommentFile")}); 0082 0083 m_cliProps->setProperty("passwordSwitch", QStringList{QStringLiteral("-p$Password")}); 0084 m_cliProps->setProperty("passwordSwitchHeaderEnc", QStringList{QStringLiteral("-hp$Password")}); 0085 0086 m_cliProps->setProperty("compressionLevelSwitch", QStringLiteral("-m$CompressionLevel")); 0087 m_cliProps->setProperty("compressionMethodSwitch", 0088 QHash<QString, QVariant>{{QStringLiteral("application/vnd.rar"), QStringLiteral("-ma$CompressionMethod")}, 0089 {QStringLiteral("application/x-rar"), QStringLiteral("-ma$CompressionMethod")}}); 0090 m_cliProps->setProperty("multiVolumeSwitch", QStringLiteral("-v$VolumeSizek")); 0091 0092 m_cliProps->setProperty("testPassedPatterns", QStringList{QStringLiteral("^All OK$")}); 0093 m_cliProps->setProperty("fileExistsFileNameRegExp", 0094 QStringList{QStringLiteral("^(.+) already exists. Overwrite it"), // unrar 3 & 4 0095 QStringLiteral("^Would you like to replace the existing file (.+)$")}); // unrar 5 0096 m_cliProps->setProperty("fileExistsInput", 0097 QStringList{ 0098 QStringLiteral("Y"), // Overwrite 0099 QStringLiteral("N"), // Skip 0100 QStringLiteral("A"), // Overwrite all 0101 QStringLiteral("E"), // Autoskip 0102 QStringLiteral("Q"), // Cancel 0103 }); 0104 0105 // rar will sometimes create multi-volume archives where first volume is 0106 // called name.part1.rar and other times name.part01.rar. 0107 m_cliProps->setProperty("multiVolumeSuffix", QStringList{QStringLiteral("part01.$Suffix"), QStringLiteral("part1.$Suffix")}); 0108 } 0109 0110 bool CliPlugin::readListLine(const QString &line) 0111 { 0112 // Ignore number of lines corresponding to m_remainingIgnoreLines. 0113 if (m_remainingIgnoreLines > 0) { 0114 --m_remainingIgnoreLines; 0115 return true; 0116 } 0117 0118 // Parse the title line, which contains the version of unrar. 0119 if (m_parseState == ParseStateTitle) { 0120 QRegularExpression rxVersionLine(QStringLiteral("^UNRAR (\\d+\\.\\d+)( beta \\d)? .*$")); 0121 QRegularExpressionMatch matchVersion = rxVersionLine.match(line); 0122 0123 if (matchVersion.hasMatch()) { 0124 m_parseState = ParseStateComment; 0125 m_unrarVersion = matchVersion.captured(1); 0126 qCDebug(ARK) << "UNRAR version" << m_unrarVersion << "detected"; 0127 if (m_unrarVersion.toFloat() >= 5) { 0128 m_isUnrar5 = true; 0129 qCDebug(ARK) << "Using UNRAR 5 parser"; 0130 } else { 0131 qCDebug(ARK) << "Using UNRAR 4 parser"; 0132 } 0133 } else { 0134 // If the second line doesn't contain an UNRAR title, something 0135 // is wrong. 0136 qCCritical(ARK) << "Failed to detect UNRAR output."; 0137 return false; 0138 } 0139 0140 // Or see what version of unrar we are dealing with and call specific 0141 // handler functions. 0142 } else if (m_isUnrar5) { 0143 return handleUnrar5Line(line); 0144 } else { 0145 return handleUnrar4Line(line); 0146 } 0147 return true; 0148 } 0149 0150 bool CliPlugin::handleUnrar5Line(const QString &line) 0151 { 0152 if (line.startsWith(QLatin1String("Cannot find volume "))) { 0153 Q_EMIT error(i18n("Failed to find all archive volumes.")); 0154 return false; 0155 } 0156 0157 switch (m_parseState) { 0158 // Parses the comment field. 0159 case ParseStateComment: 0160 0161 // "Archive: " is printed after the comment. 0162 // FIXME: Comment itself could also contain the searched string. 0163 0164 if (line.startsWith(QLatin1String("Archive: "))) { 0165 m_parseState = ParseStateHeader; 0166 m_comment = m_comment.trimmed(); 0167 m_linesComment = m_comment.count(QLatin1Char('\n')) + 1; 0168 if (!m_comment.isEmpty()) { 0169 qCDebug(ARK) << "Found a comment with" << m_linesComment << "lines"; 0170 } 0171 0172 } else { 0173 m_comment.append(line + QLatin1Char('\n')); 0174 } 0175 0176 break; 0177 0178 // Parses the header, which is whatever is between the comment field 0179 // and the entries. 0180 case ParseStateHeader: 0181 0182 // "Details: " indicates end of header. 0183 if (line.startsWith(QLatin1String("Details: "))) { 0184 ignoreLines(1, ParseStateEntryDetails); 0185 if (line.contains(QLatin1String("volume"))) { 0186 m_numberOfVolumes++; 0187 if (!isMultiVolume()) { 0188 setMultiVolume(true); 0189 qCDebug(ARK) << "Multi-volume archive detected"; 0190 } 0191 } 0192 if (line.contains(QLatin1String("solid")) && !m_isSolid) { 0193 m_isSolid = true; 0194 qCDebug(ARK) << "Solid archive detected"; 0195 } 0196 if (line.contains(QLatin1String("RAR 4"))) { 0197 Q_EMIT compressionMethodFound(QStringLiteral("RAR4")); 0198 } else if (line.contains(QLatin1String("RAR 5"))) { 0199 Q_EMIT compressionMethodFound(QStringLiteral("RAR5")); 0200 m_isRAR5 = true; 0201 } 0202 if (line.contains(QLatin1String("lock"))) { 0203 m_isLocked = true; 0204 } 0205 } 0206 break; 0207 0208 // Parses the entry details for each entry. 0209 case ParseStateEntryDetails: 0210 0211 // For multi-volume archives there is a header between the entries in 0212 // each volume. 0213 if (line.startsWith(QLatin1String("Archive: "))) { 0214 m_parseState = ParseStateHeader; 0215 return true; 0216 0217 // Empty line indicates end of entry. 0218 } else if (line.trimmed().isEmpty() && !m_unrar5Details.isEmpty()) { 0219 handleUnrar5Entry(); 0220 0221 } else { 0222 // All detail lines should contain a colon. 0223 if (!line.contains(QLatin1Char(':'))) { 0224 qCWarning(ARK) << "Unrecognized line:" << line; 0225 return true; 0226 } 0227 0228 // The details are on separate lines, so we store them in the QHash 0229 // m_unrar5Details. 0230 m_unrar5Details.insert(line.section(QLatin1Char(':'), 0, 0).trimmed().toLower(), line.section(QLatin1Char(':'), 1).trimmed()); 0231 } 0232 0233 break; 0234 0235 default: 0236 break; 0237 } 0238 return true; 0239 } 0240 0241 void CliPlugin::handleUnrar5Entry() 0242 { 0243 Archive::Entry *e = new Archive::Entry(this); 0244 0245 QString compressionRatio = m_unrar5Details.value(QStringLiteral("ratio")); 0246 compressionRatio.chop(1); // Remove the '%' 0247 e->setProperty("ratio", compressionRatio); 0248 0249 e->setProperty("timestamp", QDateTime::fromString(m_unrar5Details.value(QStringLiteral("mtime")), QStringLiteral("yyyy-MM-dd HH:mm:ss,zzz"))); 0250 0251 bool isDirectory = (m_unrar5Details.value(QStringLiteral("type")) == QLatin1String("Directory")); 0252 e->setProperty("isDirectory", isDirectory); 0253 0254 if (isDirectory && !m_unrar5Details.value(QStringLiteral("name")).endsWith(QLatin1Char('/'))) { 0255 m_unrar5Details[QStringLiteral("name")] += QLatin1Char('/'); 0256 } 0257 0258 QString compression = m_unrar5Details.value(QStringLiteral("compression")); 0259 int optionPos = compression.indexOf(QLatin1Char('-')); 0260 if (optionPos != -1) { 0261 e->setProperty("method", compression.mid(optionPos)); 0262 e->setProperty("version", compression.left(optionPos).trimmed()); 0263 } else { 0264 // No method specified. 0265 e->setProperty("method", QString()); 0266 e->setProperty("version", compression); 0267 } 0268 0269 m_isPasswordProtected = m_unrar5Details.value(QStringLiteral("flags")).contains(QLatin1String("encrypted")); 0270 e->setProperty("isPasswordProtected", m_isPasswordProtected); 0271 if (m_isPasswordProtected) { 0272 m_isRAR5 ? Q_EMIT encryptionMethodFound(QStringLiteral("AES256")) : Q_EMIT encryptionMethodFound(QStringLiteral("AES128")); 0273 } 0274 0275 e->setProperty("fullPath", m_unrar5Details.value(QStringLiteral("name"))); 0276 e->setProperty("size", m_unrar5Details.value(QStringLiteral("size"))); 0277 e->setProperty("compressedSize", m_unrar5Details.value(QStringLiteral("packed size"))); 0278 e->setProperty("permissions", m_unrar5Details.value(QStringLiteral("attributes"))); 0279 e->setProperty("CRC", m_unrar5Details.value(QStringLiteral("crc32"))); 0280 e->setProperty("BLAKE2", m_unrar5Details.value(QStringLiteral("blake2"))); 0281 0282 if (e->property("permissions").toString().startsWith(QLatin1Char('l'))) { 0283 e->setProperty("link", m_unrar5Details.value(QStringLiteral("target"))); 0284 } 0285 0286 m_unrar5Details.clear(); 0287 Q_EMIT entry(e); 0288 } 0289 0290 bool CliPlugin::handleUnrar4Line(const QString &line) 0291 { 0292 if (line.startsWith(QLatin1String("Cannot find volume "))) { 0293 Q_EMIT error(i18n("Failed to find all archive volumes.")); 0294 return false; 0295 } 0296 0297 // RegExp matching end of comment field. 0298 // FIXME: Comment itself could also contain the Archive path string here. 0299 QRegularExpression rxCommentEnd(QStringLiteral("^(Solid archive|Archive|Volume) .+$")); 0300 0301 // Three types of subHeaders can be displayed for unrar 3 and 4. 0302 // STM has 4 lines, RR has 3, and CMT has lines corresponding to 0303 // length of comment field +3. We ignore the subheaders. 0304 QRegularExpression rxSubHeader(QStringLiteral("^Data header type: (CMT|STM|RR)$")); 0305 QRegularExpressionMatch matchSubHeader; 0306 0307 switch (m_parseState) { 0308 // Parses the comment field. 0309 case ParseStateComment: 0310 0311 // unrar 4 outputs the following string when opening v5 RAR archives. 0312 if (line == QLatin1String("Unsupported archive format. Please update RAR to a newer version.")) { 0313 Q_EMIT error( 0314 i18n("Your unrar executable is version %1, which is too old to handle this archive. Please update to a more recent version.", m_unrarVersion)); 0315 return false; 0316 } 0317 0318 // unrar 3 reports a non-RAR archive when opening v5 RAR archives. 0319 if (line.endsWith(QLatin1String(" is not RAR archive"))) { 0320 Q_EMIT error(i18n("Unrar reported a non-RAR archive. The installed unrar version (%1) is old. Try updating your unrar.", m_unrarVersion)); 0321 return false; 0322 } 0323 0324 // If we reach this point, then we can be sure that it's not a RAR5 0325 // archive, so assume RAR4. 0326 Q_EMIT compressionMethodFound(QStringLiteral("RAR4")); 0327 0328 if (rxCommentEnd.match(line).hasMatch()) { 0329 if (line.startsWith(QLatin1String("Volume "))) { 0330 m_numberOfVolumes++; 0331 if (!isMultiVolume()) { 0332 setMultiVolume(true); 0333 qCDebug(ARK) << "Multi-volume archive detected"; 0334 } 0335 } 0336 if (line.startsWith(QLatin1String("Solid archive")) && !m_isSolid) { 0337 m_isSolid = true; 0338 qCDebug(ARK) << "Solid archive detected"; 0339 } 0340 0341 m_parseState = ParseStateHeader; 0342 m_comment = m_comment.trimmed(); 0343 m_linesComment = m_comment.count(QLatin1Char('\n')) + 1; 0344 if (!m_comment.isEmpty()) { 0345 qCDebug(ARK) << "Found a comment with" << m_linesComment << "lines"; 0346 } 0347 0348 } else { 0349 m_comment.append(line + QLatin1Char('\n')); 0350 } 0351 0352 break; 0353 0354 // Parses the header, which is whatever is between the comment field 0355 // and the entries. 0356 case ParseStateHeader: 0357 0358 // Horizontal line indicates end of header. 0359 if (line.startsWith(QLatin1String("--------------------"))) { 0360 m_parseState = ParseStateEntryFileName; 0361 } else if (line.startsWith(QLatin1String("Volume "))) { 0362 m_numberOfVolumes++; 0363 } else if (line == QLatin1String("Lock is present")) { 0364 m_isLocked = true; 0365 } 0366 break; 0367 0368 // Parses the entry name, which is on the first line of each entry. 0369 case ParseStateEntryFileName: 0370 0371 // Ignore empty lines. 0372 if (line.trimmed().isEmpty()) { 0373 return true; 0374 } 0375 0376 matchSubHeader = rxSubHeader.match(line); 0377 0378 if (matchSubHeader.hasMatch()) { 0379 qCDebug(ARK) << "SubHeader of type" << matchSubHeader.captured(1) << "found"; 0380 if (matchSubHeader.captured(1) == QLatin1String("STM")) { 0381 ignoreLines(4, ParseStateEntryFileName); 0382 } else if (matchSubHeader.captured(1) == QLatin1String("CMT")) { 0383 ignoreLines(m_linesComment + 3, ParseStateEntryFileName); 0384 } else if (matchSubHeader.captured(1) == QLatin1String("RR")) { 0385 ignoreLines(3, ParseStateEntryFileName); 0386 } 0387 return true; 0388 } 0389 0390 // The entries list ends with a horizontal line, followed by a 0391 // single summary line or, for multi-volume archives, another header. 0392 if (line.startsWith(QLatin1String("-----------------"))) { 0393 m_parseState = ParseStateHeader; 0394 return true; 0395 0396 // Encrypted files are marked with an asterisk. 0397 } else if (line.startsWith(QLatin1Char('*'))) { 0398 m_isPasswordProtected = true; 0399 m_unrar4Details.append(QString(line.trimmed()).remove(0, 1)); // Remove the asterisk 0400 Q_EMIT encryptionMethodFound(QStringLiteral("AES128")); 0401 0402 // Entry names always start at the second position, so a line not 0403 // starting with a space is not an entry name. 0404 } else if (!line.startsWith(QLatin1Char(' '))) { 0405 qCWarning(ARK) << "Unrecognized line:" << line; 0406 return true; 0407 0408 // If we reach this, then we can assume the line is an entry name, so 0409 // save it, and move on to the rest of the entry details. 0410 } else { 0411 m_unrar4Details.append(line.trimmed()); 0412 } 0413 0414 m_parseState = ParseStateEntryDetails; 0415 0416 break; 0417 0418 // Parses the remainder of the entry details for each entry. 0419 case ParseStateEntryDetails: 0420 0421 // If the line following an entry name is empty, we did something 0422 // wrong. 0423 Q_ASSERT(!line.trimmed().isEmpty()); 0424 0425 // If we reach a horizontal line, then the previous line was not an 0426 // entry name, so go back to header. 0427 if (line.startsWith(QLatin1String("-----------------"))) { 0428 m_parseState = ParseStateHeader; 0429 return true; 0430 } 0431 0432 // In unrar 3 and 4 the details are on a single line, so we 0433 // pass a QStringList containing the details. We need to store 0434 // it due to symlinks (see below). 0435 m_unrar4Details.append(line.split(QLatin1Char(' '), Qt::SkipEmptyParts)); 0436 0437 // The details line contains 9 fields, so m_unrar4Details 0438 // should now contain 9 + the filename = 10 strings. If not, this is 0439 // not an archive entry. 0440 if (m_unrar4Details.size() != 10) { 0441 m_parseState = ParseStateHeader; 0442 return true; 0443 } 0444 0445 // When unrar 3 and 4 list a symlink, they output an extra line 0446 // containing the link target. The extra line is output after 0447 // the line we ignore, so we first need to ignore one line. 0448 if (m_unrar4Details.at(6).startsWith(QLatin1Char('l'))) { 0449 ignoreLines(1, ParseStateLinkTarget); 0450 return true; 0451 } else { 0452 handleUnrar4Entry(); 0453 } 0454 0455 // Unrar 3 & 4 show a third line for each entry, which contains 0456 // three details: Host OS, Solid, and Old. We can ignore this 0457 // line. 0458 ignoreLines(1, ParseStateEntryFileName); 0459 0460 break; 0461 0462 // Parses a symlink target. 0463 case ParseStateLinkTarget: 0464 0465 m_unrar4Details.append(QString(line).remove(QStringLiteral("-->")).trimmed()); 0466 handleUnrar4Entry(); 0467 0468 m_parseState = ParseStateEntryFileName; 0469 break; 0470 0471 default: 0472 break; 0473 } 0474 0475 return true; 0476 } 0477 0478 void CliPlugin::handleUnrar4Entry() 0479 { 0480 Archive::Entry *e = new Archive::Entry(this); 0481 0482 QDateTime ts = QDateTime::fromString(QString(m_unrar4Details.at(4) + QLatin1Char(' ') + m_unrar4Details.at(5)), QStringLiteral("dd-MM-yy hh:mm")); 0483 // Unrar 3 & 4 output dates with a 2-digit year but QDateTime takes it as 0484 // 19??. Let's take 1950 as cut-off; similar to KDateTime. 0485 // Hopefully no one will create rar archives in 2051 with unrar 4... 0486 if (ts.date().year() < 1950) { 0487 // NOTE: only change the date. QDateTime::addYears() might also change the time because of DST changes. 0488 ts.setDate(ts.date().addYears(100)); 0489 } 0490 e->setProperty("timestamp", ts); 0491 0492 bool isDirectory = ((m_unrar4Details.at(6).at(0) == QLatin1Char('d')) || (m_unrar4Details.at(6).at(1) == QLatin1Char('D'))); 0493 e->setProperty("isDirectory", isDirectory); 0494 0495 if (isDirectory && !m_unrar4Details.at(0).endsWith(QLatin1Char('/'))) { 0496 m_unrar4Details[0] += QLatin1Char('/'); 0497 } 0498 0499 // Unrar reports the ratio as ((compressed size * 100) / size); 0500 // we consider ratio as (100 * ((size - compressed size) / size)). 0501 // If the archive is a multivolume archive, a string indicating 0502 // whether the archive's position in the volume is displayed 0503 // instead of the compression ratio. 0504 QString compressionRatio = m_unrar4Details.at(3); 0505 if ((compressionRatio == QLatin1String("<--")) || (compressionRatio == QLatin1String("<->")) || (compressionRatio == QLatin1String("-->"))) { 0506 compressionRatio = QLatin1Char('0'); 0507 } else { 0508 compressionRatio.chop(1); // Remove the '%' 0509 } 0510 e->setProperty("ratio", compressionRatio); 0511 0512 // TODO: 0513 // - Permissions differ depending on the system the entry was added 0514 // to the archive. 0515 e->setProperty("fullPath", m_unrar4Details.at(0)); 0516 e->setProperty("size", m_unrar4Details.at(1)); 0517 e->setProperty("compressedSize", m_unrar4Details.at(2)); 0518 e->setProperty("permissions", m_unrar4Details.at(6)); 0519 e->setProperty("CRC", m_unrar4Details.at(7)); 0520 e->setProperty("method", m_unrar4Details.at(8)); 0521 e->setProperty("version", m_unrar4Details.at(9)); 0522 e->setProperty("isPasswordProtected", m_isPasswordProtected); 0523 0524 if (e->property("permissions").toString().startsWith(QLatin1Char('l'))) { 0525 e->setProperty("link", m_unrar4Details.at(10)); 0526 } 0527 0528 m_unrar4Details.clear(); 0529 Q_EMIT entry(e); 0530 } 0531 0532 bool CliPlugin::readExtractLine(const QString &line) 0533 { 0534 if (line.contains(QLatin1String("CRC failed"))) { 0535 Q_EMIT error(i18n("One or more wrong checksums")); 0536 return false; 0537 } 0538 0539 if (line.startsWith(QLatin1String("Cannot find volume "))) { 0540 Q_EMIT error(i18n("Failed to find all archive volumes.")); 0541 return false; 0542 } 0543 0544 return true; 0545 } 0546 0547 bool CliPlugin::hasBatchExtractionProgress() const 0548 { 0549 return true; 0550 } 0551 0552 void CliPlugin::ignoreLines(int lines, ParseState nextState) 0553 { 0554 m_remainingIgnoreLines = lines; 0555 m_parseState = nextState; 0556 } 0557 0558 bool CliPlugin::isPasswordPrompt(const QString &line) 0559 { 0560 return line.startsWith(QLatin1String("Enter password (will not be echoed) for")); 0561 } 0562 0563 bool CliPlugin::isWrongPasswordMsg(const QString &line) 0564 { 0565 return (line.contains(QLatin1String("password incorrect")) || line.contains(QLatin1String("wrong password"))); 0566 } 0567 0568 bool CliPlugin::isCorruptArchiveMsg(const QString &line) 0569 { 0570 return (line == QLatin1String("Unexpected end of archive") || line.contains(QLatin1String("the file header is corrupt")) 0571 || line.endsWith(QLatin1String("checksum error"))); 0572 } 0573 0574 bool CliPlugin::isDiskFullMsg(const QString &line) 0575 { 0576 return line.contains(QLatin1String("No space left on device")); 0577 } 0578 0579 bool CliPlugin::isFileExistsMsg(const QString &line) 0580 { 0581 return (line == QLatin1String("[Y]es, [N]o, [A]ll, n[E]ver, [R]ename, [Q]uit ")); 0582 } 0583 0584 bool CliPlugin::isFileExistsFileName(const QString &line) 0585 { 0586 return (line.startsWith(QLatin1String("Would you like to replace the existing file ")) || // unrar 5 0587 line.contains(QLatin1String(" already exists. Overwrite it"))); // unrar 3 & 4 0588 } 0589 0590 bool CliPlugin::isLocked() const 0591 { 0592 return m_isLocked; 0593 } 0594 0595 #include "cliplugin.moc" 0596 #include "moc_cliplugin.cpp"