File indexing completed on 2024-06-02 05:43:47
0001 /* 0002 KHelper - KDE Font Installer 0003 0004 SPDX-FileCopyrightText: 2003-2010 Craig Drummond <craig@kde.org> 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "Helper.h" 0009 #include "Folder.h" 0010 #include "FontInst.h" 0011 #include "Misc.h" 0012 #include "Utils.h" 0013 #include <KAuth/HelperSupport> 0014 #include <QCoreApplication> 0015 #include <QDebug> 0016 #include <QDomDocument> 0017 #include <kio/global.h> 0018 #include <signal.h> 0019 #include <sys/errno.h> 0020 #include <sys/types.h> 0021 #include <unistd.h> 0022 0023 KAUTH_HELPER_MAIN("org.kde.fontinst", KFI::Helper) 0024 0025 namespace KFI 0026 { 0027 static Folder theFontFolder; 0028 0029 typedef void (*SignalHandler)(int); 0030 0031 static void registerSignalHandler(SignalHandler handler) 0032 { 0033 if (!handler) { 0034 handler = SIG_DFL; 0035 } 0036 0037 sigset_t mask; 0038 sigemptyset(&mask); 0039 0040 #ifdef SIGSEGV 0041 signal(SIGSEGV, handler); 0042 sigaddset(&mask, SIGSEGV); 0043 #endif 0044 #ifdef SIGFPE 0045 signal(SIGFPE, handler); 0046 sigaddset(&mask, SIGFPE); 0047 #endif 0048 #ifdef SIGILL 0049 signal(SIGILL, handler); 0050 sigaddset(&mask, SIGILL); 0051 #endif 0052 #ifdef SIGABRT 0053 signal(SIGABRT, handler); 0054 sigaddset(&mask, SIGABRT); 0055 #endif 0056 0057 sigprocmask(SIG_UNBLOCK, &mask, nullptr); 0058 } 0059 0060 static void signalHander(int) 0061 { 0062 static bool inHandler = false; 0063 0064 if (!inHandler) { 0065 inHandler = true; 0066 theFontFolder.saveDisabled(); 0067 inHandler = false; 0068 } 0069 } 0070 0071 static void cleanup() 0072 { 0073 theFontFolder.saveDisabled(); 0074 } 0075 0076 Helper::Helper() 0077 { 0078 registerSignalHandler(signalHander); 0079 qAddPostRoutine(cleanup); 0080 theFontFolder.init(true, true); 0081 theFontFolder.loadDisabled(); 0082 } 0083 0084 Helper::~Helper() 0085 { 0086 theFontFolder.saveDisabled(); 0087 } 0088 0089 ActionReply Helper::manage(const QVariantMap &args) 0090 { 0091 int result = KIO::ERR_UNSUPPORTED_ACTION; 0092 QString method = args["method"].toString(); 0093 0094 // qDebug() << method; 0095 0096 if ("install" == method) { 0097 result = install(args); 0098 } else if ("uninstall" == method) { 0099 result = uninstall(args); 0100 } else if ("move" == method) { 0101 result = move(args); 0102 } else if ("toggle" == method) { 0103 result = toggle(args); 0104 } else if ("removeFile" == method) { 0105 result = removeFile(args); 0106 } else if ("reconfigure" == method) { 0107 result = reconfigure(); 0108 } else if ("saveDisabled" == method) { 0109 result = saveDisabled(); 0110 } else { 0111 // qDebug() << "Uknown action"; 0112 } 0113 0114 if (FontInst::STATUS_OK == result) { 0115 return ActionReply::SuccessReply(); 0116 } 0117 0118 ActionReply reply(ActionReply::HelperErrorType); 0119 reply.setErrorCode(static_cast<KAuth::ActionReply::Error>(result)); 0120 return reply; 0121 } 0122 0123 int Helper::install(const QVariantMap &args) 0124 { 0125 QString file(args["file"].toString()), name(args["name"].toString()), destFolder(args["destFolder"].toString()); 0126 bool createAfm(args["createAfm"].toBool()); 0127 int type(args["type"].toInt()); 0128 0129 // qDebug() << file << destFolder << name << createAfm; 0130 0131 int result = FontInst::STATUS_OK; 0132 0133 if (!Misc::dExists(destFolder)) { 0134 result = Misc::createDir(destFolder) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; 0135 } 0136 0137 if (FontInst::STATUS_OK == result) { 0138 result = QFile::copy(file, destFolder + name) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; 0139 } 0140 0141 if (FontInst::STATUS_OK == result) { 0142 Misc::setFilePerms(QFile::encodeName(destFolder + name)); 0143 if ((Utils::FILE_SCALABLE == type || Utils::FILE_PFM == type) && createAfm) { 0144 Utils::createAfm(destFolder + name, (KFI::Utils::EFileType)type); 0145 } 0146 theFontFolder.addModifiedDir(destFolder); 0147 } 0148 0149 return result; 0150 } 0151 0152 int Helper::uninstall(const QVariantMap &args) 0153 { 0154 QStringList files(args["files"].toStringList()); 0155 int result = checkWriteAction(files); 0156 0157 if (FontInst::STATUS_OK == result) { 0158 QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); 0159 0160 for (; it != end; ++it) { 0161 if (!Misc::fExists(*it) || QFile::remove(*it)) { 0162 // Also remove any AFM or PFM files... 0163 QStringList other; 0164 Misc::getAssociatedFiles(*it, other); 0165 QStringList::ConstIterator oit(other.constBegin()), oend(other.constEnd()); 0166 for (; oit != oend; ++oit) { 0167 QFile::remove(*oit); 0168 } 0169 0170 theFontFolder.addModifiedDir(Misc::getDir(*it)); 0171 } 0172 } 0173 } 0174 0175 return result; 0176 } 0177 0178 static bool renameFontFile(const QString &from, const QString &to, int uid = -1, int gid = -1) 0179 { 0180 if (!QFile::rename(from, to)) { 0181 return false; 0182 } 0183 0184 QByteArray dest(QFile::encodeName(to)); 0185 0186 Misc::setFilePerms(dest); 0187 if (-1 != uid && -1 != gid) { 0188 ::chown(dest.data(), uid, gid); 0189 } 0190 return true; 0191 } 0192 0193 int Helper::move(const QVariantMap &args) 0194 { 0195 QStringList files(args["files"].toStringList()); 0196 bool toSystem(args["toSystem"].toBool()); 0197 QString dest(args["dest"].toString()); 0198 int uid(args["uid"].toInt()), gid(args["gid"].toInt()); 0199 0200 // qDebug() << files << dest << toSystem; 0201 0202 int result = FontInst::STATUS_OK; 0203 QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); 0204 0205 // Cant move hidden fonts - need to unhide first. 0206 for (; it != end && FontInst::STATUS_OK == result; ++it) { 0207 if (Misc::isHidden(Misc::getFile(*it))) { 0208 result = KIO::ERR_UNSUPPORTED_ACTION; 0209 } 0210 } 0211 0212 if (FontInst::STATUS_OK == result) { 0213 QHash<QString, QString> movedFiles; 0214 int toUid = toSystem ? getuid() : uid, fromUid = toSystem ? uid : getuid(), toGid = toSystem ? getgid() : gid, fromGid = toSystem ? gid : getgid(); 0215 0216 // Move fonts! 0217 for (it = files.constBegin(); it != end && FontInst::STATUS_OK == result; ++it) { 0218 QString name(Misc::modifyName(Misc::getFile(*it))), destFolder(Misc::getDestFolder(dest, name)); 0219 0220 if (!Misc::dExists(destFolder)) { 0221 result = Misc::createDir(destFolder) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED; 0222 if (FontInst::STATUS_OK == result) { 0223 ::chown(QFile::encodeName(destFolder).data(), toUid, toGid); 0224 } 0225 } 0226 0227 if (renameFontFile(*it, destFolder + name, toUid, toGid)) { 0228 movedFiles[*it] = destFolder + name; 0229 // Now try to move an associated AFM or PFM files... 0230 QStringList assoc; 0231 0232 Misc::getAssociatedFiles(*it, assoc); 0233 0234 QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); 0235 0236 for (; ait != aend && FontInst::STATUS_OK == result; ++ait) { 0237 name = Misc::getFile(*ait); 0238 if (renameFontFile(*ait, destFolder + name, toUid, toGid)) { 0239 movedFiles[*ait] = destFolder + name; 0240 } else { 0241 result = KIO::ERR_WRITE_ACCESS_DENIED; 0242 } 0243 } 0244 0245 if (toSystem) { 0246 theFontFolder.addModifiedDir(theFontFolder.location()); 0247 } 0248 } else { 0249 result = KIO::ERR_WRITE_ACCESS_DENIED; 0250 } 0251 } 0252 0253 if (FontInst::STATUS_OK != result) // un-move fonts! 0254 { 0255 QHash<QString, QString>::ConstIterator it(movedFiles.constBegin()), end(movedFiles.constEnd()); 0256 0257 for (; it != end; ++it) { 0258 renameFontFile(it.value(), it.key(), fromUid, fromGid); 0259 } 0260 } 0261 } 0262 return result; 0263 } 0264 0265 int Helper::toggle(const QVariantMap &args) 0266 { 0267 QDomDocument doc; 0268 doc.setContent(args["xml"].toString()); 0269 Family font(doc.documentElement(), true); 0270 bool enable(args["enable"].toBool()); 0271 0272 // qDebug() << font.name() << enable; 0273 0274 if (1 != font.styles().count()) { 0275 return KIO::ERR_WRITE_ACCESS_DENIED; 0276 } 0277 0278 int result = FontInst::STATUS_OK; 0279 FileCont files((*font.styles().begin()).files()), toggledFiles; 0280 FileCont::ConstIterator it(files.constBegin()), end(files.constEnd()); 0281 QHash<File, QString> movedFonts; 0282 QHash<QString, QString> movedAssoc; 0283 QSet<QString> modifiedDirs; 0284 // Move fonts! 0285 for (; it != end && FontInst::STATUS_OK == result; ++it) { 0286 QString to = Misc::getDir((*it).path()) + QString(enable ? Misc::unhide(Misc::getFile((*it).path())) : Misc::hide(Misc::getFile((*it).path()))); 0287 0288 if (to != (*it).path()) { 0289 // qDebug() << "MOVE:" << (*it).path() << " to " << to; 0290 if (renameFontFile((*it).path(), to)) { 0291 modifiedDirs.insert(Misc::getDir(enable ? to : (*it).path())); 0292 toggledFiles.insert(File(to, (*it).foundry(), (*it).index())); 0293 // Now try to move an associated AFM or PFM files... 0294 QStringList assoc; 0295 0296 movedFonts[*it] = to; 0297 Misc::getAssociatedFiles((*it).path(), assoc); 0298 0299 QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd()); 0300 0301 for (; ait != aend && FontInst::STATUS_OK == result; ++ait) { 0302 to = Misc::getDir(*ait) + QString(enable ? Misc::unhide(Misc::getFile(*ait)) : Misc::hide(Misc::getFile(*ait))); 0303 0304 if (to != *ait) { 0305 if (renameFontFile(*ait, to)) { 0306 movedAssoc[*ait] = to; 0307 } else { 0308 result = KIO::ERR_WRITE_ACCESS_DENIED; 0309 } 0310 } 0311 } 0312 } else { 0313 result = KIO::ERR_WRITE_ACCESS_DENIED; 0314 } 0315 } 0316 } 0317 0318 theFontFolder.addModifiedDirs(modifiedDirs); 0319 0320 if (FontInst::STATUS_OK == result) { 0321 FamilyCont::ConstIterator f = theFontFolder.fonts().find(font); 0322 0323 if (theFontFolder.fonts().end() == f) { 0324 f = theFontFolder.addFont(font); 0325 } 0326 0327 StyleCont::ConstIterator st = (*f).styles().find(*font.styles().begin()); 0328 0329 if ((*f).styles().end() == st) { 0330 st = (*f).add(*font.styles().begin()); 0331 } 0332 0333 // This helper only needs to store list of disabled fonts, 0334 // for writing back to disk - therefore no need to store 0335 // list of enabled font files. 0336 FileCont empty; 0337 (*st).setFiles(enable ? empty : toggledFiles); 0338 if ((*st).files().isEmpty()) { 0339 (*f).remove(*st); 0340 } 0341 if ((*f).styles().isEmpty()) { 0342 theFontFolder.removeFont(*f); 0343 } 0344 theFontFolder.setDisabledDirty(); 0345 } else { 0346 QHash<File, QString>::ConstIterator fit(movedFonts.constBegin()), fend(movedFonts.constEnd()); 0347 QHash<QString, QString>::ConstIterator ait(movedAssoc.constBegin()), aend(movedAssoc.constEnd()); 0348 0349 for (; fit != fend; ++fit) { 0350 renameFontFile(fit.value(), fit.key().path()); 0351 } 0352 for (; ait != aend; ++ait) { 0353 renameFontFile(ait.value(), ait.key()); 0354 } 0355 } 0356 0357 return result; 0358 } 0359 0360 int Helper::removeFile(const QVariantMap &args) 0361 { 0362 QString file(args["file"].toString()); 0363 0364 // qDebug() << file; 0365 0366 QString dir(Misc::getDir(file)); 0367 int result = Misc::fExists(file) ? QFile::remove(file) ? (int)FontInst::STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED : (int)KIO::ERR_DOES_NOT_EXIST; 0368 0369 if (FontInst::STATUS_OK == result) { 0370 theFontFolder.addModifiedDir(dir); 0371 } 0372 0373 return result; 0374 } 0375 0376 int Helper::reconfigure() 0377 { 0378 saveDisabled(); 0379 // qDebug() << theFontFolder.isModified(); 0380 if (theFontFolder.isModified()) { 0381 theFontFolder.configure(); 0382 } 0383 return FontInst::STATUS_OK; 0384 } 0385 0386 int Helper::saveDisabled() 0387 { 0388 // Load internally calls save! 0389 theFontFolder.loadDisabled(); 0390 return FontInst::STATUS_OK; 0391 } 0392 0393 int Helper::checkWriteAction(const QStringList &files) 0394 { 0395 QStringList::ConstIterator it(files.constBegin()), end(files.constEnd()); 0396 0397 for (; it != end; ++it) { 0398 if (!Misc::dWritable(Misc::getDir(*it))) { 0399 return KIO::ERR_WRITE_ACCESS_DENIED; 0400 } 0401 } 0402 return FontInst::STATUS_OK; 0403 } 0404 0405 }