2022-03-05 22:41:29 +05:00

890 lines
30 KiB
C++

/*
SPDX-FileCopyrightText: 2003-2009 Craig Drummond <craig@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "FontInst.h"
#include "Fc.h"
#include "Misc.h"
#include "Utils.h"
#include "WritingSystems.h"
#include "fontinstadaptor.h"
#include "kfontinst_debug.h"
#include <KAuth>
#include <QDebug>
#include <QTimer>
#include <fontconfig/fontconfig.h>
#include <kio/global.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
namespace KFI
{
static void decompose(const QString &name, QString &family, QString &style)
{
int commaPos = name.lastIndexOf(',');
family = -1 == commaPos ? name : name.left(commaPos);
style = -1 == commaPos ? KFI_WEIGHT_REGULAR : name.mid(commaPos + 2);
}
static bool isSystem = false;
static Folder theFolders[FontInst::FOLDER_COUNT];
static const int constSystemReconfigured = -1;
static const int constConnectionsTimeout = 30 * 1000;
static const int constFontListTimeout = 10 * 1000;
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);
}
void signalHander(int)
{
static bool inHandler = false;
if (!inHandler) {
inHandler = true;
theFolders[isSystem ? FontInst::FOLDER_SYS : FontInst::FOLDER_USER].saveDisabled();
inHandler = false;
}
}
FontInst::FontInst()
{
isSystem = Misc::root();
registerTypes();
new FontinstAdaptor(this);
QDBusConnection bus = QDBusConnection::sessionBus();
// qDebug() << "Connecting to session bus";
if (!bus.registerService(OrgKdeFontinstInterface::staticInterfaceName())) {
// qDebug() << "Failed to register service!";
::exit(-1);
}
if (!bus.registerObject(FONTINST_PATH, this)) {
// qDebug() << "Failed to register object!";
::exit(-1);
}
registerSignalHandler(signalHander);
m_connectionsTimer = new QTimer(this);
m_fontListTimer = new QTimer(this);
connect(m_connectionsTimer, &QTimer::timeout, this, &FontInst::connectionsTimeout);
connect(m_fontListTimer, &QTimer::timeout, this, &FontInst::fontListTimeout);
m_connectionsTimer->start(constConnectionsTimeout);
m_fontListTimer->start(constFontListTimeout);
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT); ++i) {
theFolders[i].init(FOLDER_SYS == i, isSystem);
}
updateFontList(false);
}
FontInst::~FontInst()
{
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT); ++i) {
theFolders[i].saveDisabled();
}
}
void FontInst::list(int folders, int pid)
{
// qDebug() << folders << pid;
m_connections.insert(pid);
updateFontList(false);
QList<KFI::Families> fonts;
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT); ++i) {
if (0 == folders || folders & (1 << i)) {
fonts += theFolders[i].list();
}
}
m_connectionsTimer->start(constConnectionsTimeout);
m_fontListTimer->start(constFontListTimeout);
Q_EMIT fontList(pid, fonts);
}
void FontInst::statFont(const QString &name, int folders, int pid)
{
// qDebug() << name << folders << pid;
bool checkSystem = 0 == folders || folders & SYS_MASK || isSystem, checkUser = 0 == folders || (folders & USR_MASK && !isSystem);
FamilyCont::ConstIterator fam;
StyleCont::ConstIterator st;
m_connections.insert(pid);
if ((checkSystem && findFont(name, FOLDER_SYS, fam, st)) || (checkUser && findFont(name, FOLDER_USER, fam, st, !checkSystem))) {
Family rv((*fam).name());
rv.add(*st);
// qDebug() << "Found font, Q_EMIT details...";
Q_EMIT fontStat(pid, rv);
} else {
// qDebug() << "Font not found, Q_EMIT empty details...";
Q_EMIT fontStat(pid, Family(name));
}
}
void FontInst::install(const QString &file, bool createAfm, bool toSystem, int pid, bool checkConfig)
{
// qDebug() << file << createAfm << toSystem << pid << checkConfig;
m_connections.insert(pid);
if (checkConfig) {
updateFontList();
}
EFolder folder = isSystem || toSystem ? FOLDER_SYS : FOLDER_USER;
Family font;
Utils::EFileType type = Utils::check(file, font);
int result = Utils::FILE_BITMAP == type && !FC::bitmapsEnabled() ? STATUS_BITMAPS_DISABLED : Utils::FILE_INVALID == type ? STATUS_NOT_FONT_FILE : STATUS_OK;
if (STATUS_OK == result) {
if (Utils::FILE_AFM != type && Utils::FILE_PFM != type) {
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT) && STATUS_OK == result; ++i) {
if (theFolders[i].contains(font.name(), (*font.styles().begin()).value())) {
result = STATUS_ALREADY_INSTALLED;
}
}
}
if (STATUS_OK == result) {
QString name(Misc::modifyName(Misc::getFile(file))), destFolder(Misc::getDestFolder(theFolders[folder].location(), name));
result = Utils::FILE_AFM != type && Utils::FILE_PFM != type && Misc::fExists(destFolder + name) ? (int)KIO::ERR_FILE_ALREADY_EXIST : (int)STATUS_OK;
if (STATUS_OK == result) {
if (toSystem && !isSystem) {
// qDebug() << "Send request to system helper" << file << destFolder << name;
QVariantMap args;
args["method"] = "install";
args["file"] = file;
args["name"] = name;
args["destFolder"] = destFolder;
args["createAfm"] = createAfm;
args["type"] = (int)type;
result = performAction(args);
} else {
if (!Misc::dExists(destFolder)) {
result = Misc::createDir(destFolder) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED;
}
if (STATUS_OK == result) {
result = QFile::copy(file, destFolder + name) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED;
}
if (STATUS_OK == result) {
Misc::setFilePerms(QFile::encodeName(destFolder + name));
if ((Utils::FILE_SCALABLE == type || Utils::FILE_PFM == type) && createAfm) {
Utils::createAfm(destFolder + name, type);
}
}
}
if (STATUS_OK == result && Utils::FILE_AFM != type && Utils::FILE_PFM != type) {
StyleCont::ConstIterator st(font.styles().begin());
FileCont::ConstIterator f((*st).files().begin());
File df(destFolder + name, (*f).foundry(), (*f).index());
(*st).clearFiles();
(*st).add(df);
theFolders[folder].add(font);
theFolders[folder].addModifiedDir(destFolder);
Q_EMIT fontsAdded(Families(font, FOLDER_SYS == folder));
}
}
}
}
Q_EMIT status(pid, result);
m_connectionsTimer->start(constConnectionsTimeout);
m_fontListTimer->start(constFontListTimeout);
}
void FontInst::uninstall(const QString &family, quint32 style, bool fromSystem, int pid, bool checkConfig)
{
// qDebug() << family << style << fromSystem << pid << checkConfig;
m_connections.insert(pid);
if (checkConfig) {
updateFontList();
}
EFolder folder = isSystem || fromSystem ? FOLDER_SYS : FOLDER_USER;
FamilyCont::ConstIterator fam;
StyleCont::ConstIterator st;
int result = findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST;
if (STATUS_OK == result) {
Family del((*fam).name());
Style s((*st).value(), (*st).scalable(), (*st).writingSystems());
FileCont files((*st).files());
FileCont::ConstIterator it(files.begin()), end(files.end());
if (fromSystem && !isSystem) {
QStringList fileList;
bool wasDisabled(false);
for (; it != end; ++it) {
fileList.append((*it).path());
theFolders[FOLDER_SYS].addModifiedDir(Misc::getDir((*it).path()));
if (!wasDisabled && Misc::isHidden(Misc::getFile((*it).path()))) {
wasDisabled = true;
}
}
QVariantMap args;
args["method"] = "uninstall";
args["files"] = fileList;
result = performAction(args);
if (STATUS_OK == result) {
FileCont empty;
s.setFiles(files);
(*st).setFiles(empty);
if (wasDisabled) {
theFolders[FOLDER_SYS].setDisabledDirty();
}
}
} else {
for (; it != end; ++it) {
if (!Misc::fExists((*it).path()) || QFile::remove((*it).path())) {
// Also remove any AFM or PFM files...
QStringList other;
Misc::getAssociatedFiles((*it).path(), other);
QStringList::ConstIterator oit(other.constBegin()), oend(other.constEnd());
for (; oit != oend; ++oit) {
QFile::remove(*oit);
}
theFolders[folder].addModifiedDir(Misc::getDir((*it).path()));
(*st).remove(*it);
s.add(*it);
if (!theFolders[folder].disabledDirty() && Misc::isHidden(Misc::getFile((*it).path()))) {
theFolders[folder].setDisabledDirty();
}
}
}
}
if (STATUS_OK == result) {
if ((*st).files().isEmpty()) {
(*fam).remove(*st);
if ((*fam).styles().isEmpty()) {
theFolders[folder].removeFont(*fam);
}
} else {
result = STATUS_PARTIAL_DELETE;
}
del.add(s);
}
Q_EMIT fontsRemoved(Families(del, FOLDER_SYS == folder));
}
// qDebug() << "status" << result;
Q_EMIT status(pid, result);
m_connectionsTimer->start(constConnectionsTimeout);
m_fontListTimer->start(constFontListTimeout);
}
void FontInst::uninstall(const QString &name, bool fromSystem, int pid, bool checkConfig)
{
// qDebug() << name << fromSystem << pid << checkConfig;
FamilyCont::ConstIterator fam;
StyleCont::ConstIterator st;
if (findFont(name, fromSystem || isSystem ? FOLDER_SYS : FOLDER_USER, fam, st)) {
uninstall((*fam).name(), (*st).value(), fromSystem, pid, checkConfig);
} else {
Q_EMIT status(pid, KIO::ERR_DOES_NOT_EXIST);
}
}
void FontInst::move(const QString &family, quint32 style, bool toSystem, int pid, bool checkConfig)
{
// qDebug() << family << style << toSystem << pid << checkConfig;
m_connections.insert(pid);
if (checkConfig) {
updateFontList();
}
if (isSystem) {
Q_EMIT status(pid, KIO::ERR_UNSUPPORTED_ACTION);
} else {
FamilyCont::ConstIterator fam;
StyleCont::ConstIterator st;
EFolder from = toSystem ? FOLDER_USER : FOLDER_SYS, to = toSystem ? FOLDER_SYS : FOLDER_USER;
if (findFont(family, style, from, fam, st)) {
FileCont::ConstIterator it((*st).files().begin()), end((*st).files().end());
QStringList files;
for (; it != end; ++it) {
files.append((*it).path());
theFolders[from].addModifiedDir(Misc::getDir((*it).path()));
// Actual 'to' folder does not really matter, as we only want to call fc-cache
// ...actual folders only matter for xreating fonts.dir, etc, and we wont be doing this...
theFolders[to].addModifiedDir(theFolders[to].location());
}
QVariantMap args;
args["method"] = "move";
args["files"] = files;
args["toSystem"] = toSystem;
args["dest"] = theFolders[to].location();
args["uid"] = getuid();
args["gid"] = getgid();
int result = performAction(args);
if (STATUS_OK == result) {
updateFontList();
}
Q_EMIT status(pid, result);
} else {
// qDebug() << "does not exist";
Q_EMIT status(pid, KIO::ERR_DOES_NOT_EXIST);
}
}
m_connectionsTimer->start(constConnectionsTimeout);
m_fontListTimer->start(constFontListTimeout);
}
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;
}
void FontInst::enable(const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig)
{
// qDebug() << family << style << inSystem << pid << checkConfig;
toggle(true, family, style, inSystem, pid, checkConfig);
}
void FontInst::disable(const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig)
{
// qDebug() << family << style << inSystem << pid << checkConfig;
toggle(false, family, style, inSystem, pid, checkConfig);
}
void FontInst::removeFile(const QString &family, quint32 style, const QString &file, bool fromSystem, int pid, bool checkConfig)
{
// qDebug() << family << style << file << fromSystem << pid << checkConfig;
m_connections.insert(pid);
if (checkConfig) {
updateFontList();
}
// First find the family/style
EFolder folder = isSystem || fromSystem ? FOLDER_SYS : FOLDER_USER;
FamilyCont::ConstIterator fam;
StyleCont::ConstIterator st;
int result = findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST;
if (STATUS_OK == result) {
// Family/style found - now check that the requested file is *within* the same folder as one
// of the files linked to this font...
FileCont files((*st).files());
FileCont::ConstIterator it(files.begin()), end(files.end());
QString dir(Misc::getDir(file));
result = KIO::ERR_DOES_NOT_EXIST;
for (; it != end && STATUS_OK != result; ++it) {
if (Misc::getDir((*it).path()) == dir) {
result = STATUS_OK;
}
}
if (STATUS_OK == result) {
// OK, found folder - so can now proceed to delete the file...
if (fromSystem && !isSystem) {
QVariantMap args;
args["method"] = "removeFile";
args["file"] = file;
result = performAction(args);
} else {
result = Misc::fExists(file) ? QFile::remove(file) ? (int)STATUS_OK : (int)KIO::ERR_WRITE_ACCESS_DENIED : (int)KIO::ERR_DOES_NOT_EXIST;
}
if (STATUS_OK == result) {
theFolders[folder].addModifiedDir(dir);
}
}
}
Q_EMIT status(pid, result);
}
void FontInst::reconfigure(int pid, bool force)
{
// qDebug() << pid << force;
bool sysModified(theFolders[FOLDER_SYS].isModified());
saveDisabled();
// qDebug() << theFolders[FOLDER_USER].isModified() << sysModified;
if (!isSystem && (force || theFolders[FOLDER_USER].isModified())) {
theFolders[FOLDER_USER].configure(force);
}
if (sysModified) {
if (isSystem) {
theFolders[FOLDER_SYS].configure();
} else {
QVariantMap args;
args["method"] = "reconfigure";
performAction(args);
theFolders[FOLDER_SYS].clearModified();
}
}
m_connectionsTimer->start(constConnectionsTimeout);
m_fontListTimer->start(constFontListTimeout);
updateFontList();
Q_EMIT status(pid, isSystem ? constSystemReconfigured : STATUS_OK);
}
QString FontInst::folderName(bool sys)
{
return theFolders[sys || isSystem ? FOLDER_SYS : FOLDER_USER].location();
}
void FontInst::saveDisabled()
{
if (isSystem) {
theFolders[FOLDER_SYS].saveDisabled();
} else {
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT); ++i) {
if (FOLDER_SYS == i && !isSystem) {
if (theFolders[i].disabledDirty()) {
QVariantMap args;
args["method"] = "saveDisabled";
performAction(args);
theFolders[i].saveDisabled();
}
} else {
theFolders[i].saveDisabled();
}
}
}
}
void FontInst::connectionsTimeout()
{
bool canExit(true);
// qDebug() << "exiting";
checkConnections();
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT); ++i) {
if (theFolders[i].disabledDirty()) {
canExit = false;
}
theFolders[i].saveDisabled();
}
if (0 == m_connections.count()) {
if (canExit) {
qApp->exit(0);
} else { // Try again later...
m_connectionsTimer->start(constConnectionsTimeout);
}
}
}
void FontInst::fontListTimeout()
{
updateFontList(true);
m_fontListTimer->start(constFontListTimeout);
}
void FontInst::updateFontList(bool emitChanges)
{
// For some reason just the "!FcConfigUptoDate(0)" check does not always work :-(
FcBool fcModified = !FcConfigUptoDate(nullptr);
if (fcModified || theFolders[FOLDER_SYS].fonts().isEmpty() || (!isSystem && theFolders[FOLDER_USER].fonts().isEmpty())
|| theFolders[FOLDER_SYS].disabledDirty() || (!isSystem && theFolders[FOLDER_USER].disabledDirty())) {
// qDebug() << "Need to refresh font lists";
if (fcModified) {
// qDebug() << "Re-init FC";
if (!FcInitReinitialize()) {
// qDebug() << "Re-init failed????";
}
}
Folder::Flat old[FOLDER_COUNT];
if (emitChanges) {
// qDebug() << "Flatten existing font lists";
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT); ++i) {
old[i] = theFolders[i].flatten();
}
}
saveDisabled();
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT); ++i) {
theFolders[i].clearFonts();
}
// qDebug() << "update list of fonts";
FcPattern *pat = FcPatternCreate();
FcObjectSet *os = FcObjectSetBuild(FC_FILE,
FC_FAMILY,
FC_FAMILYLANG,
FC_WEIGHT,
FC_LANG,
FC_CHARSET,
FC_SCALABLE,
#ifndef KFI_FC_NO_WIDTHS
FC_WIDTH,
#endif
FC_SLANT,
FC_INDEX,
FC_FOUNDRY,
(void *)nullptr);
FcFontSet *list = FcFontList(nullptr, pat, os);
FcPatternDestroy(pat);
FcObjectSetDestroy(os);
theFolders[FOLDER_SYS].loadDisabled();
if (!isSystem) {
theFolders[FOLDER_USER].loadDisabled();
}
if (list) {
QString home(Misc::dirSyntax(QDir::homePath()));
for (int i = 0; i < list->nfont; i++) {
QString fileName(Misc::fileSyntax(FC::getFcString(list->fonts[i], FC_FILE)));
if (!fileName.isEmpty() && Misc::fExists(fileName)) // && 0!=fileName.indexOf(constDefomaLocation))
{
QString family, foundry;
quint32 styleVal;
int index;
qulonglong writingSystems(WritingSystems::instance()->get(list->fonts[i]));
FcBool scalable = FcFalse;
if (FcResultMatch != FcPatternGetBool(list->fonts[i], FC_SCALABLE, 0, &scalable)) {
scalable = FcFalse;
}
FC::getDetails(list->fonts[i], family, styleVal, index, foundry);
FamilyCont::ConstIterator fam = theFolders[isSystem || 0 != fileName.indexOf(home) ? FOLDER_SYS : FOLDER_USER].addFont(Family(family));
StyleCont::ConstIterator style = (*fam).add(Style(styleVal));
FileCont::ConstIterator file = (*style).add(File(fileName, foundry, index));
Q_UNUSED(file);
(*style).setWritingSystems((*style).writingSystems() | writingSystems);
if (scalable) {
(*style).setScalable();
}
}
}
FcFontSetDestroy(list);
}
if (emitChanges) {
// qDebug() << "Look for differences";
for (int i = 0; i < (isSystem ? 1 : FOLDER_COUNT); ++i) {
// qDebug() << "Flatten, and take copies...";
Folder::Flat newList = theFolders[i].flatten(), onlyNew = newList;
// qDebug() << "Determine differences...";
onlyNew.subtract(old[i]);
old[i].subtract(newList);
// qDebug() << "Emit changes...";
Families families = onlyNew.build(isSystem || i == FOLDER_SYS);
if (!families.items.isEmpty()) {
Q_EMIT fontsAdded(families);
}
families = old[i].build(isSystem || i == FOLDER_SYS);
if (!families.items.isEmpty()) {
Q_EMIT fontsRemoved(families);
}
}
}
// qDebug() << "updated list of fonts";
}
}
void FontInst::toggle(bool enable, const QString &family, quint32 style, bool inSystem, int pid, bool checkConfig)
{
m_connections.insert(pid);
if (checkConfig) {
updateFontList();
}
EFolder folder = isSystem || inSystem ? FOLDER_SYS : FOLDER_USER;
FamilyCont::ConstIterator fam;
StyleCont::ConstIterator st;
int result = findFont(family, style, folder, fam, st) ? (int)STATUS_OK : (int)KIO::ERR_DOES_NOT_EXIST;
if (STATUS_OK == result) {
FileCont files((*st).files()), toggledFiles;
FileCont::ConstIterator it(files.begin()), end(files.end());
QHash<File, QString> movedFonts;
QHash<QString, QString> movedAssoc;
QSet<QString> modifiedDirs;
for (; it != end && 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 the font is a system font, and we're not root, then just go through the actions here - so
// that we can build the list of changes that would happen...
if ((inSystem && !isSystem) || 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 && STATUS_OK == result; ++ait) {
to = Misc::getDir(*ait) + QString(enable ? Misc::unhide(Misc::getFile(*ait)) : Misc::hide(Misc::getFile(*ait)));
if (to != *ait) {
if ((inSystem && !isSystem) || renameFontFile(*ait, to)) {
movedAssoc[*ait] = to;
} else {
result = KIO::ERR_WRITE_ACCESS_DENIED;
}
}
}
} else {
result = KIO::ERR_WRITE_ACCESS_DENIED;
}
}
}
if (inSystem && !isSystem) {
Family toggleFam((*fam).name());
toggleFam.add(*st);
QVariantMap args;
args["method"] = "toggle";
QString xml;
QTextStream str(&xml);
toggleFam.toXml(false, str);
args["xml"] = xml;
args["enable"] = enable;
result = performAction(args);
}
if (STATUS_OK == result) {
Family addFam((*fam).name()), delFam((*fam).name());
Style addStyle((*st).value(), (*st).scalable(), (*st).writingSystems()), delStyle((*st).value(), (*st).scalable(), (*st).writingSystems());
addStyle.setFiles(toggledFiles);
addFam.add(addStyle);
delStyle.setFiles(files);
delFam.add(delStyle);
(*st).setFiles(toggledFiles);
theFolders[folder].addModifiedDirs(modifiedDirs);
Q_EMIT fontsAdded(Families(addFam, FOLDER_SYS == folder));
Q_EMIT fontsRemoved(Families(delFam, FOLDER_SYS == folder));
theFolders[folder].setDisabledDirty();
} else // un-move fonts!
{
QHash<File, QString>::ConstIterator fit(movedFonts.constBegin()), fend(movedFonts.constEnd());
QHash<QString, QString>::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());
}
}
}
Q_EMIT status(pid, result);
m_connectionsTimer->start(constConnectionsTimeout);
m_fontListTimer->start(constFontListTimeout);
}
void FontInst::addModifedSysFolders(const Family &family)
{
StyleCont::ConstIterator style(family.styles().begin()), styleEnd(family.styles().end());
for (; style != styleEnd; ++style) {
FileCont::ConstIterator file((*style).files().begin()), fileEnd((*style).files().end());
for (; file != fileEnd; ++file) {
theFolders[FOLDER_SYS].addModifiedDir(Misc::getDir((*file).path()));
}
}
}
void FontInst::checkConnections()
{
QSet<int>::ConstIterator it(m_connections.begin()), end(m_connections.end());
QSet<int> remove;
for (; it != end; ++it) {
if (0 != kill(*it, 0)) {
remove.insert(*it);
}
}
m_connections.subtract(remove);
}
bool FontInst::findFontReal(const QString &family, const QString &style, EFolder folder, FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st)
{
Family f(family);
fam = theFolders[folder].fonts().find(f);
if (theFolders[folder].fonts().end() == fam) {
return false;
}
StyleCont::ConstIterator end((*fam).styles().end());
for (st = (*fam).styles().begin(); st != end; ++st) {
if (FC::createStyleName((*st).value()) == style) {
return true;
}
}
return false;
}
bool FontInst::findFont(const QString &font, EFolder folder, FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st, bool updateList)
{
QString family, style;
decompose(font, family, style);
if (!findFontReal(family, style, folder, fam, st)) {
if (updateList) {
// Not found, so refresh font list and try again...
updateFontList();
return findFontReal(family, style, folder, fam, st);
} else {
return false;
}
}
return true;
}
bool FontInst::findFontReal(const QString &family, quint32 style, EFolder folder, FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st)
{
fam = theFolders[folder].fonts().find(Family(family));
if (theFolders[folder].fonts().end() == fam) {
return false;
} else {
st = (*fam).styles().find(style);
return (*fam).styles().end() != st;
}
}
bool FontInst::findFont(const QString &family, quint32 style, EFolder folder, FamilyCont::ConstIterator &fam, StyleCont::ConstIterator &st, bool updateList)
{
if (!findFontReal(family, style, folder, fam, st)) {
if (updateList) {
// Not found, so refresh font list and try again...
updateFontList();
return findFontReal(family, style, folder, fam, st);
} else {
return false;
}
}
return true;
}
int FontInst::performAction(const QVariantMap &args)
{
KAuth::Action action("org.kde.fontinst.manage");
action.setHelperId("org.kde.fontinst");
action.setArguments(args);
// qDebug() << "Call " << args["method"].toString() << " on helper";
m_fontListTimer->stop();
m_connectionsTimer->stop();
KAuth::ExecuteJob *j = action.execute();
j->exec();
if (j->error()) {
qCWarning(KFONTINST_DEBUG) << "kauth action failed" << j->errorString() << j->errorText();
// error is a KAuth::ActionReply::Error rest of this code expects KIO error codes which are extended by EStatus
switch (j->error()) {
case KAuth::ActionReply::Error::UserCancelledError:
return KIO::ERR_USER_CANCELED;
case KAuth::ActionReply::Error::AuthorizationDeniedError:
/*fall through*/
case KAuth::ActionReply::Error::NoSuchActionError:
return KIO::ERR_CANNOT_AUTHENTICATE;
default:
return KIO::ERR_INTERNAL;
}
return KIO::ERR_INTERNAL;
}
// qDebug() << "Success!";
return STATUS_OK;
}
}