/* KHelper - KDE Font Installer SPDX-FileCopyrightText: 2003-2010 Craig Drummond SPDX-License-Identifier: GPL-2.0-or-later */ #include "Helper.h" #include "Folder.h" #include "FontInst.h" #include "Misc.h" #include "Utils.h" #include #include #include #include #include #include #include #include #include KAUTH_HELPER_MAIN("org.kde.fontinst", KFI::Helper) using namespace Qt::StringLiterals; namespace KFI { static Folder theFontFolder; typedef void (*SignalHandler)(int); static void registerSignalHandler(SignalHandler handler) { if (!handler) { handler = SIG_DFL; } sigset_t mask; sigemptyset(&mask); #ifdef SIGSEGV signal(SIGSEGV, handler); sigaddset(&mask, SIGSEGV); #endif #ifdef SIGFPE signal(SIGFPE, handler); sigaddset(&mask, SIGFPE); #endif #ifdef SIGILL signal(SIGILL, handler); sigaddset(&mask, SIGILL); #endif #ifdef SIGABRT signal(SIGABRT, handler); sigaddset(&mask, SIGABRT); #endif sigprocmask(SIG_UNBLOCK, &mask, nullptr); } static void signalHander(int) { static bool inHandler = false; if (!inHandler) { inHandler = true; theFontFolder.saveDisabled(); inHandler = false; } } static void cleanup() { theFontFolder.saveDisabled(); } Helper::Helper() { registerSignalHandler(signalHander); qAddPostRoutine(cleanup); theFontFolder.init(true, true); theFontFolder.loadDisabled(); } Helper::~Helper() { theFontFolder.saveDisabled(); } ActionReply Helper::manage(const QVariantMap &args) { int result = KIO::ERR_UNSUPPORTED_ACTION; QString method = args[u"method"_s].toString(); // qDebug() << method; if (u"install" == method) { result = install(args); } else if (u"uninstall" == method) { result = uninstall(args); } else if (u"move" == method) { result = move(args); } else if (u"toggle" == method) { result = toggle(args); } else if (u"removeFile" == method) { result = removeFile(args); } else if (u"reconfigure" == method) { result = reconfigure(); } else if (u"saveDisabled" == method) { result = saveDisabled(); } else { // qDebug() << "Uknown action"; } if (FontInst::STATUS_OK == result) { return ActionReply::SuccessReply(); } ActionReply reply(ActionReply::HelperErrorType); reply.setErrorCode(static_cast(result)); return reply; } int Helper::install(const QVariantMap &args) { QString file(args[u"file"_s].toString()), name(args[u"name"_s].toString()), destFolder(args[u"destFolder"_s].toString()); bool createAfm(args[u"createAfm"_s].toBool()); int type(args[u"type"_s].toInt()); // qDebug() << file << destFolder << name << createAfm; int result = FontInst::STATUS_OK; if (!Misc::dExists(destFolder)) { result = Misc::createDir(destFolder) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; } if (FontInst::STATUS_OK == result) { result = QFile::copy(file, destFolder + name) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; } if (FontInst::STATUS_OK == result) { Misc::setFilePerms(QFile::encodeName(destFolder + name)); if ((Utils::FILE_SCALABLE == type || Utils::FILE_PFM == type) && createAfm) { Utils::createAfm(destFolder + name, (KFI::Utils::EFileType)type); } theFontFolder.addModifiedDir(destFolder); } return result; } int Helper::uninstall(const QVariantMap &args) { QStringList files(args[u"files"_s].toStringList()); int result = checkWriteAction(files); if (FontInst::STATUS_OK == result) { QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); for (; it != end; ++it) { if (!Misc::fExists(*it) || QFile::remove(*it)) { // Also remove any AFM or PFM files... QStringList other; Misc::getAssociatedFiles(*it, other); QStringList::ConstIterator oit(other.constBegin()), oend(other.constEnd()); for (; oit != oend; ++oit) { QFile::remove(*oit); } theFontFolder.addModifiedDir(Misc::getDir(*it)); } } } return result; } static bool renameFontFile(const QString &from, const QString &to, int uid = -1, int gid = -1) { if (!QFile::rename(from, to)) { return false; } QByteArray dest(QFile::encodeName(to)); Misc::setFilePerms(dest); if (-1 != uid && -1 != gid) { ::chown(dest.data(), uid, gid); } return true; } int Helper::move(const QVariantMap &args) { QStringList files(args[u"files"_s].toStringList()); bool toSystem(args[u"toSystem"_s].toBool()); QString dest(args[u"dest"_s].toString()); int uid(args[u"uid"_s].toInt()), gid(args[u"gid"_s].toInt()); // qDebug() << files << dest << toSystem; int result = FontInst::STATUS_OK; QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); // Cant move hidden fonts - need to unhide first. for (; it != end && FontInst::STATUS_OK == result; ++it) { if (Misc::isHidden(Misc::getFile(*it))) { result = KIO::ERR_UNSUPPORTED_ACTION; } } if (FontInst::STATUS_OK == result) { QHash movedFiles; int toUid = toSystem ? getuid() : uid, fromUid = toSystem ? uid : getuid(), toGid = toSystem ? getgid() : gid, fromGid = toSystem ? gid : getgid(); // Move fonts! for (it = files.constBegin(); it != end && FontInst::STATUS_OK == result; ++it) { QString name(Misc::modifyName(Misc::getFile(*it))), destFolder(Misc::getDestFolder(dest, name)); if (!Misc::dExists(destFolder)) { result = Misc::createDir(destFolder) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; if (FontInst::STATUS_OK == result) { ::chown(QFile::encodeName(destFolder).data(), toUid, toGid); } } if (renameFontFile(*it, destFolder + name, toUid, toGid)) { movedFiles[*it] = destFolder + name; // Now try to move an associated AFM or PFM files... QStringList assoc; Misc::getAssociatedFiles(*it, assoc); QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); for (; ait != aend && FontInst::STATUS_OK == result; ++ait) { name = Misc::getFile(*ait); if (renameFontFile(*ait, destFolder + name, toUid, toGid)) { movedFiles[*ait] = destFolder + name; } else { result = KIO::ERR_WRITE_ACCESS_DENIED; } } if (toSystem) { theFontFolder.addModifiedDir(theFontFolder.location()); } } else { result = KIO::ERR_WRITE_ACCESS_DENIED; } } if (FontInst::STATUS_OK != result) // un-move fonts! { QHash::ConstIterator it(movedFiles.constBegin()), end(movedFiles.constEnd()); for (; it != end; ++it) { renameFontFile(it.value(), it.key(), fromUid, fromGid); } } } return result; } int Helper::toggle(const QVariantMap &args) { QDomDocument doc; doc.setContent(args[u"xml"_s].toString()); Family font(doc.documentElement(), true); bool enable(args[u"enable"_s].toBool()); // qDebug() << font.name() << enable; if (1 != font.styles().count()) { return KIO::ERR_WRITE_ACCESS_DENIED; } int result = FontInst::STATUS_OK; FileCont files((*font.styles().begin()).files()), toggledFiles; FileCont::ConstIterator it(files.constBegin()), end(files.constEnd()); QHash movedFonts; QHash movedAssoc; QSet modifiedDirs; // Move fonts! for (; it != end && FontInst::STATUS_OK == result; ++it) { QString to = Misc::getDir((*it).path()) + QString(enable ? Misc::unhide(Misc::getFile((*it).path())) : Misc::hide(Misc::getFile((*it).path()))); if (to != (*it).path()) { // qDebug() << "MOVE:" << (*it).path() << " to " << to; if (renameFontFile((*it).path(), to)) { modifiedDirs.insert(Misc::getDir(enable ? to : (*it).path())); toggledFiles.insert(File(to, (*it).foundry(), (*it).index())); // Now try to move an associated AFM or PFM files... QStringList assoc; movedFonts[*it] = to; Misc::getAssociatedFiles((*it).path(), assoc); QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); for (; ait != aend && FontInst::STATUS_OK == result; ++ait) { to = Misc::getDir(*ait) + QString(enable ? Misc::unhide(Misc::getFile(*ait)) : Misc::hide(Misc::getFile(*ait))); if (to != *ait) { if (renameFontFile(*ait, to)) { movedAssoc[*ait] = to; } else { result = KIO::ERR_WRITE_ACCESS_DENIED; } } } } else { result = KIO::ERR_WRITE_ACCESS_DENIED; } } } theFontFolder.addModifiedDirs(modifiedDirs); if (FontInst::STATUS_OK == result) { FamilyCont::ConstIterator f = theFontFolder.fonts().find(font); if (theFontFolder.fonts().end() == f) { f = theFontFolder.addFont(font); } StyleCont::ConstIterator st = (*f).styles().find(*font.styles().begin()); if ((*f).styles().end() == st) { st = (*f).add(*font.styles().begin()); } // This helper only needs to store list of disabled fonts, // for writing back to disk - therefore no need to store // list of enabled font files. FileCont empty; (*st).setFiles(enable ? empty : toggledFiles); if ((*st).files().isEmpty()) { (*f).remove(*st); } if ((*f).styles().isEmpty()) { theFontFolder.removeFont(*f); } theFontFolder.setDisabledDirty(); } else { QHash::ConstIterator fit(movedFonts.constBegin()), fend(movedFonts.constEnd()); QHash::ConstIterator ait(movedAssoc.constBegin()), aend(movedAssoc.constEnd()); for (; fit != fend; ++fit) { renameFontFile(fit.value(), fit.key().path()); } for (; ait != aend; ++ait) { renameFontFile(ait.value(), ait.key()); } } return result; } int Helper::removeFile(const QVariantMap &args) { QString file(args[u"file"_s].toString()); // qDebug() << file; QString dir(Misc::getDir(file)); int result = Misc::fExists(file) ? QFile::remove(file) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED : (int)KIO::ERR_DOES_NOT_EXIST; if (FontInst::STATUS_OK == result) { theFontFolder.addModifiedDir(dir); } return result; } int Helper::reconfigure() { saveDisabled(); // qDebug() << theFontFolder.isModified(); if (theFontFolder.isModified()) { theFontFolder.configure(); } return FontInst::STATUS_OK; } int Helper::saveDisabled() { // Load internally calls save! theFontFolder.loadDisabled(); return FontInst::STATUS_OK; } int Helper::checkWriteAction(const QStringList &files) { QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); for (; it != end; ++it) { if (!Misc::dWritable(Misc::getDir(*it))) { return KIO::ERR_WRITE_ACCESS_DENIED; } } return FontInst::STATUS_OK; } }