refactor: reimplement unescapeExec
adjusted patch from master branch (originally 2f0f34a44fb) Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
		@ -250,8 +250,8 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
 | 
				
			|||||||
        execStr = toString(actionExec.value());
 | 
					        execStr = toString(actionExec.value());
 | 
				
			||||||
        if (execStr.isEmpty()) {
 | 
					        if (execStr.isEmpty()) {
 | 
				
			||||||
            qWarning() << "exec value to string failed, try default action.";  // we need this log.
 | 
					            qWarning() << "exec value to string failed, try default action.";  // we need this log.
 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -304,46 +304,78 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
 | 
				
			|||||||
    auto &jobManager = parent()->jobManager();
 | 
					    auto &jobManager = parent()->jobManager();
 | 
				
			||||||
    return jobManager.addJob(
 | 
					    return jobManager.addJob(
 | 
				
			||||||
        m_applicationPath.path(),
 | 
					        m_applicationPath.path(),
 | 
				
			||||||
        [this, binary = std::move(bin), commands = std::move(cmds)](const QVariant &variantValue) -> QVariant {
 | 
					        [this, binary = std::move(bin), commands = std::move(cmds)](const QVariant &value) -> QVariant {
 | 
				
			||||||
            auto resourceFile = variantValue.toString();
 | 
					            auto rawResources = value.toString();
 | 
				
			||||||
            auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
 | 
					            auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
 | 
				
			||||||
            auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
 | 
					            auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
 | 
				
			||||||
            auto newCommands = commands;
 | 
					            auto newCommands = commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
 | 
					            newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
 | 
				
			||||||
            auto location = newCommands.indexOf(R"(%f)");
 | 
					            if (rawResources.isEmpty()) {
 | 
				
			||||||
            if (location != -1) {  // due to std::move, there only remove once
 | 
					 | 
				
			||||||
                newCommands.remove(location);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (resourceFile.isEmpty()) {
 | 
					 | 
				
			||||||
                newCommands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
 | 
					                newCommands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
 | 
				
			||||||
                    escapeApplicationId(this->id()), instanceRandomUUID));  // launcher should use this instanceId
 | 
					                    escapeApplicationId(this->id()), instanceRandomUUID));  // launcher should use this instanceId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                QProcess process;
 | 
					                QProcess process;
 | 
				
			||||||
                qDebug() << "run with commands:" << newCommands;
 | 
					                qDebug() << "launcher :" << m_launcher << "run with commands:" << newCommands;
 | 
				
			||||||
                process.start(m_launcher, newCommands);
 | 
					                process.start(m_launcher, newCommands);
 | 
				
			||||||
                process.waitForFinished();
 | 
					                process.waitForFinished();
 | 
				
			||||||
                if (auto code = process.exitCode(); code != 0) {
 | 
					                if (auto code = process.exitCode(); code != 0) {
 | 
				
			||||||
                    qWarning() << "Launch Application Failed";
 | 
					                    qWarning() << "Launch Application Failed";
 | 
				
			||||||
                    return QDBusError::Failed;
 | 
					                    return QDBusError::Failed;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return objectPath;
 | 
					                return objectPath;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            auto url = QUrl::fromUserInput(resourceFile);
 | 
					            auto location = newCommands.end();
 | 
				
			||||||
            if (!url.isValid()) {  // if url is invalid, passing to launcher directly
 | 
					            qsizetype fieldIndex{-1};
 | 
				
			||||||
                auto scheme = url.scheme();
 | 
					            for (auto it = newCommands.begin(); it != newCommands.end(); ++it) {
 | 
				
			||||||
                if (!scheme.isEmpty()) {
 | 
					                auto fieldLocation = it->indexOf(R"(%f)");
 | 
				
			||||||
                    // TODO: resourceFile = processRemoteFile(resourceFile);
 | 
					                if (fieldLocation != -1) {
 | 
				
			||||||
 | 
					                    fieldIndex = fieldLocation;
 | 
				
			||||||
 | 
					                    location = it;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                fieldLocation = it->indexOf(R"(%F)");
 | 
				
			||||||
 | 
					                if (fieldLocation != -1) {
 | 
				
			||||||
 | 
					                    fieldIndex = fieldLocation;
 | 
				
			||||||
 | 
					                    location = it;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // NOTE: resourceFile must be available in the following contexts
 | 
					            if (location == newCommands.end()) {
 | 
				
			||||||
            newCommands.insert(location, resourceFile);
 | 
					                qCritical() << R"(internal logic error, can't find %f or %F in exec command, abort.)";
 | 
				
			||||||
 | 
					                return QDBusError::Failed;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const auto &rawResource = rawResources.split(' ', Qt::SkipEmptyParts);
 | 
				
			||||||
 | 
					            QStringList resources;
 | 
				
			||||||
 | 
					            std::transform(rawResource.cbegin(), rawResource.cend(), std::back_inserter(resources), [](const QString &res) {
 | 
				
			||||||
 | 
					                auto url = QUrl::fromUserInput(res);
 | 
				
			||||||
 | 
					                if (url.isValid()) {
 | 
				
			||||||
 | 
					                    if (url.isLocalFile()) {
 | 
				
			||||||
 | 
					                        return url.toLocalFile();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    // for now, we only support local file, maybe we will support remote file in the future.
 | 
				
			||||||
 | 
					                    // TODO: return processRemoteFile(url);
 | 
				
			||||||
 | 
					                }  // if url is invalid, passing to launcher directly
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return res;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            auto tmpRes = resources.join(' ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            location->replace(fieldIndex, tmpRes.size(), tmpRes);
 | 
				
			||||||
 | 
					            auto newCmd = location->split(' ', Qt::SkipEmptyParts);
 | 
				
			||||||
 | 
					            location = newCommands.erase(location);
 | 
				
			||||||
 | 
					            for (auto &c : newCmd) {
 | 
				
			||||||
 | 
					                location = newCommands.insert(location, std::move(c));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            newCommands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
 | 
					            newCommands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            QProcess process;
 | 
					            QProcess process;
 | 
				
			||||||
            qDebug() << "run with commands:" << newCommands;
 | 
					            qDebug().noquote() << "launcher :" << m_launcher << "run with commands:" << newCommands;
 | 
				
			||||||
            process.start(getApplicationLauncherBinary(), newCommands);
 | 
					            process.start(getApplicationLauncherBinary(), newCommands);
 | 
				
			||||||
            process.waitForFinished();
 | 
					            process.waitForFinished();
 | 
				
			||||||
            auto exitCode = process.exitCode();
 | 
					            auto exitCode = process.exitCode();
 | 
				
			||||||
@ -351,6 +383,7 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
 | 
				
			|||||||
                qWarning() << "Launch Application Failed";
 | 
					                qWarning() << "Launch Application Failed";
 | 
				
			||||||
                return QDBusError::Failed;
 | 
					                return QDBusError::Failed;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return objectPath;
 | 
					            return objectPath;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        std::move(res));
 | 
					        std::move(res));
 | 
				
			||||||
@ -957,139 +990,160 @@ std::optional<QStringList> ApplicationService::unescapeExecArgs(const QString &s
 | 
				
			|||||||
    return execList;
 | 
					    return execList;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringList &fields) noexcept
 | 
					LaunchTask ApplicationService::unescapeExec(const QString &str, QStringList fields) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    LaunchTask task;
 | 
					    LaunchTask task;
 | 
				
			||||||
    auto opt = unescapeExecArgs(str);
 | 
					    auto args = unescapeExecArgs(str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!opt.has_value()) {
 | 
					    if (!args) {
 | 
				
			||||||
        qWarning() << "unescapeExecArgs failed.";
 | 
					        qWarning() << "unescapeExecArgs failed.";
 | 
				
			||||||
        return {};
 | 
					        return {};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto execList = std::move(opt).value();
 | 
					    if (args->isEmpty()) {
 | 
				
			||||||
    if (execList.isEmpty()) {
 | 
					 | 
				
			||||||
        qWarning() << "exec format is invalid.";
 | 
					        qWarning() << "exec format is invalid.";
 | 
				
			||||||
        return {};
 | 
					        return {};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    task.LaunchBin = execList.first();
 | 
					    auto processUrl = [](const QString &str) {
 | 
				
			||||||
    QRegularExpression re{"%[fFuUickdDnNvm]"};
 | 
					        auto url = QUrl::fromUserInput(str);
 | 
				
			||||||
    auto matcher = re.match(str);
 | 
					        if (!url.isValid()) {
 | 
				
			||||||
    if (!matcher.hasMatch()) {
 | 
					            qDebug() << "url is invalid, pass to exec directly.";
 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					            return str;
 | 
				
			||||||
        task.Resources.emplace_back(QString{""});  // mapReduce should run once at least
 | 
					 | 
				
			||||||
        return task;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto list = matcher.capturedTexts();
 | 
					        if (url.isLocalFile()) {
 | 
				
			||||||
    if (list.count() != 1) {
 | 
					            return url.toLocalFile();
 | 
				
			||||||
        qWarning() << "invalid exec format, all filed code will be ignored.";
 | 
					 | 
				
			||||||
        for (const auto &code : list) {
 | 
					 | 
				
			||||||
            execList.removeOne(code);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					 | 
				
			||||||
        return task;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto filesCode = list.first().back().toLatin1();
 | 
					        return url.toString();
 | 
				
			||||||
    auto codeStr = QString(R"(%%1)").arg(filesCode);
 | 
					    };
 | 
				
			||||||
    auto location = execList.indexOf(codeStr);
 | 
					
 | 
				
			||||||
    if (location == -1) {
 | 
					    task.LaunchBin = args->first();
 | 
				
			||||||
        qWarning() << "invalid exec format, all filed code will be ignored.";
 | 
					    const QChar percentage{'%'};
 | 
				
			||||||
 | 
					    bool exclusiveField{false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const auto &arg : *args) {
 | 
				
			||||||
 | 
					        QString newArg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const auto *it = arg.cbegin(); it != arg.cend();) {
 | 
				
			||||||
 | 
					            if (*it != percentage) {
 | 
				
			||||||
 | 
					                newArg.append(*(it++));
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const auto *code = it + 1;
 | 
				
			||||||
 | 
					            if (code == arg.cend()) {
 | 
				
			||||||
 | 
					                qWarning() << R"(content of exec is invalid, a unterminated % is detected.)";
 | 
				
			||||||
                return {};
 | 
					                return {};
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (filesCode) {
 | 
					            if (*code == percentage) {
 | 
				
			||||||
    case 'f': {  // Defer to async job
 | 
					                newArg.append(percentage);
 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					                it += 2;
 | 
				
			||||||
        for (const auto &field : fields) {
 | 
					                continue;
 | 
				
			||||||
            task.Resources.emplace_back(field);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
    } break;
 | 
					
 | 
				
			||||||
    case 'u': {
 | 
					            switch (code->toLatin1()) {
 | 
				
			||||||
        execList.removeAt(location);
 | 
					            case 'f': {  // Defer to async job
 | 
				
			||||||
        if (fields.empty()) {
 | 
					                if (exclusiveField) {
 | 
				
			||||||
            task.command.append(execList);
 | 
					                    qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        if (fields.count() > 1) {
 | 
					                exclusiveField = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (fields.empty()) {
 | 
				
			||||||
 | 
					                    qDebug() << R"(fields is empty, %f will be ignored.)";
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (fields.size() > 1) {
 | 
				
			||||||
 | 
					                    qDebug() << R"(fields count is greater than one, %f will only take first element.)";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                task.Resources.emplace_back(fields.takeFirst());
 | 
				
			||||||
 | 
					                newArg.append(R"(%f)");
 | 
				
			||||||
 | 
					            } break;
 | 
				
			||||||
 | 
					            case 'u': {
 | 
				
			||||||
 | 
					                if (exclusiveField) {
 | 
				
			||||||
 | 
					                    qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                exclusiveField = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (fields.empty()) {
 | 
				
			||||||
 | 
					                    qDebug() << "fields is empty, %u will be ignored.";
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (fields.size() > 1) {
 | 
				
			||||||
                    qDebug() << R"(fields count is greater than one, %u will only take first element.)";
 | 
					                    qDebug() << R"(fields count is greater than one, %u will only take first element.)";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        execList.insert(location, fields.first());
 | 
					
 | 
				
			||||||
        task.command.append(execList);
 | 
					                newArg.append(processUrl(fields.takeFirst()));
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
    case 'F': {
 | 
					            case 'F': {  // Defer to async job
 | 
				
			||||||
        execList.remove(location);
 | 
					                if (exclusiveField) {
 | 
				
			||||||
        auto it = execList.begin() + location;
 | 
					                    qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
 | 
				
			||||||
        for (const auto &field : fields) {
 | 
					                    break;
 | 
				
			||||||
            auto tmp = QUrl::fromUserInput(field);
 | 
					 | 
				
			||||||
            if (auto scheme = tmp.scheme(); scheme.startsWith("file") or scheme.isEmpty()) {
 | 
					 | 
				
			||||||
                it = execList.insert(it, tmp.toLocalFile());
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                qWarning() << "shouldn't replace %F with an URL:" << field;
 | 
					 | 
				
			||||||
                it = execList.insert(it, field);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            ++it;
 | 
					                exclusiveField = true;
 | 
				
			||||||
        }
 | 
					
 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					                task.Resources.emplace_back(fields.join(' '));
 | 
				
			||||||
 | 
					                fields.clear();
 | 
				
			||||||
 | 
					                newArg.append(R"(%F)");
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
            case 'U': {
 | 
					            case 'U': {
 | 
				
			||||||
        execList.removeAt(location);
 | 
					                if (exclusiveField) {
 | 
				
			||||||
        auto it = execList.begin() + location;
 | 
					                    qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
 | 
				
			||||||
        for (const auto &field : fields) {
 | 
					                    break;
 | 
				
			||||||
            it = execList.insert(it, field);
 | 
					 | 
				
			||||||
            ++it;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					                exclusiveField = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                QStringList urls;
 | 
				
			||||||
 | 
					                std::transform(fields.cbegin(), fields.cend(), std::back_inserter(urls), processUrl);
 | 
				
			||||||
 | 
					                fields.clear();
 | 
				
			||||||
 | 
					                newArg.append(urls.join(' '));  // split at the end of loop
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
            case 'i': {
 | 
					            case 'i': {
 | 
				
			||||||
        execList.removeAt(location);
 | 
					 | 
				
			||||||
                auto val = m_entry->value(DesktopFileEntryKey, "Icon");
 | 
					                auto val = m_entry->value(DesktopFileEntryKey, "Icon");
 | 
				
			||||||
                if (!val) {
 | 
					                if (!val) {
 | 
				
			||||||
                    qDebug() << R"(Application Icons can't be found. %i will be ignored.)";
 | 
					                    qDebug() << R"(Application Icons can't be found. %i will be ignored.)";
 | 
				
			||||||
            task.command.append(std::move(execList));
 | 
					                    break;
 | 
				
			||||||
            return task;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                auto iconStr = toIconString(val.value());
 | 
					                auto iconStr = toIconString(val.value());
 | 
				
			||||||
                if (iconStr.isEmpty()) {
 | 
					                if (iconStr.isEmpty()) {
 | 
				
			||||||
                    qDebug() << R"(Icons Convert to string failed. %i will be ignored.)";
 | 
					                    qDebug() << R"(Icons Convert to string failed. %i will be ignored.)";
 | 
				
			||||||
            task.command.append(std::move(execList));
 | 
					                    break;
 | 
				
			||||||
            return task;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        auto it = execList.insert(location, iconStr);
 | 
					
 | 
				
			||||||
        execList.insert(it, "--icon");
 | 
					                // split at the end of loop
 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					                newArg.append(QString{"--icon %1"}.arg(iconStr));
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
            case 'c': {
 | 
					            case 'c': {
 | 
				
			||||||
        execList.removeAt(location);
 | 
					 | 
				
			||||||
                auto val = m_entry->value(DesktopFileEntryKey, "Name");
 | 
					                auto val = m_entry->value(DesktopFileEntryKey, "Name");
 | 
				
			||||||
                if (!val) {
 | 
					                if (!val) {
 | 
				
			||||||
                    qDebug() << R"(Application Name can't be found. %c will be ignored.)";
 | 
					                    qDebug() << R"(Application Name can't be found. %c will be ignored.)";
 | 
				
			||||||
            task.command.append(std::move(execList));
 | 
					                    break;
 | 
				
			||||||
            return task;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const auto &rawValue = val.value();
 | 
					                const auto &rawValue = val.value();
 | 
				
			||||||
                if (!rawValue.canConvert<QStringMap>()) {
 | 
					                if (!rawValue.canConvert<QStringMap>()) {
 | 
				
			||||||
                    qDebug() << "Name's underlying type mismatch:" << "QStringMap" << rawValue.metaType().name();
 | 
					                    qDebug() << "Name's underlying type mismatch:" << "QStringMap" << rawValue.metaType().name();
 | 
				
			||||||
            task.command.append(std::move(execList));
 | 
					                    break;
 | 
				
			||||||
            return task;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                auto NameStr = toLocaleString(rawValue.value<QStringMap>(), getUserLocale());
 | 
					                auto NameStr = toLocaleString(rawValue.value<QStringMap>(), getUserLocale());
 | 
				
			||||||
                if (NameStr.isEmpty()) {
 | 
					                if (NameStr.isEmpty()) {
 | 
				
			||||||
                    qDebug() << R"(Name Convert to locale string failed. %c will be ignored.)";
 | 
					                    qDebug() << R"(Name Convert to locale string failed. %c will be ignored.)";
 | 
				
			||||||
            task.command.append(std::move(execList));
 | 
					                    break;
 | 
				
			||||||
            return task;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
        execList.insert(location, NameStr);
 | 
					
 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					                newArg.append(NameStr);
 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
            case 'k': {  // ignore all desktop file location for now.
 | 
					            case 'k': {  // ignore all desktop file location for now.
 | 
				
			||||||
        execList.removeAt(location);
 | 
					                newArg.append(m_desktopSource.sourcePath());
 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
            case 'd':
 | 
					            case 'd':
 | 
				
			||||||
            case 'D':
 | 
					            case 'D':
 | 
				
			||||||
@ -1098,11 +1152,19 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringLis
 | 
				
			|||||||
            case 'v':
 | 
					            case 'v':
 | 
				
			||||||
                [[fallthrough]];  // Deprecated field codes should be removed from the command line and ignored.
 | 
					                [[fallthrough]];  // Deprecated field codes should be removed from the command line and ignored.
 | 
				
			||||||
            case 'm': {
 | 
					            case 'm': {
 | 
				
			||||||
        execList.removeAt(location);
 | 
					                qDebug() << "field code" << *code << "has been deprecated.";
 | 
				
			||||||
        task.command.append(std::move(execList));
 | 
					 | 
				
			||||||
            } break;
 | 
					            } break;
 | 
				
			||||||
            default: {
 | 
					            default: {
 | 
				
			||||||
        qDebug() << "unrecognized file code.";
 | 
					                qDebug() << "unknown field code:" << *code << ", ignore it.";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            it += 2;  // skip filed code
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto newArgList = newArg.split(' ', Qt::SkipEmptyParts);
 | 
				
			||||||
 | 
					        if (!newArgList.isEmpty()) {
 | 
				
			||||||
 | 
					            task.command.append(std::move(newArgList));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1110,9 +1172,54 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringLis
 | 
				
			|||||||
        task.Resources.emplace_back(QString{""});  // mapReduce should run once at least
 | 
					        task.Resources.emplace_back(QString{""});  // mapReduce should run once at least
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qInfo() << "after unescape exec:" << task.LaunchBin << task.command << task.Resources;
 | 
				
			||||||
    return task;
 | 
					    return task;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ApplicationService::unescapeEens(QVariantMap &options) noexcept
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (options.find("env") == options.end()) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    QStringList result;
 | 
				
			||||||
 | 
					    auto envs = options["env"];
 | 
				
			||||||
 | 
					    for (const QString &var : envs.toStringList()) {
 | 
				
			||||||
 | 
					        wordexp_t p;
 | 
				
			||||||
 | 
					        if (wordexp(var.toStdString().c_str(), &p, 0) == 0) {
 | 
				
			||||||
 | 
					            for (size_t i = 0; i < p.we_wordc; i++) {
 | 
				
			||||||
 | 
					                result << QString::fromLocal8Bit(p.we_wordv[i]);  // 将结果转换为QString
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            wordfree(&p);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options.insert("env", result);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ApplicationService::autoRemoveFromDesktop() const noexcept
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    auto dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
 | 
				
			||||||
 | 
					    if (dir.isEmpty()) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QFileInfo desktopFile{QDir{dir}.filePath(m_desktopSource.desktopId() + ".desktop")};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!desktopFile.isSymbolicLink()) {
 | 
				
			||||||
 | 
					        qDebug() << desktopFile.filePath() << " is not symbolicLink";
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    QFile file{desktopFile.filePath()};
 | 
				
			||||||
 | 
					    auto success = file.remove();
 | 
				
			||||||
 | 
					    if (!success) {
 | 
				
			||||||
 | 
					        qWarning() << "remove desktop file failed:" << file.errorString();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QVariant ApplicationService::findEntryValue(const QString &group,
 | 
					QVariant ApplicationService::findEntryValue(const QString &group,
 | 
				
			||||||
                                            const QString &valueKey,
 | 
					                                            const QString &valueKey,
 | 
				
			||||||
                                            EntryValueType type,
 | 
					                                            EntryValueType type,
 | 
				
			||||||
 | 
				
			|||||||
@ -134,8 +134,10 @@ public:
 | 
				
			|||||||
                                          EntryValueType type,
 | 
					                                          EntryValueType type,
 | 
				
			||||||
                                          const QLocale &locale = getUserLocale()) const noexcept;
 | 
					                                          const QLocale &locale = getUserLocale()) const noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields) noexcept;
 | 
					    [[nodiscard]] LaunchTask unescapeExec(const QString &str, QStringList fields) noexcept;
 | 
				
			||||||
    [[nodiscard]] static std::optional<QStringList> unescapeExecArgs(const QString &str) noexcept;
 | 
					    [[nodiscard]] static std::optional<QStringList> unescapeExecArgs(const QString &str) noexcept;
 | 
				
			||||||
 | 
					    void unescapeEens(QVariantMap&) noexcept;
 | 
				
			||||||
 | 
					    void autoRemoveFromDesktop() const noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public Q_SLOTS:
 | 
					public Q_SLOTS:
 | 
				
			||||||
    // NOTE: 'realExec' only for internal implementation
 | 
					    // NOTE: 'realExec' only for internal implementation
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user