File indexing completed on 2024-12-22 05:16:01
0001 /* 0002 localegenhelper.cpp 0003 SPDX-FileCopyrightText: 2021 Han Young <hanyoung@protonmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 #include "localegenhelper.h" 0008 #include "localegenhelperadaptor.h" 0009 0010 #include <KLocalizedString> 0011 0012 #include <QDBusConnection> 0013 #include <QDebug> 0014 0015 #include <chrono> 0016 0017 LocaleGenHelper::LocaleGenHelper() 0018 : m_authority(PolkitQt1::Authority::instance()) 0019 { 0020 new LocaleGenHelperAdaptor(this); 0021 if (!QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.localegenhelper"))) { 0022 qWarning() << "another helper is already running"; 0023 QCoreApplication::instance()->exit(); 0024 } 0025 if (!QDBusConnection::systemBus().registerObject(QStringLiteral("/LocaleGenHelper"), this)) { 0026 qWarning() << "unable to register service interface to dbus"; 0027 QCoreApplication::instance()->exit(); 0028 } 0029 connect(m_authority, &PolkitQt1::Authority::checkAuthorizationFinished, this, &LocaleGenHelper::enableLocalesPrivate); 0030 connect(&m_timer, &QTimer::timeout, this, [] { 0031 QCoreApplication::instance()->exit(); 0032 }); 0033 exitAfterTimeOut(); 0034 } 0035 0036 void LocaleGenHelper::enableLocales(const QStringList &locales) 0037 { 0038 qDebug() << locales; 0039 if (m_timer.isActive()) { 0040 m_timer.stop(); 0041 } 0042 if (m_isGenerating) { 0043 Q_EMIT error(i18n("Another process is already running, please retry later")); 0044 exitAfterTimeOut(); 0045 return; 0046 } 0047 processLocales(locales); 0048 m_isGenerating = true; 0049 if (shouldGenerate()) { 0050 m_authority->checkAuthorization(QStringLiteral("org.kde.localegenhelper.enableLocales"), 0051 PolkitQt1::SystemBusNameSubject(message().service()), 0052 PolkitQt1::Authority::AllowUserInteraction); 0053 } else { 0054 exitAfterTimeOut(); 0055 Q_EMIT success(); 0056 } 0057 } 0058 0059 void LocaleGenHelper::enableLocalesPrivate(PolkitQt1::Authority::Result result) 0060 { 0061 qDebug() << result; 0062 if (result != PolkitQt1::Authority::Result::Yes) { 0063 Q_EMIT error(i18n("Unauthorized to edit locale configuration file")); 0064 exitAfterTimeOut(); 0065 return; 0066 } 0067 0068 // if success, handleLocaleGen will call exit 0069 if (editLocaleGen()) { 0070 exitAfterTimeOut(); 0071 } 0072 } 0073 0074 bool LocaleGenHelper::shouldGenerate() 0075 { 0076 QFile localegen(QStringLiteral("/etc/locale.gen")); 0077 if (!localegen.open(QIODevice::ReadOnly)) { 0078 return false; 0079 } 0080 m_alreadyEnabled.clear(); 0081 while (!localegen.atEnd()) { 0082 QString locale = localegen.readLine().simplified(); 0083 if (!m_comment && locale == QStringLiteral("# generated by KDE Plasma Region & Language KCM")) { 0084 m_comment = true; 0085 } 0086 if (locale.isEmpty() || locale.front() == QLatin1Char('#')) { 0087 continue; 0088 } 0089 QStringList localeAndCharset = locale.split(QLatin1Char(' ')); 0090 if (localeAndCharset.size() != 2 || localeAndCharset.at(1) != QStringLiteral("UTF-8")) { 0091 continue; 0092 } else { 0093 QString localeNameWithoutCharset = localeAndCharset.front().remove(QStringLiteral(".UTF-8")); 0094 m_alreadyEnabled.insert(localeNameWithoutCharset); 0095 } 0096 } 0097 for (const auto &locale : std::as_const(m_locales)) { 0098 if (locale == QStringLiteral("C")) { 0099 continue; 0100 } 0101 if (m_alreadyEnabled.count(locale) == 0) { 0102 return true; 0103 } 0104 } 0105 return false; 0106 } 0107 0108 bool LocaleGenHelper::editLocaleGen() 0109 { 0110 bool result = false; 0111 QFile localegen(QStringLiteral("/etc/locale.gen")); 0112 if (!localegen.open(QIODevice::Append)) { 0113 Q_EMIT error(i18n("Can't open file `/etc/locale.gen`")); 0114 return result; 0115 } 0116 for (const auto &locale : std::as_const(m_locales)) { 0117 if (m_alreadyEnabled.count(locale) || locale == QStringLiteral("C")) { 0118 continue; 0119 } 0120 // start at newline first time 0121 if (!m_comment) { 0122 localegen.write("\n# generated by KDE Plasma Region & Language KCM\n"); 0123 m_comment = true; 0124 } 0125 localegen.write(locale.toUtf8() + ".UTF-8 UTF-8\n"); 0126 } 0127 0128 QString localeGenPath = QStandardPaths::findExecutable(QStringLiteral("locale-gen")); 0129 if (localeGenPath.isEmpty()) { 0130 localeGenPath = QStandardPaths::findExecutable(QStringLiteral("locale-gen"), 0131 { 0132 QStringLiteral("/usr/sbin"), 0133 QStringLiteral("/sbin"), 0134 QStringLiteral("/usr/local/sbin"), 0135 }); 0136 } 0137 if (!localeGenPath.isEmpty()) { 0138 auto *process = new QProcess(this); 0139 process->setProgram(localeGenPath); 0140 connect(process, &QProcess::finished, this, [this, process](int statusCode, QProcess::ExitStatus status) { 0141 handleLocaleGen(statusCode, status, process); 0142 }); 0143 process->start(); 0144 result = true; 0145 } else { 0146 Q_EMIT error(i18n("Can't locate executable `locale-gen`")); 0147 } 0148 return result; 0149 } 0150 0151 void LocaleGenHelper::handleLocaleGen(int statusCode, QProcess::ExitStatus status, QProcess *process) 0152 { 0153 Q_UNUSED(status) 0154 if (statusCode == 0) { 0155 Q_EMIT success(); 0156 } else { 0157 QString all_error; 0158 if (!process) { 0159 all_error = i18n("Unknown"); 0160 } else { 0161 all_error.append(process->readAllStandardOutput()); 0162 all_error.append(QChar('\n')); 0163 all_error.append(process->readAllStandardError()); 0164 } 0165 Q_EMIT error(all_error); 0166 } 0167 exitAfterTimeOut(); 0168 } 0169 0170 void LocaleGenHelper::exitAfterTimeOut() 0171 { 0172 m_isGenerating = false; 0173 m_timer.start(30s); 0174 } 0175 0176 void LocaleGenHelper::processLocales(const QStringList &locales) 0177 { 0178 QStringList processedLocales = locales; 0179 for (auto &locale : processedLocales) { 0180 locale.remove(QStringLiteral(".UTF-8")); 0181 if (locale == QStringLiteral("C")) { 0182 continue; 0183 } 0184 } 0185 m_locales = std::move(processedLocales); 0186 } 0187 0188 int main(int argc, char *argv[]) 0189 { 0190 QCoreApplication app(argc, argv); 0191 LocaleGenHelper generator; 0192 return app.exec(); 0193 }