mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-24 19:02:51 +00:00
444 lines
13 KiB
C++
444 lines
13 KiB
C++
/*
|
|
* 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 <KDebug>
|
|
#include <QtXml/qdom.h>
|
|
#include <QtCore/qtextcodec.h>
|
|
#include <QtCore/qcoreapplication.h>
|
|
#include <kio/global.h>
|
|
#include <kde_file.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <sys/errno.h>
|
|
|
|
#define KFI_DBUG kDebug() << time(0L)
|
|
|
|
KDE4_AUTH_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, 0);
|
|
}
|
|
|
|
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::HelperError);
|
|
reply.setErrorCode(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;
|
|
}
|
|
|
|
}
|