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

742 lines
25 KiB
C++

/*
SPDX-FileCopyrightText: 2003-2007 Craig Drummond <craig@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "KioFonts.h"
#include "Family.h"
#include "Fc.h"
#include "File.h"
#include "FontInst.h"
#include "FontInstInterface.h"
#include "KfiConstants.h"
#include "Misc.h"
#include "Style.h"
#include "XmlStrings.h"
#include "debug.h"
#include <KZip>
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QMimeDatabase>
#include <QTemporaryDir>
#include <QTemporaryFile>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <sys/stat.h>
#include <unistd.h>
static constexpr int s_MAX_IPC_SIZE = 1024 * 32;
static constexpr int constReconfigTimeout = 10;
// Pseudo plugin class to embed meta data
class KIOPluginForMetaData : public QObject
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.kde.kio.slave.fonts" FILE "fonts.json")
};
extern "C" {
Q_DECL_EXPORT int kdemain(int argc, char **argv)
{
if (argc != 4) {
fprintf(stderr, "Usage: kio_" KFI_KIO_FONTS_PROTOCOL " protocol domain-socket1 domain-socket2\n");
exit(-1);
}
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName("kio_" KFI_KIO_FONTS_PROTOCOL);
KFI::CKioFonts slave(argv[2], argv[3]);
slave.dispatchLoop();
return 0;
}
}
namespace KFI
{
inline bool isSysFolder(const QString &folder)
{
return i18n(KFI_KIO_FONTS_SYS) == folder || KFI_KIO_FONTS_SYS == folder;
}
inline bool isUserFolder(const QString &folder)
{
return i18n(KFI_KIO_FONTS_USER) == folder || KFI_KIO_FONTS_USER == folder;
}
static CKioFonts::EFolder getFolder(const QStringList &list)
{
if (list.size() > 0) {
QString folder = list[0];
if (isSysFolder(folder)) {
return CKioFonts::FOLDER_SYS;
} else if (isUserFolder(folder)) {
return CKioFonts::FOLDER_USER;
}
return CKioFonts::FOLDER_UNKNOWN;
}
return CKioFonts::FOLDER_ROOT;
}
static int getSize(const QString &file)
{
QT_STATBUF buff;
QByteArray f(QFile::encodeName(file));
if (-1 != QT_LSTAT(f.constData(), &buff)) {
if (S_ISLNK(buff.st_mode)) {
char buffer2[1000];
int n = readlink(f.constData(), buffer2, 999);
if (n != -1) {
buffer2[n] = '\0';
}
if (-1 == QT_STAT(f.constData(), &buff)) {
return -1;
}
}
return buff.st_size;
}
return -1;
}
static bool writeAll(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t written = write(fd, buf, len);
if (written < 0 && EINTR != errno) {
return false;
}
buf += written;
len -= written;
}
return true;
}
static bool isScalable(const QString &str)
{
return Misc::checkExt(str, "ttf") || Misc::checkExt(str, "otf") || Misc::checkExt(str, "ttc") || Misc::checkExt(str, "pfa") || Misc::checkExt(str, "pfb");
}
static const char *const constExtensions[] = {".ttf", KFI_FONTS_PACKAGE, ".otf", ".pfa", ".pfb", ".ttc", ".pcf", ".pcf.gz", ".bdf", ".bdf.gz", nullptr};
static QString removeKnownExtension(const QUrl &url)
{
QString fname(url.fileName());
int pos;
for (int i = 0; constExtensions[i]; ++i) {
if (-1 != (pos = fname.lastIndexOf(QString::fromLatin1(constExtensions[i]), -1, Qt::CaseInsensitive))) {
return fname.left(pos);
}
}
return fname;
}
CKioFonts::CKioFonts(const QByteArray &pool, const QByteArray &app)
: KIO::SlaveBase(KFI_KIO_FONTS_PROTOCOL, pool, app)
, m_interface(new FontInstInterface())
, m_tempDir(nullptr)
{
}
CKioFonts::~CKioFonts()
{
delete m_interface;
delete m_tempDir;
}
void CKioFonts::listDir(const QUrl &url)
{
qCDebug(KCM_KFONTINST_KIO) << url;
KIO::UDSEntry ownRootEntry;
ownRootEntry.reserve(4);
ownRootEntry.fastInsert(KIO::UDSEntry::UDS_NAME, QStringLiteral("."));
ownRootEntry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
ownRootEntry.fastInsert(KIO::UDSEntry::UDS_SIZE, 0);
ownRootEntry.fastInsert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH);
listEntry(ownRootEntry);
QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), Qt::SkipEmptyParts));
EFolder folder = Misc::root() ? FOLDER_SYS : getFolder(pathList);
KIO::UDSEntry entry;
int size = 0;
switch (folder) {
case FOLDER_ROOT:
qCDebug(KCM_KFONTINST_KIO) << "List root folder";
size = 2;
totalSize(2);
createUDSEntry(entry, FOLDER_SYS);
listEntry(entry);
createUDSEntry(entry, FOLDER_USER);
listEntry(entry);
break;
case FOLDER_SYS:
case FOLDER_USER:
size = listFolder(entry, folder);
break;
default:
break;
}
if (FOLDER_UNKNOWN != folder) {
finished();
} else {
error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
}
}
void CKioFonts::put(const QUrl &url, int /*permissions*/, KIO::JobFlags /*flags*/)
{
qCDebug(KCM_KFONTINST_KIO) << url;
QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), Qt::SkipEmptyParts));
EFolder folder(getFolder(pathList));
if (!Misc::root() && FOLDER_ROOT == folder) {
error(KIO::ERR_SLAVE_DEFINED, i18n("Can only install fonts to either \"%1\" or \"%2\".", i18n(KFI_KIO_FONTS_USER), i18n(KFI_KIO_FONTS_SYS)));
} else if (Misc::isPackage(url.fileName())) {
error(KIO::ERR_SLAVE_DEFINED,
i18n("You cannot install a fonts package directly.\n"
"Please extract %1, and install the components individually.",
url.toDisplayString()));
} else {
if (!m_tempDir) {
m_tempDir = new QTemporaryDir(QDir::tempPath() + QString::fromLatin1("/kio_fonts_") + QString::number(getpid()));
m_tempDir->setAutoRemove(true);
}
QString tempFile(m_tempDir->filePath(url.fileName()));
QFile dest(tempFile);
if (dest.open(QIODevice::WriteOnly)) {
int result;
// Loop until we got 0 (end of data)
do {
QByteArray buffer;
dataReq(); // Request for data
result = readData(buffer);
if (result > 0 && !writeAll(dest.handle(), buffer.constData(), buffer.size())) {
if (ENOSPC == errno) // disk full
{
error(KIO::ERR_DISK_FULL, dest.fileName());
result = -2; // means: remove dest file
} else {
error(KIO::ERR_CANNOT_WRITE, dest.fileName());
result = -1;
}
}
} while (result > 0);
if (result < 0) {
dest.close();
::exit(255);
}
handleResp(m_interface->install(tempFile, Misc::root() || FOLDER_SYS == folder), url.fileName(), tempFile, FOLDER_SYS == folder);
QFile::remove(tempFile);
} else {
error(EACCES == errno ? KIO::ERR_WRITE_ACCESS_DENIED : KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest.fileName());
}
}
}
void CKioFonts::get(const QUrl &url)
{
qCDebug(KCM_KFONTINST_KIO) << url;
QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), Qt::SkipEmptyParts));
EFolder folder(getFolder(pathList));
Family family(getFont(url, folder));
if (!family.name().isEmpty() && 1 == family.styles().count()) {
StyleCont::ConstIterator style(family.styles().begin());
FileCont::ConstIterator it((*style).files().begin()), end((*style).files().end());
//
// The thumbnail job always downloads non-local files to /tmp/... and passes this file name to
// the thumbnail creator. However, in the case of fonts which are split among many files, this
// wont work. Therefore, when the thumbnail code asks for the font to download, just return
// the family and style info for enabled fonts, and the filename for disabled fonts. This way
// the font-thumbnail creator can read this and just ask Xft/fontconfig for the font data.
if ("1" == metaData("thumbnail")) {
QByteArray array;
QTextStream stream(&array, QIODevice::WriteOnly);
Q_EMIT mimeType("text/plain");
bool hidden(true);
for (; it != end && hidden; ++it) {
if (!Misc::isHidden(Misc::getFile((*it).path()))) {
hidden = false;
}
}
if (hidden) {
//
// OK, its a disabled font - if possible try to return the location of the font file
// itself.
bool found = false;
it = (*style).files().begin();
end = (*style).files().end();
for (; it != end && hidden; ++it) {
if (isScalable((*it).path())) {
qCDebug(KCM_KFONTINST_KIO) << "hasMetaData(\"thumbnail\"), so return FILE: " << (*it).path() << " / " << (*it).index();
stream << KFI_PATH_KEY << (*it).path() << Qt::endl << KFI_FACE_KEY << (*it).index() << Qt::endl;
found = true;
break;
}
}
if (!found) {
qCDebug(KCM_KFONTINST_KIO) << "hasMetaData(\"thumbnail\"), so return Url: " << url;
stream << url.toDisplayString();
}
} else {
qCDebug(KCM_KFONTINST_KIO) << "hasMetaData(\"thumbnail\"), so return DETAILS: " << family.name() << " / " << (*style).value();
stream << KFI_NAME_KEY << family.name() << Qt::endl << KFI_STYLE_KEY << (*style).value() << Qt::endl;
}
totalSize(array.size());
data(array);
processedSize(array.size());
data(QByteArray());
processedSize(array.size());
finished();
qCDebug(KCM_KFONTINST_KIO) << "Finished thumbnail...";
return;
}
QSet<QString> files;
QString realPath;
QT_STATBUF buff;
bool multiple = false;
for (; it != end; ++it) {
QStringList assoc;
files.insert((*it).path());
Misc::getAssociatedFiles((*it).path(), assoc);
QStringList::ConstIterator ait(assoc.constBegin()), aend(assoc.constEnd());
for (; ait != aend; ++ait) {
files.insert(*ait);
}
}
if (1 == files.count()) {
realPath = (*files.begin());
} else // Font is made up of multiple files - so create .zip of them all!
{
QTemporaryFile tmpFile;
if (tmpFile.open()) {
KZip zip(tmpFile.fileName());
tmpFile.setAutoRemove(false);
realPath = tmpFile.fileName();
if (zip.open(QIODevice::WriteOnly)) {
QMap<QString, QString> map = Misc::getFontFileMap(files);
QMap<QString, QString>::ConstIterator it(map.constBegin()), end(map.constEnd());
for (; it != end; ++it) {
zip.addLocalFile(it.value(), it.key());
}
multiple = true;
zip.close();
}
}
}
QByteArray realPathC(QFile::encodeName(realPath));
qCDebug(KCM_KFONTINST_KIO) << "real: " << realPathC;
if (-2 == QT_STAT(realPathC.constData(), &buff)) {
error(EACCES == errno ? KIO::ERR_ACCESS_DENIED : KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
} else if (S_ISDIR(buff.st_mode)) {
error(KIO::ERR_IS_DIRECTORY, url.toDisplayString());
} else if (!S_ISREG(buff.st_mode)) {
error(KIO::ERR_CANNOT_OPEN_FOR_READING, url.toDisplayString());
} else {
int fd = QT_OPEN(realPathC.constData(), O_RDONLY);
if (fd < 0) {
error(KIO::ERR_CANNOT_OPEN_FOR_READING, url.toDisplayString());
} else {
// Determine the mimetype of the file to be retrieved, and Q_EMIT it.
// This is mandatory in all slaves (for KRun/BrowserRun to work).
// This code can be optimized by using QFileInfo instead of buff above
// and passing it to mimeTypeForFile() instead of realPath.
QMimeDatabase db;
Q_EMIT mimeType(db.mimeTypeForFile(realPath).name());
totalSize(buff.st_size);
KIO::filesize_t processed = 0;
char buffer[s_MAX_IPC_SIZE];
QByteArray array;
while (1) {
int n = ::read(fd, buffer, s_MAX_IPC_SIZE);
if (-1 == n) {
if (EINTR == errno) {
continue;
}
error(KIO::ERR_CANNOT_READ, url.toDisplayString());
::close(fd);
if (multiple) {
::unlink(realPathC);
}
return;
}
if (0 == n) {
break; // Finished
}
array = array.fromRawData(buffer, n);
data(array);
array.clear();
processed += n;
processedSize(processed);
}
data(QByteArray());
::close(fd);
processedSize(buff.st_size);
finished();
}
}
if (multiple) {
::unlink(realPathC);
}
} else {
error(KIO::ERR_CANNOT_READ, url.toDisplayString());
}
}
void CKioFonts::copy(const QUrl &, const QUrl &, int, KIO::JobFlags)
{
error(KIO::ERR_SLAVE_DEFINED, i18n("Cannot copy fonts"));
}
void CKioFonts::rename(const QUrl &, const QUrl &, KIO::JobFlags)
{
error(KIO::ERR_SLAVE_DEFINED, i18n("Cannot move fonts"));
}
void CKioFonts::del(const QUrl &url, bool isFile)
{
qCDebug(KCM_KFONTINST_KIO) << url;
QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), Qt::SkipEmptyParts));
EFolder folder(getFolder(pathList));
QString name(removeKnownExtension(url));
if (!isFile) {
error(KIO::ERR_SLAVE_DEFINED, i18n("Only fonts may be deleted."));
} else if (!Misc::root() && FOLDER_ROOT == folder) {
error(KIO::ERR_SLAVE_DEFINED, i18n("Can only remove fonts from either \"%1\" or \"%2\".", i18n(KFI_KIO_FONTS_USER), i18n(KFI_KIO_FONTS_SYS)));
} else if (!name.isEmpty()) {
handleResp(m_interface->uninstall(name, Misc::root() || FOLDER_SYS == folder), name);
} else {
error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
}
}
void CKioFonts::stat(const QUrl &url)
{
qCDebug(KCM_KFONTINST_KIO) << url;
QStringList pathList(url.adjusted(QUrl::StripTrailingSlash).path().split(QLatin1Char('/'), Qt::SkipEmptyParts));
EFolder folder = getFolder(pathList);
KIO::UDSEntry entry;
bool ok = true;
switch (pathList.count()) {
case 0:
createUDSEntry(entry, FOLDER_ROOT);
break;
case 1:
if (Misc::root()) {
ok = createStatEntry(entry, url, FOLDER_SYS);
} else if (FOLDER_SYS == folder || FOLDER_USER == folder) {
createUDSEntry(entry, folder);
} else {
error(KIO::ERR_SLAVE_DEFINED, i18n("Please specify \"%1\" or \"%2\".", i18n(KFI_KIO_FONTS_USER), i18n(KFI_KIO_FONTS_SYS)));
return;
}
break;
default:
ok = createStatEntry(entry, url, folder);
}
if (ok) {
statEntry(entry);
finished();
} else {
error(KIO::ERR_DOES_NOT_EXIST, url.toDisplayString());
return;
}
}
void CKioFonts::special(const QByteArray &a)
{
if (!a.isEmpty()) {
error(KIO::ERR_UNSUPPORTED_ACTION, i18n("No special methods supported."));
} else {
setTimeoutSpecialCommand(-1);
m_interface->reconfigure();
}
}
int CKioFonts::listFolder(KIO::UDSEntry &entry, EFolder folder)
{
qCDebug(KCM_KFONTINST_KIO) << folder;
int styleCount(0);
KFI::Families families(m_interface->list(FOLDER_SYS == folder));
FamilyCont::ConstIterator family(families.items.begin()), end(families.items.end());
qCDebug(KCM_KFONTINST_KIO) << "Num families:" << families.items.count();
for (; family != end; ++family) {
StyleCont::ConstIterator styleIt((*family).styles().begin()), styleEnd((*family).styles().end());
styleCount += (*family).styles().count();
for (; styleIt != styleEnd; ++styleIt) {
createUDSEntry(entry, folder, *family, *styleIt);
listEntry(entry);
}
}
totalSize(styleCount);
return styleCount;
}
QString CKioFonts::getUserName(uid_t uid)
{
if (!m_userCache.contains(uid)) {
struct passwd *user = getpwuid(uid);
if (user) {
m_userCache.insert(uid, QString::fromLatin1(user->pw_name));
} else {
return QString::number(uid);
}
}
return m_userCache[uid];
}
QString CKioFonts::getGroupName(gid_t gid)
{
if (!m_groupCache.contains(gid)) {
struct group *grp = getgrgid(gid);
if (grp) {
m_groupCache.insert(gid, QString::fromLatin1(grp->gr_name));
} else {
return QString::number(gid);
}
}
return m_groupCache[gid];
}
bool CKioFonts::createStatEntry(KIO::UDSEntry &entry, const QUrl &url, EFolder folder)
{
Family fam(getFont(url, folder));
if (!fam.name().isEmpty() && 1 == fam.styles().count()) {
createUDSEntry(entry, folder, fam, *fam.styles().begin());
return true;
}
return false;
}
void CKioFonts::createUDSEntry(KIO::UDSEntry &entry, EFolder folder)
{
qCDebug(KCM_KFONTINST_KIO) << QString(FOLDER_SYS == folder ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER));
entry.clear();
entry.fastInsert(KIO::UDSEntry::UDS_NAME,
FOLDER_ROOT == folder || Misc::root() ? i18n("Fonts")
: FOLDER_SYS == folder ? i18n(KFI_KIO_FONTS_SYS)
: i18n(KFI_KIO_FONTS_USER));
entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, !Misc::root() && FOLDER_SYS == folder ? 0444 : 0744);
entry.fastInsert(KIO::UDSEntry::UDS_USER, Misc::root() || FOLDER_SYS == folder ? QString::fromLatin1("root") : getUserName(getuid()));
entry.fastInsert(KIO::UDSEntry::UDS_GROUP, Misc::root() || FOLDER_SYS == folder ? QString::fromLatin1("root") : getGroupName(getgid()));
entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1("inode/directory"));
}
bool CKioFonts::createUDSEntry(KIO::UDSEntry &entry, EFolder folder, const Family &family, const Style &style)
{
int size = 0;
QString name(FC::createName(family.name(), style.value()));
FileCont::ConstIterator file(style.files().begin()), fileEnd(style.files().end());
QList<File> files;
bool hidden = true, haveExtraFiles = false;
qCDebug(KCM_KFONTINST_KIO) << name;
for (; file != fileEnd; ++file) {
size += getSize((*file).path());
// TODO: Make scalable a property of the file?
// Then isScalable() is not needed!!!
if (isScalable((*file).path())) {
files.prepend(*file);
} else {
files.append(*file);
}
if (hidden && !Misc::isHidden(Misc::getFile((*file).path()))) {
hidden = false;
}
QStringList assoc;
Misc::getAssociatedFiles((*file).path(), assoc);
QStringList::ConstIterator oit(assoc.constBegin()), oend(assoc.constEnd());
if (!haveExtraFiles && !assoc.isEmpty()) {
haveExtraFiles = true;
}
for (; oit != oend; ++oit) {
size += getSize(*oit);
}
}
entry.clear();
entry.fastInsert(KIO::UDSEntry::UDS_DISPLAY_NAME, name);
entry.fastInsert(KIO::UDSEntry::UDS_SIZE, size);
entry.fastInsert(UDS_EXTRA_FC_STYLE, style.value());
QList<File>::ConstIterator it(files.constBegin()), end(files.constEnd());
for (; it != end; ++it) {
const QString fontPath = it->path();
QByteArray cPath(QFile::encodeName(fontPath));
QT_STATBUF buff;
if (-1 != QT_LSTAT(cPath, &buff)) {
const QString fileName = Misc::getFile(fontPath);
QString mt;
int dotPos(fileName.lastIndexOf('.'));
QString extension(-1 == dotPos ? QString() : fileName.mid(dotPos));
if (QString::fromLatin1(".gz") == extension) {
dotPos = fileName.lastIndexOf('.', dotPos - 1);
extension = -1 == dotPos ? QString() : fileName.mid(dotPos);
}
if (QString::fromLatin1(".ttf") == extension || QString::fromLatin1(".ttc") == extension) {
mt = "application/x-font-ttf";
} else if (QString::fromLatin1(".otf") == extension) {
mt = "application/x-font-otf";
} else if (QString::fromLatin1(".pfa") == extension || QString::fromLatin1(".pfb") == extension) {
mt = "application/x-font-type1";
} else if (QString::fromLatin1(".pcf.gz") == extension || QString::fromLatin1(".pcf") == extension) {
mt = "application/x-font-pcf";
} else if (QString::fromLatin1(".bdf.gz") == extension || QString::fromLatin1(".bdf") == extension) {
mt = "application/x-font-bdf";
} else {
// File extension check failed, use QMimeDatabase to read contents...
QMimeDatabase db;
QMimeType mime = db.mimeTypeForFile(fontPath);
QStringList patterns = mime.globPatterns();
mt = mime.name();
if (patterns.size() > 0) {
extension = (*patterns.begin()).remove("*");
}
}
entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, buff.st_mode & S_IFMT);
entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, buff.st_mode & 07777);
entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, buff.st_mtime);
entry.fastInsert(KIO::UDSEntry::UDS_ACCESS_TIME, buff.st_atime);
entry.fastInsert(KIO::UDSEntry::UDS_USER, getUserName(buff.st_uid));
entry.fastInsert(KIO::UDSEntry::UDS_GROUP, getGroupName(buff.st_gid));
entry.fastInsert(KIO::UDSEntry::UDS_MIME_TYPE, mt);
const QUrl entryUrl = QUrl::fromLocalFile(fontPath);
entry.fastInsert(KIO::UDSEntry::UDS_URL, entryUrl.toDisplayString());
entry.fastInsert(KIO::UDSEntry::UDS_NAME, entryUrl.fileName());
if (hidden) {
entry.fastInsert(KIO::UDSEntry::UDS_HIDDEN, 1);
entry.fastInsert(UDS_EXTRA_FILE_NAME, fontPath);
entry.fastInsert(UDS_EXTRA_FILE_FACE, fontPath);
}
return true;
}
}
return false;
}
Family CKioFonts::getFont(const QUrl &url, EFolder folder)
{
QString name(removeKnownExtension(url));
qCDebug(KCM_KFONTINST_KIO) << url << name;
return m_interface->statFont(name, FOLDER_SYS == folder);
}
void CKioFonts::handleResp(int resp, const QString &file, const QString &tempFile, bool destIsSystem)
{
switch (resp) {
case FontInst::STATUS_NO_SYS_CONNECTION:
error(KIO::ERR_SLAVE_DEFINED, i18n("Failed to start the system daemon"));
break;
case FontInst::STATUS_SERVICE_DIED:
error(KIO::ERR_SLAVE_DEFINED, i18n("Backend died"));
break;
case FontInst::STATUS_BITMAPS_DISABLED:
error(KIO::ERR_SLAVE_DEFINED, i18n("%1 is a bitmap font, and these have been disabled on your system.", file));
break;
case FontInst::STATUS_ALREADY_INSTALLED:
error(KIO::ERR_SLAVE_DEFINED, i18n("%1 contains the font <b>%2</b>, which is already installed on your system.", file, FC::getName(tempFile)));
break;
case FontInst::STATUS_NOT_FONT_FILE:
error(KIO::ERR_SLAVE_DEFINED, i18n("%1 is not a font.", file));
break;
case FontInst::STATUS_PARTIAL_DELETE:
error(KIO::ERR_SLAVE_DEFINED, i18n("Could not remove all files associated with %1", file));
break;
case KIO::ERR_FILE_ALREADY_EXIST: {
QString name(Misc::modifyName(file)), destFolder(Misc::getDestFolder(m_interface->folderName(destIsSystem), name));
error(KIO::ERR_SLAVE_DEFINED, i18n("<i>%1</i> already exists.", destFolder + name));
break;
}
case FontInst::STATUS_OK:
finished();
break;
default:
error(resp, file);
}
if (FontInst::STATUS_OK == resp) {
setTimeoutSpecialCommand(constReconfigTimeout);
}
}
}
#include "KioFonts.moc"