You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

398 lines
12 KiB

/*
* KHelper - KDE Font Installer
*
* Copyright 2003-2010 Craig Drummond <craig@kde.org>
*
* ----
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "Helper.h"
#include "Folder.h"
#include "FontInst.h"
#include "Misc.h"
#include "Utils.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDomDocument>
#include <QTextCodec>
#include <kio/global.h>
#include <signal.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <unistd.h>
#define KFI_DBUG qDebug() << time(nullptr)
KAUTH_HELPER_MAIN("org.kde.fontinst", KFI::Helper)
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()
{
KFI_DBUG;
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
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["method"].toString();
KFI_DBUG << method;
if ("install" == method)
result = install(args);
else if ("uninstall" == method)
result = uninstall(args);
else if ("move" == method)
result = move(args);
else if ("toggle" == method)
result = toggle(args);
else if ("removeFile" == method)
result = removeFile(args);
else if ("reconfigure" == method)
result = reconfigure();
else if ("saveDisabled" == method)
result = saveDisabled();
else
KFI_DBUG << "Uknown action";
if (FontInst::STATUS_OK == result)
return ActionReply::SuccessReply();
ActionReply reply(ActionReply::HelperErrorType);
reply.setErrorCode(static_cast<KAuth::ActionReply::Error>(result));
return reply;
}
int Helper::install(const QVariantMap &args)
{
QString file(args["file"].toString()), name(args["name"].toString()), destFolder(args["destFolder"].toString());
bool createAfm(args["createAfm"].toBool());
int type(args["type"].toInt());
KFI_DBUG << 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["files"].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["files"].toStringList());
bool toSystem(args["toSystem"].toBool());
QString dest(args["dest"].toString());
int uid(args["uid"].toInt()), gid(args["gid"].toInt());
KFI_DBUG << 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<QString, QString> 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<QString, QString>::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["xml"].toString());
Family font(doc.documentElement(), true);
bool enable(args["enable"].toBool());
KFI_DBUG << 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<File, QString> movedFonts;
QHash<QString, QString> movedAssoc;
QSet<QString> 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()) {
KFI_DBUG << "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<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());
}
return result;
}
int Helper::removeFile(const QVariantMap &args)
{
QString file(args["file"].toString());
KFI_DBUG << 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()
{
KFI_DBUG;
saveDisabled();
KFI_DBUG << theFontFolder.isModified();
if (theFontFolder.isModified())
theFontFolder.configure();
return FontInst::STATUS_OK;
}
int Helper::saveDisabled()
{
KFI_DBUG;
// 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;
}
}