summaryrefslogtreecommitdiffstats
path: root/kcontrol/kfontinst/kio
diff options
context:
space:
mode:
Diffstat (limited to 'kcontrol/kfontinst/kio')
-rw-r--r--kcontrol/kfontinst/kio/KioFonts.cpp2534
-rw-r--r--kcontrol/kfontinst/kio/KioFonts.h161
-rw-r--r--kcontrol/kfontinst/kio/Makefile.am20
-rw-r--r--kcontrol/kfontinst/kio/folder.desktop80
-rw-r--r--kcontrol/kfontinst/kio/fonts.desktop85
-rw-r--r--kcontrol/kfontinst/kio/fonts.protocol18
-rw-r--r--kcontrol/kfontinst/kio/package.desktop74
-rw-r--r--kcontrol/kfontinst/kio/system-folder.desktop79
8 files changed, 3051 insertions, 0 deletions
diff --git a/kcontrol/kfontinst/kio/KioFonts.cpp b/kcontrol/kfontinst/kio/KioFonts.cpp
new file mode 100644
index 000000000..e5bc2d6af
--- /dev/null
+++ b/kcontrol/kfontinst/kio/KioFonts.cpp
@@ -0,0 +1,2534 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Class Name : KFI::CKioFonts
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 05/03/2003
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+/***************************************************************************
+
+ NOTE: Large sections of this code are copied from kio_file
+ -- can't just inherit from kio_file as kio_file uses "error(...);
+ return;" So there is no way to know if an error occured!
+
+ ***************************************************************************/
+
+#include "KioFonts.h"
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <utime.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <kio/global.h>
+#include <kio/ioslave_defaults.h>
+#include <kio/netaccess.h>
+#include <kio/slaveinterface.h>
+#include <kio/connection.h>
+#include <qtextstream.h>
+#include <kmimetype.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <qdir.h>
+#include <qdatastream.h>
+#include <qregexp.h>
+#include <kinstance.h>
+#include <klargefile.h>
+#include <ktempfile.h>
+#include <kdesu/su.h>
+#include <kprocess.h>
+#include <kdebug.h>
+#include <ktar.h>
+#include <kxftconfig.h>
+#include <fontconfig/fontconfig.h>
+#include "KfiConstants.h"
+#include "FcEngine.h"
+#include "Misc.h"
+#include <X11/Xlib.h>
+#include <fixx11h.h>
+#include <ctype.h>
+
+//#define KFI_FORCE_DEBUG_TO_STDERR
+
+#ifdef KFI_FORCE_DEBUG_TO_STDERR
+
+#include <qtextstream.h>
+QTextOStream ostr(stderr);
+#define KFI_DBUG ostr << "[" << (int)(getpid()) << "] "
+
+#else
+
+#define KFI_DBUG kdDebug() << "[" << (int)(getpid()) << "] "
+
+#endif
+
+#define MAX_IPC_SIZE (1024*32)
+#define TIMEOUT 2 // Time between last mod and writing files...
+#define MAX_NEW_FONTS 50 // #fonts that can be installed before automatically configuring (related to above)
+#define FC_CACHE_CMD "fc-cache"
+
+static const char * constMultipleExtension=".fonts.tar.gz"; // Fonts that have multiple files are returned as a .tar.gz!
+static const int constMaxLastDestTime=5;
+static const int constMaxFcCheckTime=10;
+
+extern "C"
+{
+ KDE_EXPORT int kdemain(int argc, char **argv);
+}
+
+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);
+ }
+
+ KLocale::setMainCatalogue(KFI_CATALOGUE);
+
+ KInstance instance("kio_" KFI_KIO_FONTS_PROTOCOL);
+ KFI::CKioFonts slave(argv[2], argv[3]);
+
+ slave.dispatchLoop();
+
+ return 0;
+}
+
+namespace KFI
+{
+
+inline bool isSysFolder(const QString &sect)
+{
+ return i18n(KFI_KIO_FONTS_SYS)==sect || KFI_KIO_FONTS_SYS==sect;
+}
+
+inline bool isUserFolder(const QString &sect)
+{
+ return i18n(KFI_KIO_FONTS_USER)==sect || KFI_KIO_FONTS_USER==sect;
+}
+
+static QString removeMultipleExtension(const KURL &url)
+{
+ QString fname(url.fileName());
+ int pos;
+
+ if(-1!=(pos=fname.findRev(QString::fromLatin1(constMultipleExtension))))
+ fname=fname.left(pos);
+
+ return fname;
+}
+
+static QString modifyName(const QString &fname)
+{
+ static const char constSymbols[]={ '-', ' ', ':', 0 };
+
+ QString rv(fname);
+ int dotPos=rv.findRev('.');
+
+ if(-1!=dotPos)
+ {
+ unsigned int rvLen=rv.length();
+
+ for(unsigned int i=dotPos+1; i<rvLen; ++i)
+ rv[i]=rv[i].lower();
+ }
+
+ for(int s=0; constSymbols[s]; ++s)
+ rv=rv.replace(constSymbols[s], '_');
+
+ return rv;
+}
+
+static int getSize(const QCString &file)
+{
+ KDE_struct_stat buff;
+
+ if(-1!=KDE_lstat(file, &buff))
+ {
+ if (S_ISLNK(buff.st_mode))
+ {
+ char buffer2[1000];
+ int n=readlink(file, buffer2, 1000);
+ if(n!= -1)
+ buffer2[n]='\0';
+
+ if(-1==KDE_stat(file, &buff))
+ return -1;
+ }
+ return buff.st_size;
+ }
+
+ return -1;
+}
+
+static int getFontSize(const QString &file)
+{
+ int size=0;
+
+ KURL::List urls;
+ QStringList files;
+
+ Misc::getAssociatedUrls(KURL(file), urls);
+
+ files.append(file);
+
+ if(urls.count())
+ {
+ KURL::List::Iterator uIt,
+ uEnd=urls.end();
+
+ for(uIt=urls.begin(); uIt!=uEnd; ++uIt)
+ files.append((*uIt).path());
+ }
+
+ QStringList::Iterator it(files.begin()),
+ end(files.end());
+
+ for(; it!=end; ++it)
+ {
+ int s=getSize(QFile::encodeName(*it));
+
+ if(s>-1)
+ size+=s;
+ }
+
+ return size;
+}
+
+static int getSize(QValueList<FcPattern *> &patterns)
+{
+ QValueList<FcPattern *>::Iterator it,
+ end=patterns.end();
+ int size=0;
+
+ for(it=patterns.begin(); it!=end; ++it)
+ size+=getFontSize(CFcEngine::getFcString(*it, FC_FILE));
+
+ return size;
+}
+
+static void addAtom(KIO::UDSEntry &entry, unsigned int ID, long l, const QString &s=QString::null)
+{
+ KIO::UDSAtom atom;
+ atom.m_uds = ID;
+ atom.m_long = l;
+ atom.m_str = s;
+ entry.append(atom);
+}
+
+static bool createFolderUDSEntry(KIO::UDSEntry &entry, const QString &name, const QString &path, bool sys)
+{
+ KFI_DBUG << "createFolderUDSEntry " << name << ' ' << path << ' ' << sys << ' ' << endl;
+
+ KDE_struct_stat buff;
+ QCString cPath(QFile::encodeName(path));
+
+ entry.clear();
+
+ if(-1!=KDE_lstat(cPath, &buff))
+ {
+ addAtom(entry, KIO::UDS_NAME, 0, name);
+
+ if (S_ISLNK(buff.st_mode))
+ {
+ KFI_DBUG << path << " is a link" << endl;
+
+ char buffer2[1000];
+ int n=readlink(cPath, buffer2, 1000);
+ if(n!= -1)
+ buffer2[n]='\0';
+
+ addAtom(entry, KIO::UDS_LINK_DEST, 0, QString::fromLocal8Bit(buffer2));
+
+ if(-1==KDE_stat(cPath, &buff))
+ {
+ // It is a link pointing to nowhere
+ addAtom(entry, KIO::UDS_FILE_TYPE, S_IFMT - 1);
+ addAtom(entry, KIO::UDS_ACCESS, S_IRWXU | S_IRWXG | S_IRWXO);
+ addAtom(entry, KIO::UDS_SIZE, 0);
+ goto notype;
+ }
+ }
+
+ addAtom(entry, KIO::UDS_FILE_TYPE, buff.st_mode&S_IFMT);
+ addAtom(entry, KIO::UDS_ACCESS, buff.st_mode&07777);
+ addAtom(entry, KIO::UDS_SIZE, buff.st_size);
+
+ notype:
+ addAtom(entry, KIO::UDS_MODIFICATION_TIME, buff.st_mtime);
+
+ struct passwd *user = getpwuid(buff.st_uid);
+ addAtom(entry, KIO::UDS_USER, 0, user ? user->pw_name : QString::number(buff.st_uid).latin1());
+
+ struct group *grp = getgrgid(buff.st_gid);
+ addAtom(entry, KIO::UDS_GROUP, 0, grp ? grp->gr_name : QString::number(buff.st_gid).latin1());
+
+ addAtom(entry, KIO::UDS_ACCESS_TIME, buff.st_atime);
+ addAtom(entry, KIO::UDS_MIME_TYPE, 0, sys
+ ? KFI_KIO_FONTS_PROTOCOL"/system-folder"
+ : KFI_KIO_FONTS_PROTOCOL"/folder");
+ addAtom(entry, KIO::UDS_GUESSED_MIME_TYPE, 0, "application/octet-stream");
+ QString url(KFI_KIO_FONTS_PROTOCOL+QString::fromLatin1(":/"));
+ return true;
+ }
+ else if (sys && !Misc::root()) // Default system fonts folder does not actually exist yet!
+ {
+ KFI_DBUG << "Default system folder (" << path << ") does not yet exist, so create dummy entry" << endl;
+ addAtom(entry, KIO::UDS_NAME, 0, name);
+ addAtom(entry, KIO::UDS_FILE_TYPE, S_IFDIR);
+ addAtom(entry, KIO::UDS_ACCESS, 0744);
+ addAtom(entry, KIO::UDS_USER, 0, "root");
+ addAtom(entry, KIO::UDS_GROUP, 0, "root");
+ addAtom(entry, KIO::UDS_MIME_TYPE, 0, KFI_KIO_FONTS_PROTOCOL"/system-folder");
+ addAtom(entry, KIO::UDS_GUESSED_MIME_TYPE, 0, "application/octet-stream");
+
+ return true;
+ }
+
+
+ return false;
+}
+
+static bool createFontUDSEntry(KIO::UDSEntry &entry, const QString &name, QValueList<FcPattern *> &patterns, bool sys)
+{
+ KFI_DBUG << "createFontUDSEntry " << name << ' ' << patterns.count() << endl;
+
+ bool multiple=true;
+
+ if(1==patterns.count()) // Only one font file, but are there any .pfm or .afm files?
+ {
+ KURL::List urls;
+
+ Misc::getAssociatedUrls(KURL(CFcEngine::getFcString(patterns.first(), FC_FILE)), urls);
+
+ if(0==urls.count())
+ multiple=false;
+ }
+
+ //
+ // In case of mixed bitmap/scalable - prefer scalable
+ QValueList<FcPattern *> sortedPatterns;
+ QValueList<FcPattern *>::Iterator it,
+ end(patterns.end());
+ FcBool b=FcFalse;
+
+ for(it=patterns.begin(); it!=end; ++it)
+ if(FcResultMatch==FcPatternGetBool(*it, FC_SCALABLE, 0, &b) && b)
+ sortedPatterns.prepend(*it);
+ else
+ sortedPatterns.append(*it);
+
+ end=sortedPatterns.end();
+ entry.clear();
+ addAtom(entry, KIO::UDS_SIZE, getSize(patterns));
+
+ for(it=sortedPatterns.begin(); it!=end; ++it)
+ {
+ QString path(CFcEngine::getFcString(*it, FC_FILE));
+ QCString cPath(QFile::encodeName(path));
+ KDE_struct_stat buff;
+
+ if(-1!=KDE_lstat(cPath, &buff))
+ {
+ addAtom(entry, KIO::UDS_NAME, 0, name);
+
+ if (S_ISLNK(buff.st_mode))
+ {
+ KFI_DBUG << path << " is a link" << endl;
+
+ char buffer2[1000];
+ int n=readlink(cPath, buffer2, 1000);
+
+ if(n!= -1)
+ buffer2[n]='\0';
+
+ addAtom(entry, KIO::UDS_LINK_DEST, 0, QString::fromLocal8Bit(buffer2));
+
+ if(-1==KDE_stat(cPath, &buff))
+ {
+ // It is a link pointing to nowhere
+ addAtom(entry, KIO::UDS_FILE_TYPE, S_IFMT - 1);
+ addAtom(entry, KIO::UDS_ACCESS, S_IRWXU | S_IRWXG | S_IRWXO);
+ goto notype;
+ }
+ }
+
+ addAtom(entry, KIO::UDS_FILE_TYPE, buff.st_mode&S_IFMT);
+ addAtom(entry, KIO::UDS_ACCESS, buff.st_mode&07777);
+
+ notype:
+ addAtom(entry, KIO::UDS_MODIFICATION_TIME, buff.st_mtime);
+
+ struct passwd *user = getpwuid(buff.st_uid);
+ addAtom(entry, KIO::UDS_USER, 0, user ? user->pw_name : QString::number(buff.st_uid).latin1());
+
+ struct group *grp = getgrgid(buff.st_gid);
+ addAtom(entry, KIO::UDS_GROUP, 0, grp ? grp->gr_name : QString::number(buff.st_gid).latin1());
+
+ addAtom(entry, KIO::UDS_ACCESS_TIME, buff.st_atime);
+ addAtom(entry, KIO::UDS_MIME_TYPE, 0, KMimeType::findByPath(path, 0, true)->name());
+ addAtom(entry, KIO::UDS_GUESSED_MIME_TYPE, 0, "application/octet-stream");
+
+ QString url(KFI_KIO_FONTS_PROTOCOL+QString::fromLatin1(":/"));
+
+ if(!Misc::root())
+ {
+ url+=sys ? i18n(KFI_KIO_FONTS_SYS) : i18n(KFI_KIO_FONTS_USER);
+ url+=QString::fromLatin1("/");
+ }
+ if(multiple)
+ url+=name+QString::fromLatin1(constMultipleExtension);
+ else
+ url+=Misc::getFile(path);
+ addAtom(entry, KIO::UDS_URL, 0, url);
+ return true; // This file was OK, so use its values...
+ }
+ }
+ return false;
+}
+
+enum EUrlStatus
+{
+ BAD_URL,
+ URL_OK,
+ REDIRECT_URL
+};
+
+static KURL getRedirect(const KURL &u)
+{
+ // Go from fonts:/System to fonts:/
+
+ KURL redirect(u);
+ QString path(u.path()),
+ sect(CKioFonts::getSect(path));
+
+ path.remove(sect);
+ path.replace("//", "/");
+ redirect.setPath(path);
+
+ KFI_DBUG << "Redirect from " << u.path() << " to " << redirect.path() << endl;
+ return redirect;
+}
+
+static bool nonRootSys(const KURL &u)
+{
+ return !Misc::root() && isSysFolder(CKioFonts::getSect(u.path()));
+}
+
+static QString getFontFolder(const QString &defaultDir, const QString &root, QStringList &dirs)
+{
+ if(dirs.contains(defaultDir))
+ return defaultDir;
+ else
+ {
+ QStringList::Iterator it,
+ end=dirs.end();
+ bool found=false;
+
+ for(it=dirs.begin(); it!=end && !found; ++it)
+ if(0==(*it).find(root))
+ return *it;
+ }
+
+ return QString::null;
+}
+
+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 checkExt(const char *fname, const char *ext)
+{
+ unsigned int len=strlen(fname);
+
+ return len>4 ? (fname[len-4]=='.' && tolower(fname[len-3])==ext[0] && tolower(fname[len-2])==ext[1] &&
+ tolower(fname[len-1])==ext[2])
+ : false;
+}
+
+static bool isAAfm(const QString &fname)
+{
+ if(checkExt(QFile::encodeName(fname), "afm")) // CPD? Is this a necessary check?
+ {
+ QFile file(fname);
+
+ if(file.open(IO_ReadOnly))
+ {
+ QTextStream stream(&file);
+ QString line;
+
+ for(int lc=0; lc<30 && !stream.atEnd(); ++lc)
+ {
+ line=stream.readLine();
+
+ if(line.contains("StartFontMetrics"))
+ {
+ file.close();
+ return true;
+ }
+ }
+
+ file.close();
+ }
+ }
+
+ return false;
+}
+
+static bool isAPfm(const QString &fname)
+{
+ bool ok=false;
+
+ // I know extension checking is bad, but Ghostscript's pf2afm requires the pfm file to
+ // have the .pfm extension...
+ if(checkExt(QFile::encodeName(fname), "pfm"))
+ {
+ //
+ // OK, the extension matches, so perform a little contents checking...
+ FILE *f=fopen(QFile::encodeName(fname).data(), "r");
+
+ if(f)
+ {
+ static const unsigned long constCopyrightLen = 60;
+ static const unsigned long constTypeToExt = 49;
+ static const unsigned long constExtToFname = 20;
+ static const unsigned long constExtLen = 30;
+ static const unsigned long constFontnameMin = 75;
+ static const unsigned long constFontnameMax = 512;
+
+ unsigned short version=0,
+ type=0,
+ extlen=0;
+ unsigned long length=0,
+ fontname=0,
+ fLength=0;
+
+ fseek(f, 0, SEEK_END);
+ fLength=ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ if(2==fread(&version, 1, 2, f) && // Read version
+ 4==fread(&length, 1, 4, f) && // length...
+ length==fLength &&
+ 0==fseek(f, constCopyrightLen, SEEK_CUR) && // Skip copyright notice...
+ 2==fread(&type, 1, 2, f) &&
+ 0==fseek(f, constTypeToExt, SEEK_CUR) &&
+ 2==fread(&extlen, 1, 2, f) &&
+ extlen==constExtLen &&
+ 0==fseek(f, constExtToFname, SEEK_CUR) &&
+ 4==fread(&fontname, 1, 4, f) &&
+ fontname>constFontnameMin && fontname<constFontnameMax)
+ ok=true;
+ fclose(f);
+ }
+ }
+
+ return ok;
+}
+
+//
+// This function is *only* used for the generation of AFMs from PFMs.
+static bool isAType1(const QString &fname)
+{
+ static const char * constStr="%!PS-AdobeFont-";
+ static const unsigned int constStrLen=15;
+ static const unsigned int constPfbOffset=6;
+ static const unsigned int constPfbLen=constStrLen+constPfbOffset;
+
+ QCString name(QFile::encodeName(fname));
+ char buffer[constPfbLen];
+ bool match=false;
+
+ if(checkExt(name, "pfa"))
+ {
+ FILE *f=fopen(name.data(), "r");
+
+ if(f)
+ {
+ if(constStrLen==fread(buffer, 1, constStrLen, f))
+ match=0==memcmp(buffer, constStr, constStrLen);
+ fclose(f);
+ }
+ }
+ else if(checkExt(name, "pfb"))
+ {
+ static const char constPfbMarker=0x80;
+
+ FILE *f=fopen(name.data(), "r");
+
+ if(f)
+ {
+ if(constPfbLen==fread(buffer, 1, constPfbLen, f))
+ match=buffer[0]==constPfbMarker && 0==memcmp(&buffer[constPfbOffset], constStr, constStrLen);
+ fclose(f);
+ }
+ }
+
+ return match;
+}
+
+static QString getMatch(const QString &file, const char *extension)
+{
+ QString f(Misc::changeExt(file, extension));
+
+ return Misc::fExists(f) ? f : QString::null;
+}
+
+inline bool isHidden(const KURL &u)
+{
+ return QChar('.')==u.fileName()[0];
+}
+
+struct FontList
+{
+ struct Path
+ {
+ Path(const QString &p=QString::null) : orig(p) { }
+
+ QString orig,
+ modified;
+
+ bool operator==(const Path &p) const { return p.orig==orig; }
+ };
+
+ FontList(const QString &n=QString::null, const QString &p=QString::null) : name(n) { if(!p.isEmpty()) paths.append(Path(p)); }
+
+ QString name;
+ QValueList<Path> paths;
+
+ bool operator==(const FontList &f) const { return f.name==name; }
+};
+
+//
+// This function returns a set of maping of from -> to for copy/move operations
+static bool getFontList(const QStringList &files, QMap<QString, QString> &map)
+{
+ //
+ // First of all create a list of font files, and their paths
+ QStringList::ConstIterator it=files.begin(),
+ end=files.end();
+ QValueList<FontList> list;
+
+ for(;it!=end; ++it)
+ {
+ QString name(Misc::getFile(*it)),
+ path(Misc::getDir(*it));
+ QValueList<FontList>::Iterator entry=list.find(FontList(name));
+
+ if(entry!=list.end())
+ {
+ if(!(*entry).paths.contains(path))
+ (*entry).paths.append(path);
+ }
+ else
+ list.append(FontList(name, path));
+ }
+
+ QValueList<FontList>::Iterator fIt(list.begin()),
+ fEnd(list.end());
+
+ for(; fIt!=fEnd; ++fIt)
+ {
+ QValueList<FontList::Path>::Iterator pBegin((*fIt).paths.begin()),
+ pIt(++pBegin),
+ pEnd((*fIt).paths.end());
+ --pBegin;
+
+ if((*fIt).paths.count()>1)
+ {
+ // There's more than 1 file with the same name, but in a different locations
+ // therefore, take the unique part of the path, and replace / with _
+ // e.g.
+ // /usr/X11R6/lib/X11/fonts/75dpi/times.pcf.gz
+ // /usr/X11R6/lib/X11/fonts/100dpi/times.pcf.gz
+ //
+ // Will produce:
+ // 75dpi_times.pcf.gz
+ // 100dpi_times.pcf.gz
+ unsigned int beginLen((*pBegin).orig.length());
+
+ for(; pIt!=pEnd; ++pIt)
+ {
+ unsigned int len=QMIN((*pIt).orig.length(), beginLen);
+
+ for(unsigned int i=0; i<len; ++i)
+ if((*pIt).orig[i]!=(*pBegin).orig[i])
+ {
+ (*pIt).modified=(*pIt).orig.mid(i);
+ (*pIt).modified=(*pIt).modified.replace('/', '_');
+ if((*pBegin).modified.isEmpty())
+ {
+ (*pBegin).modified=(*pBegin).orig.mid(i);
+ (*pBegin).modified=(*pBegin).modified.replace('/', '_');
+ }
+ break;
+ }
+ }
+ }
+ for(pIt=(*fIt).paths.begin(); pIt!=pEnd; ++pIt)
+ map[(*pIt).orig+(*fIt).name]=(*pIt).modified+(*fIt).name;
+ }
+
+ return list.count() ? true : false;
+}
+
+CKioFonts::CKioFonts(const QCString &pool, const QCString &app)
+ : KIO::SlaveBase(KFI_KIO_FONTS_PROTOCOL, pool, app),
+ itsRoot(Misc::root()),
+ itsUsingFcFpe(false),
+ itsUsingXfsFpe(false),
+ itsHasSys(false),
+ itsAddToSysFc(false),
+ itsFontChanges(0),
+ itsLastDest(DEST_UNCHANGED),
+ itsLastDestTime(0),
+ itsLastFcCheckTime(0),
+ itsFontList(NULL)
+{
+ KFI_DBUG << "Constructor" << endl;
+
+ // Set core dump size to 0 because we will have
+ // root's password in memory.
+ struct rlimit rlim;
+ rlim.rlim_cur=rlim.rlim_max=0;
+ itsCanStorePasswd=setrlimit(RLIMIT_CORE, &rlim) ? false : true;
+
+ //
+ // Check with fontconfig for folder locations...
+ //
+ // 1. Get list of fontconfig dirs
+ // 2. For user, look for any starting with $HOME - but prefer $HOME/.fonts
+ // 3. For system, look for any starting with /usr/local/share - but prefer /usr/local/share/fonts
+ // 4. If either are not found, then add to local.conf / .fonts.conf
+
+ FcStrList *list=FcConfigGetFontDirs(FcInitLoadConfigAndFonts());
+ QStringList dirs;
+ FcChar8 *dir;
+
+ while((dir=FcStrListNext(list)))
+ dirs.append(Misc::dirSyntax((const char *)dir));
+
+ EFolder mainFolder=FOLDER_SYS;
+
+ if(!itsRoot)
+ {
+ QString home(Misc::dirSyntax(QDir::homeDirPath())),
+ defaultDir(Misc::dirSyntax(QDir::homeDirPath()+"/.fonts/")),
+ dir(getFontFolder(defaultDir, home, dirs));
+
+ if(dir.isEmpty()) // Then no $HOME/ was found in fontconfigs dirs!
+ {
+ KXftConfig xft(KXftConfig::Dirs, false);
+ xft.addDir(defaultDir);
+ xft.apply();
+ dir=defaultDir;
+ }
+ mainFolder=FOLDER_USER;
+ itsFolders[FOLDER_USER].location=dir;
+ }
+
+ QString sysDefault("/usr/local/share/fonts/"),
+ sysDir(getFontFolder(sysDefault, "/usr/local/share/", dirs));
+
+ if(sysDir.isEmpty())
+ {
+ if(itsRoot)
+ {
+ KXftConfig xft(KXftConfig::Dirs, true);
+ xft.addDir(sysDefault);
+ xft.apply();
+ }
+ else
+ itsAddToSysFc=true;
+
+ sysDir=sysDefault;
+ }
+
+ itsFolders[FOLDER_SYS].location=sysDir;
+
+ //
+ // Ensure exists
+ if(!Misc::dExists(itsFolders[mainFolder].location))
+ Misc::createDir(itsFolders[mainFolder].location);
+
+ //
+ // Work out best params to send to kfontinst
+
+ // ...determine if X already knows about the system font path...
+ Display *xDisplay=XOpenDisplay(NULL);
+
+ if(xDisplay)
+ {
+ int numPaths=0;
+ char **paths=XGetFontPath(xDisplay, &numPaths);
+
+ if(numPaths>0)
+ for(int path=0; path<numPaths && !itsUsingFcFpe; ++path)
+ if(paths[path][0]=='/')
+ {
+ if(Misc::dirSyntax(paths[path])==itsFolders[FOLDER_SYS].location)
+ itsHasSys=true;
+ }
+ else
+ {
+ QString str(paths[path]);
+
+ str.replace(QRegExp("\\s*"), "");
+
+ if(0==str.find("unix/:"))
+ itsUsingXfsFpe=true;
+ else if("fontconfig"==str)
+ itsUsingFcFpe=true;
+ }
+ XFreeFontPath(paths);
+ XCloseDisplay(xDisplay);
+ }
+}
+
+CKioFonts::~CKioFonts()
+{
+ KFI_DBUG << "Destructor" << endl;
+ doModified();
+}
+
+void CKioFonts::listDir(const KURL &url)
+{
+ KFI_DBUG << "listDir " << url.path() << endl;
+
+ if(updateFontList() && checkUrl(url, true))
+ {
+ KIO::UDSEntry entry;
+ int size=0;
+
+ if(itsRoot || QStringList::split('/', url.path(), false).count()!=0)
+ {
+ EFolder folder=getFolder(url);
+
+ totalSize(itsFolders[folder].fontMap.count());
+ if(itsFolders[folder].fontMap.count())
+ {
+ QMap<QString, QValueList<FcPattern *> >::Iterator it=itsFolders[folder].fontMap.begin(),
+ end=itsFolders[folder].fontMap.end();
+
+ for ( ; it != end; ++it)
+ {
+ entry.clear();
+ if(createFontUDSEntry(entry, it.key(), it.data(), FOLDER_SYS==folder))
+ listEntry(entry, false);
+ }
+ }
+ }
+ else
+ {
+ size=2;
+ totalSize(size);
+ createFolderUDSEntry(entry, i18n(KFI_KIO_FONTS_USER), itsFolders[FOLDER_USER].location, false);
+ listEntry(entry, false);
+ createFolderUDSEntry(entry, i18n(KFI_KIO_FONTS_SYS), itsFolders[FOLDER_SYS].location, true);
+ listEntry(entry, false);
+ }
+
+ listEntry(size ? entry : KIO::UDSEntry(), true);
+ finished();
+ }
+
+ KFI_DBUG << "listDir - finished!" << endl;
+}
+
+void CKioFonts::stat(const KURL &url)
+{
+ KFI_DBUG << "stat " << url.prettyURL() << endl;
+
+ if(updateFontList() && checkUrl(url, true))
+ {
+ QString path(url.path(-1));
+
+ if(path.isEmpty())
+ {
+ error(KIO::ERR_COULD_NOT_STAT, url.prettyURL());
+ return;
+ }
+
+ QStringList pathList(QStringList::split('/', path, false));
+ KIO::UDSEntry entry;
+ bool err=false;
+
+ switch(pathList.count())
+ {
+ case 0:
+ err=!createFolderUDSEntry(entry, i18n("Fonts"), itsFolders[itsRoot ? FOLDER_SYS : FOLDER_USER].location, false);
+ break;
+ case 1:
+ if(itsRoot)
+ err=!createStatEntry(entry, url, FOLDER_SYS);
+ else
+ if(isUserFolder(pathList[0]))
+ err=!createFolderUDSEntry(entry, i18n(KFI_KIO_FONTS_USER), itsFolders[FOLDER_USER].location, false);
+ else if(isSysFolder(pathList[0]))
+ err=!createFolderUDSEntry(entry, i18n(KFI_KIO_FONTS_SYS), itsFolders[FOLDER_USER].location, true);
+ else
+ {
+ error(KIO::ERR_SLAVE_DEFINED,
+ i18n("Please specify \"%1\" or \"%2\".").arg(i18n(KFI_KIO_FONTS_USER)).arg(i18n(KFI_KIO_FONTS_SYS)));
+ return;
+ }
+ break;
+ default:
+ err=!createStatEntry(entry, url, getFolder(url));
+ }
+
+ if(err)
+ {
+ error(KIO::ERR_DOES_NOT_EXIST, url.prettyURL());
+ return;
+ }
+
+ statEntry(entry);
+ finished();
+ }
+}
+
+bool CKioFonts::createStatEntry(KIO::UDSEntry &entry, const KURL &url, EFolder folder)
+{
+ KFI_DBUG << "createStatEntry " << url.path() << endl;
+
+ QMap<QString, QValueList<FcPattern *> >::Iterator it=getMap(url);
+
+ if(it!=itsFolders[folder].fontMap.end())
+ return createFontUDSEntry(entry, it.key(), it.data(), FOLDER_SYS==folder);
+ return false;
+}
+
+void CKioFonts::get(const KURL &url)
+{
+ KFI_DBUG << "get " << url.path() << " query:" << url.query() << endl;
+
+ bool thumb="1"==metaData("thumbnail");
+ QStringList srcFiles;
+
+ if(updateFontList() && checkUrl(url) && getSourceFiles(url, srcFiles)) // Any error will be logged in getSourceFiles
+ {
+ //
+ // The thumbnail job always donwloads 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 donwload, just return the URL used. This way the font-thumbnail creator can
+ // read this and just ask Xft/fontconfig for the font data.
+ if(thumb)
+ {
+ QByteArray array;
+ QTextOStream stream(array);
+
+ emit mimeType("text/plain");
+
+ KFI_DBUG << "hasMetaData(\"thumbnail\"), so return: " << url.prettyURL() << endl;
+
+ stream << url.prettyURL();
+ totalSize(array.size());
+ data(array);
+ processedSize(array.size());
+ data(QByteArray());
+ processedSize(array.size());
+ finished();
+ return;
+ }
+
+ QString realPath,
+ useMime;
+ KDE_struct_stat buff;
+ bool multiple=false;
+
+ if(1==srcFiles.count())
+ realPath=srcFiles.first();
+ else // Font is made up of multiple files - so create .tar.gz of them all!
+ {
+ KTempFile tmpFile;
+ KTar tar(tmpFile.name(), "application/x-gzip");
+
+ tmpFile.setAutoDelete(false);
+ realPath=tmpFile.name();
+
+ if(tar.open(IO_WriteOnly))
+ {
+ QMap<QString, QString> map;
+
+ getFontList(srcFiles, map);
+
+ QMap<QString, QString>::Iterator fIt(map.begin()),
+ fEnd(map.end());
+
+ //
+ // Iterate through created list, and add to tar archive
+ for(; fIt!=fEnd; ++fIt)
+ tar.addLocalFile(fIt.key(), fIt.data());
+
+ multiple=true;
+ tar.close();
+ }
+ }
+
+ QCString realPathC(QFile::encodeName(realPath));
+ KFI_DBUG << "real: " << realPathC << endl;
+
+ if (-2==KDE_stat(realPathC.data(), &buff))
+ error(EACCES==errno ? KIO::ERR_ACCESS_DENIED : KIO::ERR_DOES_NOT_EXIST, url.prettyURL());
+ else if (S_ISDIR(buff.st_mode))
+ error(KIO::ERR_IS_DIRECTORY, url.prettyURL());
+ else if (!S_ISREG(buff.st_mode))
+ error(KIO::ERR_CANNOT_OPEN_FOR_READING, url.prettyURL());
+ else
+ {
+ int fd = KDE_open(realPathC.data(), O_RDONLY);
+
+ if (fd < 0)
+ error(KIO::ERR_CANNOT_OPEN_FOR_READING, url.prettyURL());
+ else
+ {
+ // Determine the mimetype of the file to be retrieved, and emit it.
+ // This is mandatory in all slaves (for KRun/BrowserRun to work).
+ emit mimeType(useMime.isEmpty() ? KMimeType::findByPath(realPathC, buff.st_mode, true)->name() : useMime);
+
+ totalSize(buff.st_size);
+
+ KIO::filesize_t processed=0;
+ char buffer[MAX_IPC_SIZE];
+ QByteArray array;
+
+ while(1)
+ {
+ int n=::read(fd, buffer, MAX_IPC_SIZE);
+ if (-1==n)
+ {
+ if (errno == EINTR)
+ continue;
+ error(KIO::ERR_COULD_NOT_READ, url.prettyURL());
+ close(fd);
+ if(multiple)
+ ::unlink(realPathC);
+ return;
+ }
+ if (0==n)
+ break; // Finished
+
+ array.setRawData(buffer, n);
+ data(array);
+ array.resetRawData(buffer, n);
+
+ processed+=n;
+ processedSize(processed);
+ }
+
+ data(QByteArray());
+ close(fd);
+
+ processedSize(buff.st_size);
+ finished();
+ }
+ }
+ if(multiple)
+ ::unlink(realPathC);
+ }
+}
+
+void CKioFonts::put(const KURL &u, int mode, bool overwrite, bool resume)
+{
+ KFI_DBUG << "put " << u.path() << endl;
+
+ if(isHidden(u))
+ {
+ error(KIO::ERR_WRITE_ACCESS_DENIED, u.prettyURL());
+ return;
+ }
+
+ // updateFontList(); // CPD: dont update font list upon a put - is too slow. Just stat on filename!
+
+ //checkUrl(u) // CPD: Don't need to check URL, as the call to "confirmUrl()" below will sort out any probs!
+
+ KURL url(u);
+ bool changed=confirmUrl(url),
+ nrs=nonRootSys(url);
+ EFolder destFolder(getFolder(url));
+ QString dest=itsFolders[destFolder].location+modifyName(url.fileName()),
+ passwd;
+ QCString destC=QFile::encodeName(dest);
+ KDE_struct_stat buffDest;
+ bool destExists=(KDE_lstat(destC.data(), &buffDest)!= -1);
+
+ if (destExists && !overwrite && !resume)
+ {
+ error(KIO::ERR_FILE_ALREADY_EXIST, url.prettyURL());
+ return;
+ }
+
+ if(nrs) // Need to check can get root passwd before start download...
+ {
+ passwd=getRootPasswd();
+
+ if(passwd.isEmpty())
+ {
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Could not access \"%1\" folder.").arg(i18n(KFI_KIO_FONTS_SYS)));
+ return;
+ }
+ }
+
+ //
+ // As we don't get passed a mime-type the following needs to happen:
+ //
+ // 1. Download to a temporary file
+ // 2. Check with FreeType that the file is a font, or that it is
+ // an AFM or PFM file
+ // 3. If its OK, then get the fonts "name" from
+ KTempFile tmpFile;
+ QCString tmpFileC(QFile::encodeName(tmpFile.name()));
+
+ tmpFile.setAutoDelete(true);
+
+ if(putReal(tmpFile.name(), tmpFileC, destExists, mode, resume))
+ {
+ if(!checkFile(tmpFile.name())) // error logged in checkFile
+ return;
+
+ if(nrs) // Ask root to copy the font...
+ {
+ QCString cmd;
+
+ if(!Misc::dExists(itsFolders[destFolder].location))
+ {
+ cmd+="mkdir ";
+ cmd+=QFile::encodeName(KProcess::quote(itsFolders[destFolder].location));
+ cmd+=" && chmod 0755 ";
+ cmd+=QFile::encodeName(KProcess::quote(itsFolders[destFolder].location));
+ cmd+=" && ";
+ }
+ cmd+="cp -f ";
+ cmd+=QFile::encodeName(KProcess::quote(tmpFileC));
+ cmd+=" ";
+ cmd+=QFile::encodeName(KProcess::quote(destC));
+ cmd+=" && chmod 0644 ";
+ cmd+=destC;
+
+ if(!itsCanStorePasswd)
+ createRootRefreshCmd(cmd);
+
+ // Get root to move this to fonts folder...
+ if(doRootCmd(cmd, passwd))
+ {
+ modified(FOLDER_SYS);
+ createAfm(dest, true, passwd);
+ }
+ else
+ {
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Could not access \"%1\" folder.").arg(i18n(KFI_KIO_FONTS_SYS)));
+ return;
+ }
+ }
+ else // Move it to our font folder...
+ {
+ tmpFile.setAutoDelete(false);
+ if(Misc::doCmd("mv", "-f", tmpFileC, destC))
+ {
+ ::chmod(destC.data(), Misc::FILE_PERMS);
+ modified(FOLDER_USER);
+ createAfm(dest);
+ }
+ else
+ {
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Could not access \"%1\" folder.").arg(i18n(KFI_KIO_FONTS_USER)));
+ return;
+ }
+ }
+
+ finished();
+
+ if(changed)
+ itsLastDestTime=time(NULL);
+ }
+}
+
+bool CKioFonts::putReal(const QString &destOrig, const QCString &destOrigC, bool origExists,
+ int mode, bool resume)
+{
+ bool markPartial=config()->readBoolEntry("MarkPartial", true);
+ QString dest;
+
+ if (markPartial)
+ {
+ QString destPart(destOrig+QString::fromLatin1(".part"));
+ QCString destPartC(QFile::encodeName(destPart));
+
+ dest = destPart;
+
+ KDE_struct_stat buffPart;
+ bool partExists=(-1!=KDE_stat(destPartC.data(), &buffPart));
+
+ if (partExists && !resume && buffPart.st_size>0)
+ {
+ // Maybe we can use this partial file for resuming
+ // Tell about the size we have, and the app will tell us
+ // if it's ok to resume or not.
+ resume=canResume(buffPart.st_size);
+
+ if (!resume)
+ if (!::remove(destPartC.data()))
+ partExists = false;
+ else
+ {
+ error(KIO::ERR_CANNOT_DELETE_PARTIAL, destPart);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ dest = destOrig;
+ if (origExists && !resume)
+ ::remove(destOrigC.data());
+ // Catch errors when we try to open the file.
+ }
+
+ QCString destC(QFile::encodeName(dest));
+
+ int fd;
+
+ if (resume)
+ {
+ fd = KDE_open(destC.data(), O_RDWR); // append if resuming
+ KDE_lseek(fd, 0, SEEK_END); // Seek to end
+ }
+ else
+ {
+ // WABA: Make sure that we keep writing permissions ourselves,
+ // otherwise we can be in for a surprise on NFS.
+ fd = KDE_open(destC.data(), O_CREAT | O_TRUNC | O_WRONLY, -1==mode ? 0666 : mode | S_IWUSR | S_IRUSR);
+ }
+
+ if (fd < 0)
+ {
+ error(EACCES==errno ? KIO::ERR_WRITE_ACCESS_DENIED : KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest);
+ return false;
+ }
+
+ int result;
+ // Loop until we got 0 (end of data)
+ do
+ {
+ QByteArray buffer;
+
+ dataReq(); // Request for data
+ result = readData(buffer);
+ if(result > 0 && !writeAll(fd, buffer.data(), buffer.size()))
+ {
+ if(ENOSPC==errno) // disk full
+ {
+ error(KIO::ERR_DISK_FULL, destOrig);
+ result = -2; // means: remove dest file
+ }
+ else
+ {
+ error(KIO::ERR_COULD_NOT_WRITE, destOrig);
+ result = -1;
+ }
+ }
+ }
+ while(result>0);
+
+ if (result<0)
+ {
+ close(fd);
+ if (-1==result)
+ ::remove(destC.data());
+ else if (markPartial)
+ {
+ KDE_struct_stat buff;
+
+ if ((-1==KDE_stat(destC.data(), &buff)) ||
+ (buff.st_size<config()->readNumEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE)))
+ ::remove(destC.data());
+ }
+ ::exit(255);
+ }
+
+ if (-1==fd) // we got nothing to write out, so we never opened the file
+ {
+ finished();
+ return false;
+ }
+
+ if (close(fd))
+ {
+ error(KIO::ERR_COULD_NOT_WRITE, destOrig);
+ return false;
+ }
+
+ // after full download rename the file back to original name
+ if (markPartial && ::rename(destC.data(), destOrigC.data()))
+ {
+ error(KIO::ERR_CANNOT_RENAME_PARTIAL, destOrig);
+ return false;
+ }
+
+ return true;
+}
+
+void CKioFonts::copy(const KURL &src, const KURL &d, int mode, bool overwrite)
+{
+ //
+ // Support:
+ // Copying to fonts:/
+ // Copying from fonts:/ and file:/
+ //
+ KFI_DBUG << "copy " << src.prettyURL() << " - " << d.prettyURL() << endl;
+
+ if(isHidden(d))
+ {
+ error(KIO::ERR_WRITE_ACCESS_DENIED, d.prettyURL());
+ return;
+ }
+
+ bool fromFonts=KFI_KIO_FONTS_PROTOCOL==src.protocol();
+
+ if((!fromFonts || updateFontList()) // CPD: dont update font list upon a copy from file - is too slow. Just stat on filename!
+ && checkUrl(src) && checkAllowed(src))
+ {
+ //checkUrl(u) // CPD as per comment in ::put()
+
+ QStringList srcFiles;
+
+ if(getSourceFiles(src, srcFiles)) // Any error will be logged in getSourceFiles
+ {
+ KURL dest(d);
+ bool changed=confirmUrl(dest);
+ EFolder destFolder(getFolder(dest));
+ QMap<QString, QString> map;
+
+ if(!fromFonts)
+ map[src.path()]=src.fileName();
+
+ // As above, if copying from file, then only stat on dest filename, but if from fonts to fonts need to
+ // get the list of possible source files, etc.
+ if(fromFonts ? confirmMultiple(src, srcFiles, FOLDER_SYS==destFolder ? FOLDER_USER : FOLDER_SYS, OP_COPY) &&
+ getFontList(srcFiles, map) &&
+ checkDestFiles(src, map, dest, destFolder, overwrite)
+ : checkDestFile(src, dest, destFolder, overwrite) )
+ {
+ if(nonRootSys(dest))
+ {
+ QCString cmd;
+ int size=0;
+
+ if(!Misc::dExists(itsFolders[destFolder].location))
+ {
+ cmd+="mkdir ";
+ cmd+=QFile::encodeName(KProcess::quote(itsFolders[destFolder].location));
+ cmd+=" && chmod 0755 ";
+ cmd+=QFile::encodeName(KProcess::quote(itsFolders[destFolder].location));
+ cmd+=" && ";
+ }
+
+ QMap<QString, QString>::Iterator fIt(map.begin()),
+ fEnd(map.end());
+
+ for(; fIt!=fEnd; ++fIt)
+ {
+ cmd+="cp -f ";
+ cmd+=QFile::encodeName(KProcess::quote(fIt.key()));
+ cmd+=" ";
+ cmd+=QFile::encodeName(KProcess::quote(itsFolders[destFolder].location+modifyName(fIt.data())));
+ int s=getSize(QFile::encodeName(fIt.key()));
+ if(s>0)
+ size+=s;
+ if(++fIt!=fEnd)
+ cmd+=" && ";
+ --fIt;
+ }
+
+ if(!itsCanStorePasswd)
+ createRootRefreshCmd(cmd);
+
+ totalSize(size);
+
+ QString passwd=getRootPasswd();
+
+ if(doRootCmd(cmd, passwd))
+ {
+ modified(destFolder);
+ processedSize(size);
+ if(src.isLocalFile() && 1==srcFiles.count())
+ createAfm(itsFolders[destFolder].location+modifyName(map.begin().data()), true, passwd);
+ }
+ else
+ {
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Could not access \"%1\" folder.").arg(i18n(KFI_KIO_FONTS_SYS)));
+ return;
+ }
+ }
+ else
+ {
+ QMap<QString, QString>::Iterator fIt(map.begin()),
+ fEnd(map.end());
+
+ for(; fIt!=fEnd; ++fIt)
+ {
+ QCString realSrc(QFile::encodeName(fIt.key())),
+ realDest(QFile::encodeName(itsFolders[destFolder].location+modifyName(fIt.data())));
+ KDE_struct_stat buffSrc;
+
+ if(-1==KDE_stat(realSrc.data(), &buffSrc))
+ {
+ error(EACCES==errno ? KIO::ERR_ACCESS_DENIED : KIO::ERR_DOES_NOT_EXIST, src.prettyURL());
+ return;
+ }
+
+ int srcFd=KDE_open(realSrc.data(), O_RDONLY);
+
+ if (srcFd<0)
+ {
+ error(KIO::ERR_CANNOT_OPEN_FOR_READING, src.prettyURL());
+ return;
+ }
+
+ if(!Misc::dExists(itsFolders[destFolder].location))
+ Misc::createDir(itsFolders[destFolder].location);
+
+ // WABA: Make sure that we keep writing permissions ourselves,
+ // otherwise we can be in for a surprise on NFS.
+ int destFd=KDE_open(realDest.data(), O_CREAT | O_TRUNC | O_WRONLY, -1==mode ? 0666 : mode | S_IWUSR);
+
+ if (destFd<0)
+ {
+ error(EACCES==errno ? KIO::ERR_WRITE_ACCESS_DENIED : KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest.prettyURL());
+ close(srcFd);
+ return;
+ }
+
+ totalSize(buffSrc.st_size);
+
+ KIO::filesize_t processed = 0;
+ char buffer[MAX_IPC_SIZE];
+ QByteArray array;
+
+ while(1)
+ {
+ int n=::read(srcFd, buffer, MAX_IPC_SIZE);
+
+ if(-1==n)
+ {
+ if (errno == EINTR)
+ continue;
+ error(KIO::ERR_COULD_NOT_READ, src.prettyURL());
+ close(srcFd);
+ close(destFd);
+ return;
+ }
+ if(0==n)
+ break; // Finished
+
+ if(!writeAll(destFd, buffer, n))
+ {
+ close(srcFd);
+ close(destFd);
+ if (ENOSPC==errno) // disk full
+ {
+ error(KIO::ERR_DISK_FULL, dest.prettyURL());
+ remove(realDest.data());
+ }
+ else
+ error(KIO::ERR_COULD_NOT_WRITE, dest.prettyURL());
+ return;
+ }
+
+ processed += n;
+ processedSize(processed);
+ }
+
+ close(srcFd);
+
+ if(close(destFd))
+ {
+ error(KIO::ERR_COULD_NOT_WRITE, dest.prettyURL());
+ return;
+ }
+
+ ::chmod(realDest.data(), Misc::FILE_PERMS);
+
+ // copy access and modification time
+ struct utimbuf ut;
+
+ ut.actime = buffSrc.st_atime;
+ ut.modtime = buffSrc.st_mtime;
+ ::utime(realDest.data(), &ut);
+
+ processedSize(buffSrc.st_size);
+ modified(destFolder);
+ }
+
+ if(src.isLocalFile() && 1==srcFiles.count())
+ createAfm(itsFolders[destFolder].location+modifyName(map.begin().data()));
+ }
+
+ finished();
+
+ if(changed)
+ itsLastDestTime=time(NULL);
+ }
+ }
+ }
+}
+
+void CKioFonts::rename(const KURL &src, const KURL &d, bool overwrite)
+{
+ KFI_DBUG << "rename " << src.prettyURL() << " - " << d.prettyURL() << ", " << overwrite << endl;
+
+ if(src.directory()==d.directory())
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Sorry, fonts cannot be renamed."));
+ else if(itsRoot) // Should never happen...
+ error(KIO::ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, KIO::CMD_RENAME));
+ else
+ {
+ //
+ // Can't rename from/to file:/ -> therefore rename can only be from fonts:/System to fonts:/Personal,
+ // or vice versa.
+
+ QStringList srcFiles;
+
+ if(getSourceFiles(src, srcFiles)) // Any error will be logged in getSourceFiles
+ {
+ KURL dest(d);
+ bool changed=confirmUrl(dest);
+ EFolder destFolder(getFolder(dest));
+ QMap<QString, QString> map;
+
+ if(confirmMultiple(src, srcFiles, FOLDER_SYS==destFolder ? FOLDER_USER : FOLDER_SYS, OP_MOVE) &&
+ getFontList(srcFiles, map) &&
+ checkDestFiles(src, map, dest, destFolder, overwrite))
+ {
+ QMap<QString, QString>::Iterator fIt(map.begin()),
+ fEnd(map.end());
+ bool askPasswd=true,
+ toSys=FOLDER_SYS==destFolder;
+ QCString userId,
+ groupId,
+ destDir(QFile::encodeName(KProcess::quote(itsFolders[destFolder].location)));
+
+ userId.setNum(toSys ? 0 : getuid());
+ groupId.setNum(toSys ? 0 : getgid());
+
+ for(; fIt!=fEnd; ++fIt)
+ {
+ QCString cmd,
+ destFile(QFile::encodeName(KProcess::quote(itsFolders[destFolder].location+fIt.data())));
+
+ if(toSys && !Misc::dExists(itsFolders[destFolder].location))
+ {
+ cmd+="mkdir ";
+ cmd+=destDir;
+ cmd+=" && ";
+ }
+
+ cmd+="mv -f ";
+ cmd+=QFile::encodeName(KProcess::quote(fIt.key()));
+ cmd+=" ";
+ cmd+=destFile;
+ cmd+=" && chmod -f 0644 ";
+ cmd+=destFile;
+ cmd+=" && chown -f ";
+ cmd+=userId;
+ cmd+=":";
+ cmd+=groupId;
+ cmd+=" ";
+ cmd+=destFile;
+
+ QString sysDir,
+ userDir;
+
+ if(FOLDER_SYS==destFolder)
+ {
+ sysDir=itsFolders[destFolder].location;
+ userDir=Misc::getDir(fIt.key());
+ }
+ else
+ {
+ userDir=itsFolders[destFolder].location;
+ sysDir=Misc::getDir(fIt.key());
+ }
+
+ if(!itsCanStorePasswd)
+ createRootRefreshCmd(cmd, sysDir);
+
+ if(doRootCmd(cmd, askPasswd))
+ {
+ modified(FOLDER_SYS, true, sysDir);
+ modified(FOLDER_USER, true, userDir);
+ askPasswd=false; // Don't keep on asking for password...
+ }
+ else
+ {
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Could not access \"%1\" folder.").arg(i18n(KFI_KIO_FONTS_SYS)));
+ return;
+ }
+ }
+ if(changed)
+ itsLastDestTime=time(NULL);
+ }
+ }
+ }
+}
+
+void CKioFonts::del(const KURL &url, bool)
+{
+ KFI_DBUG << "del " << url.path() << endl;
+
+ QValueList<FcPattern *> *entries;
+
+ if(checkUrl(url) && checkAllowed(url) &&
+ updateFontList() && (entries=getEntries(url)) && entries->count() &&
+ confirmMultiple(url, entries, getFolder(url), OP_DELETE))
+ {
+ QValueList<FcPattern *>::Iterator it,
+ end=entries->end();
+ CDirList modifiedDirs;
+ bool clearList=KFI_KIO_NO_CLEAR!=url.query();
+
+ if(nonRootSys(url))
+ {
+ QCString cmd("rm -f");
+
+ for(it=entries->begin(); it!=end; ++it)
+ {
+ QString file(CFcEngine::getFcString(*it, FC_FILE));
+
+ modifiedDirs.add(Misc::getDir(file));
+ cmd+=" ";
+ cmd+=QFile::encodeName(KProcess::quote(file));
+
+ KURL::List urls;
+
+ Misc::getAssociatedUrls(KURL(file), urls);
+
+ if(urls.count())
+ {
+ KURL::List::Iterator uIt,
+ uEnd=urls.end();
+
+ for(uIt=urls.begin(); uIt!=uEnd; ++uIt)
+ {
+ cmd+=" ";
+ cmd+=QFile::encodeName(KProcess::quote((*uIt).path()));
+ }
+ }
+ }
+
+ if(!itsCanStorePasswd)
+ createRootRefreshCmd(cmd, modifiedDirs);
+
+ if(doRootCmd(cmd))
+ modified(FOLDER_SYS, clearList, modifiedDirs);
+ else
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Could not access \"%1\" folder.").arg(i18n(KFI_KIO_FONTS_SYS)));
+ }
+ else
+ {
+ for(it=entries->begin(); it!=end; ++it)
+ {
+ QString file(CFcEngine::getFcString(*it, FC_FILE));
+
+ if (0!=unlink(QFile::encodeName(file).data()))
+ error(EACCES==errno || EPERM==errno
+ ? KIO::ERR_ACCESS_DENIED
+ : EISDIR==errno
+ ? KIO::ERR_IS_DIRECTORY
+ : KIO::ERR_CANNOT_DELETE,
+ file);
+ else
+ {
+ modifiedDirs.add(Misc::getDir(file));
+
+ KURL::List urls;
+
+ Misc::getAssociatedUrls(KURL(file), urls);
+
+ if(urls.count())
+ {
+ KURL::List::Iterator uIt,
+ uEnd=urls.end();
+
+ for(uIt=urls.begin(); uIt!=uEnd; ++uIt)
+ unlink(QFile::encodeName((*uIt).path()).data());
+ }
+ }
+ }
+ modified(itsRoot ? FOLDER_SYS : FOLDER_USER, clearList, modifiedDirs);
+ }
+ finished();
+ }
+}
+
+void CKioFonts::modified(EFolder folder, bool clearList, const CDirList &dirs)
+{
+ KFI_DBUG << "modified(" << (int)folder << ")\n";
+
+ if(FOLDER_SYS!=folder || itsCanStorePasswd || itsRoot)
+ {
+ if(dirs.count())
+ {
+ CDirList::ConstIterator it(dirs.begin()),
+ end(dirs.end());
+
+ for(; it!=end; ++it)
+ itsFolders[folder].modified.add(*it);
+ }
+ else
+ itsFolders[folder].modified.add(itsFolders[folder].location);
+
+ if(++itsFontChanges>MAX_NEW_FONTS)
+ {
+ setTimeoutSpecialCommand(0); // Cancel timer
+ doModified();
+ }
+ else
+ setTimeoutSpecialCommand(TIMEOUT);
+ }
+
+ if(FOLDER_SYS==folder && !itsRoot && !itsCanStorePasswd)
+ {
+ // If we modified sys, we're not root, and couldn't store the passwd, then kfontinst has already been called
+ // so no need to ask it to add folder to fontconfig and X's config files...
+ itsHasSys=true;
+ itsAddToSysFc=false;
+ }
+ if(clearList)
+ clearFontList(); // List of fonts has changed.../
+}
+
+void CKioFonts::special(const QByteArray &a)
+{
+ KFI_DBUG << "special" << endl;
+
+ if(a.size())
+ {
+ QDataStream stream(a, IO_ReadOnly);
+ int cmd;
+
+ stream >> cmd;
+
+ switch (cmd)
+ {
+ case SPECIAL_RESCAN:
+ clearFontList();
+ updateFontList();
+ finished();
+ break;
+ case SPECIAL_RECONFIG: // Only itended to be called from kcmfontinst - when a user has re-enabled doX or doGs
+ if(itsRoot && !itsFolders[FOLDER_SYS].modified.contains(itsFolders[FOLDER_SYS].location))
+ itsFolders[FOLDER_SYS].modified.add(itsFolders[FOLDER_SYS].location);
+ else if(!itsRoot && !itsFolders[FOLDER_USER].modified.contains(itsFolders[FOLDER_USER].location))
+ itsFolders[FOLDER_USER].modified.add(itsFolders[FOLDER_USER].location);
+
+ doModified();
+ finished();
+ break;
+ default:
+ error( KIO::ERR_UNSUPPORTED_ACTION, QString::number(cmd));
+ }
+ }
+ else
+ doModified();
+}
+
+void CKioFonts::createRootRefreshCmd(QCString &cmd, const CDirList &dirs, bool reparseCfg)
+{
+ if(reparseCfg)
+ reparseConfig();
+
+ if(!cmd.isEmpty())
+ cmd+=" && ";
+
+ cmd+=FC_CACHE_CMD;
+
+ if(dirs.count())
+ {
+ CDirList::ConstIterator it(dirs.begin()),
+ end(dirs.end());
+
+ for(; it!=end; ++it)
+ {
+ QCString tmpCmd;
+
+ if(*it==itsFolders[FOLDER_SYS].location)
+ {
+ if(0!=itsNrsKfiParams[0])
+ tmpCmd+=itsNrsKfiParams;
+ }
+ else
+ if(0!=itsNrsNonMainKfiParams[0])
+ tmpCmd+=itsNrsNonMainKfiParams;
+
+ if(!tmpCmd.isEmpty())
+ {
+ cmd+=" && kfontinst ";
+ cmd+=tmpCmd;
+ cmd+=" ";
+ cmd+=QFile::encodeName(KProcess::quote(*it));
+ }
+ }
+ }
+ else if (0!=itsNrsKfiParams[0])
+ {
+ cmd+=" && kfontinst ";
+ cmd+=itsNrsKfiParams;
+ cmd+=" ";
+ cmd+=QFile::encodeName(KProcess::quote(itsFolders[FOLDER_SYS].location));
+ }
+}
+
+void CKioFonts::doModified()
+{
+ KFI_DBUG << "doModified" << endl;
+
+ if(itsFolders[FOLDER_SYS].modified.count() || itsFolders[FOLDER_USER].modified.count())
+ reparseConfig();
+
+ itsFontChanges=0;
+ if(itsFolders[FOLDER_SYS].modified.count())
+ {
+ if(itsRoot)
+ {
+ Misc::doCmd(FC_CACHE_CMD);
+ KFI_DBUG << "RUN(root): " << FC_CACHE_CMD << endl;
+
+ //
+ // If a non-default folder has been modified, always configure X
+ if(NULL==strchr(itsKfiParams, 'x') &&
+ (itsFolders[FOLDER_SYS].modified.count()>1 || !itsFolders[FOLDER_SYS].modified.contains(itsFolders[FOLDER_SYS].location)))
+ {
+ if(0==itsKfiParams[0])
+ strcpy(itsKfiParams, "-x");
+ else
+ strcat(itsKfiParams, "x");
+ }
+
+ if(0!=itsKfiParams[0])
+ {
+ CDirList::ConstIterator it(itsFolders[FOLDER_SYS].modified.begin()),
+ end(itsFolders[FOLDER_SYS].modified.end());
+
+ for(; it!=end; ++it)
+ {
+ Misc::doCmd("kfontinst", itsKfiParams, QFile::encodeName(*it));
+ KFI_DBUG << "RUN(root): kfontinst " << itsKfiParams << ' ' << *it << endl;
+ }
+
+ if(itsFolders[FOLDER_SYS].modified.contains(itsFolders[FOLDER_SYS].location))
+ {
+ itsHasSys=true;
+ itsAddToSysFc=false;
+ }
+ }
+ }
+ else
+ {
+ QCString cmd;
+
+ createRootRefreshCmd(cmd, itsFolders[FOLDER_SYS].modified, false);
+ if(doRootCmd(cmd, false) && itsFolders[FOLDER_SYS].modified.contains(itsFolders[FOLDER_SYS].location))
+ {
+ itsHasSys=true;
+ itsAddToSysFc=false;
+ }
+ if(NULL==strstr(itsNrsKfiParams, "s"))
+ Misc::doCmd("xset", "fp", "rehash"); // doRootCmd can only refresh if xfs is being used, so try here anyway...
+ }
+ itsFolders[FOLDER_SYS].modified.clear();
+ }
+
+ if(!itsRoot && itsFolders[FOLDER_USER].modified.count())
+ {
+ Misc::doCmd(FC_CACHE_CMD);
+ KFI_DBUG << "RUN(non-root): " << FC_CACHE_CMD << endl;
+
+ if(0!=itsKfiParams[0])
+ {
+ CDirList::ConstIterator it(itsFolders[FOLDER_USER].modified.begin()),
+ end(itsFolders[FOLDER_USER].modified.end());
+
+ for(; it!=end; ++it)
+ {
+ Misc::doCmd("kfontinst", itsKfiParams, QFile::encodeName(*it));
+ KFI_DBUG << "RUN(non-root): kfontinst " << itsKfiParams << ' ' << *it << endl;
+ }
+ }
+ itsFolders[FOLDER_USER].modified.clear();
+ }
+
+ KFI_DBUG << "finished ModifiedDirs" << endl;
+}
+
+#define SYS_USER "root"
+QString CKioFonts::getRootPasswd(bool askPasswd)
+{
+ KFI_DBUG << "getRootPasswd" << endl;
+ KIO::AuthInfo authInfo;
+ SuProcess proc(SYS_USER);
+ bool error=false;
+ int attempts=0;
+ QString errorMsg;
+
+ authInfo.url=KURL(KFI_KIO_FONTS_PROTOCOL ":///");
+ authInfo.username=SYS_USER;
+ authInfo.keepPassword=true;
+
+ if(!checkCachedAuthentication(authInfo) && !askPasswd)
+ authInfo.password=itsPasswd;
+
+ if(askPasswd)
+ while(!error && 0!=proc.checkInstall(authInfo.password.local8Bit()))
+ {
+ KFI_DBUG << "ATTEMPT : " << attempts << endl;
+ if(1==attempts)
+ errorMsg=i18n("Incorrect password.\n");
+ if((!openPassDlg(authInfo, errorMsg) && attempts) || ++attempts>4 || SYS_USER!=authInfo.username)
+ error=true;
+ }
+ else
+ error=proc.checkInstall(authInfo.password.local8Bit()) ? true : false;
+ return error ? QString::null : authInfo.password;
+}
+
+bool CKioFonts::doRootCmd(const char *cmd, const QString &passwd)
+{
+ KFI_DBUG << "doRootCmd " << cmd << endl;
+
+ if(!passwd.isEmpty())
+ {
+ SuProcess proc(SYS_USER);
+
+ if(itsCanStorePasswd)
+ itsPasswd=passwd;
+
+ KFI_DBUG << "Try to run command" << endl;
+ proc.setCommand(cmd);
+ return proc.exec(passwd.local8Bit()) ? false : true;
+ }
+
+ return false;
+}
+
+bool CKioFonts::confirmUrl(KURL &url)
+{
+ KFI_DBUG << "confirmUrl " << url.path() << endl;
+ if(!itsRoot)
+ {
+ QString sect(getSect(url.path()));
+
+ if(!isSysFolder(sect) && !isUserFolder(sect))
+ {
+ bool changeToSystem=false;
+
+ if(DEST_UNCHANGED!=itsLastDest && itsLastDestTime && (abs(time(NULL)-itsLastDestTime) < constMaxLastDestTime))
+ changeToSystem=DEST_SYS==itsLastDest;
+ else
+ changeToSystem=KMessageBox::No==messageBox(QuestionYesNo,
+ i18n("Do you wish to install the font into \"%1\" (in which "
+ "case the font will only be usable by you), or \"%2\" ("
+ "the font will be usable by all users - but you will "
+ "need to know the administrator's password)?")
+ .arg(i18n(KFI_KIO_FONTS_USER)).arg(i18n(KFI_KIO_FONTS_SYS)),
+ i18n("Where to Install"), i18n(KFI_KIO_FONTS_USER),
+ i18n(KFI_KIO_FONTS_SYS));
+
+ if(changeToSystem)
+ {
+ itsLastDest=DEST_SYS;
+ url.setPath(QChar('/')+i18n(KFI_KIO_FONTS_SYS)+QChar('/')+url.fileName());
+ }
+ else
+ {
+ itsLastDest=DEST_USER;
+ url.setPath(QChar('/')+i18n(KFI_KIO_FONTS_USER)+QChar('/')+url.fileName());
+ }
+
+ KFI_DBUG << "Changed URL to:" << url.path() << endl;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CKioFonts::clearFontList()
+{
+ KFI_DBUG << "clearFontList" << endl;
+
+ if(itsFontList)
+ FcFontSetDestroy(itsFontList);
+
+ itsFontList=NULL;
+ itsFolders[FOLDER_SYS].fontMap.clear();
+ itsFolders[FOLDER_USER].fontMap.clear();
+}
+
+bool CKioFonts::updateFontList()
+{
+ KFI_DBUG << "updateFontList" << endl;
+
+ if(!itsFontList || !FcConfigUptoDate(0) || // For some reason just the "!FcConfigUptoDate(0)" check does not always work :-(
+ (abs(time(NULL)-itsLastFcCheckTime)>constMaxFcCheckTime))
+ {
+ FcInitReinitialize();
+ clearFontList();
+ }
+
+ if(!itsFontList)
+ {
+ KFI_DBUG << "updateFontList - update list of fonts " << endl;
+
+ itsLastFcCheckTime=time(NULL);
+
+ FcPattern *pat = FcPatternCreate();
+ FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_FAMILY, FC_WEIGHT, FC_SCALABLE,
+#ifdef KFI_FC_HAS_WIDTHS
+ FC_WIDTH,
+#endif
+ FC_SLANT, (void*)0);
+
+ itsFontList=FcFontList(0, pat, os);
+
+ FcPatternDestroy(pat);
+ FcObjectSetDestroy(os);
+
+ if (itsFontList)
+ {
+ QString home(Misc::dirSyntax(QDir::homeDirPath()));
+
+ for (int i = 0; i < itsFontList->nfont; i++)
+ {
+ EFolder folder=FOLDER_SYS;
+ QString file(Misc::fileSyntax(CFcEngine::getFcString(itsFontList->fonts[i], FC_FILE)));
+
+ if(!file.isEmpty())
+ {
+ if(!itsRoot && 0==file.find(home))
+ folder=FOLDER_USER;
+
+ QValueList<FcPattern *> &patterns=
+ itsFolders[folder].fontMap[CFcEngine::createName(itsFontList->fonts[i])];
+ bool use=true;
+
+ if(patterns.count()) // Check for duplicates...
+ {
+ QValueList<FcPattern *>::Iterator it,
+ end=patterns.end();
+
+ for(it=patterns.begin(); use && it!=end; ++it)
+ if(file==(Misc::fileSyntax(CFcEngine::getFcString(*it, FC_FILE))))
+ use=false;
+ }
+ if(use)
+ patterns.append(itsFontList->fonts[i]);
+ }
+ }
+ }
+ }
+
+ if(NULL==itsFontList)
+ {
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Internal fontconfig error."));
+ return false;
+ }
+
+ return true;
+}
+
+CKioFonts::EFolder CKioFonts::getFolder(const KURL &url)
+{
+ return itsRoot || isSysFolder(getSect(url.path())) ? FOLDER_SYS : FOLDER_USER;
+}
+
+QMap<QString, QValueList<FcPattern *> >::Iterator CKioFonts::getMap(const KURL &url)
+{
+ EFolder folder(getFolder(url));
+ QMap<QString, QValueList<FcPattern *> >::Iterator it=itsFolders[folder].fontMap.find(removeMultipleExtension(url));
+
+ if(it==itsFolders[folder].fontMap.end()) // Perhaps it was fonts:/System/times.ttf ???
+ {
+ FcPattern *pat=getEntry(folder, url.fileName(), false);
+
+ if(pat)
+ it=itsFolders[folder].fontMap.find(CFcEngine::createName(pat));
+ }
+
+ return it;
+}
+
+QValueList<FcPattern *> * CKioFonts::getEntries(const KURL &url)
+{
+ QMap<QString, QValueList<FcPattern *> >::Iterator it=getMap(url);
+
+ if(it!=itsFolders[getFolder(url)].fontMap.end())
+ return &(it.data());
+
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Could not access \"%1\".").arg(url.prettyURL()));
+ return NULL;
+}
+
+FcPattern * CKioFonts::getEntry(EFolder folder, const QString &file, bool full)
+{
+ QMap<QString, QValueList<FcPattern *> >::Iterator it,
+ end=itsFolders[folder].fontMap.end();
+
+ for(it=itsFolders[folder].fontMap.begin(); it!=end; ++it)
+ {
+ QValueList<FcPattern *>::Iterator patIt,
+ patEnd=it.data().end();
+
+ for(patIt=it.data().begin(); patIt!=patEnd; ++patIt)
+ if( (full && CFcEngine::getFcString(*patIt, FC_FILE)==file) ||
+ (!full && Misc::getFile(CFcEngine::getFcString(*patIt, FC_FILE))==file))
+ return *patIt;
+ }
+
+ return NULL;
+}
+
+bool CKioFonts::checkFile(const QString &file)
+{
+ QCString cFile(QFile::encodeName(file));
+
+ //
+ // To speed things up, check the files extension 1st...
+ if(checkExt(cFile, "ttf") || checkExt(cFile, "otf") || checkExt(cFile, "ttc") || checkExt(cFile, "pfa") || checkExt(cFile, "pfb") ||
+ isAAfm(file) || isAPfm(file))
+ return true;
+
+ //
+ // No exension match, so try querying with FreeType...
+ int count=0;
+ FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(file).data()), 0, NULL, &count);
+
+ if(pat)
+ {
+ FcPatternDestroy(pat);
+ return true;
+ }
+
+ error(KIO::ERR_SLAVE_DEFINED, i18n("<p>Only fonts may be installed.</p><p>If installing a fonts package (*%1), then "
+ "extract the components, and install individually.</p>").arg(constMultipleExtension));
+ return false;
+}
+
+bool CKioFonts::getSourceFiles(const KURL &src, QStringList &files)
+{
+ if(KFI_KIO_FONTS_PROTOCOL==src.protocol())
+ {
+ QValueList<FcPattern *> *entries=getEntries(src);
+
+ if(entries && entries->count())
+ {
+ QValueList<FcPattern *>::Iterator it,
+ end=entries->end();
+
+ for(it=entries->begin(); it!=end; ++it)
+ files.append(CFcEngine::getFcString(*it, FC_FILE));
+ }
+
+ if(files.count())
+ {
+ QStringList::Iterator sIt,
+ sEnd=files.end();
+
+ for(sIt=files.begin(); sIt!=sEnd; ++sIt)
+ {
+ KURL::List urls;
+
+ Misc::getAssociatedUrls(KURL(*sIt), urls);
+
+ if(urls.count())
+ {
+ KURL::List::Iterator uIt,
+ uEnd=urls.end();
+
+ for(uIt=urls.begin(); uIt!=uEnd; ++uIt)
+ if(-1==files.findIndex((*uIt).path()))
+ files.append((*uIt).path());
+ }
+ }
+ }
+ }
+ else
+ if(src.isLocalFile())
+ if(checkFile(src.path()))
+ files.append(src.path());
+ else
+ return false; // error logged in checkFile...
+
+ if(files.count())
+ {
+ QStringList::Iterator it,
+ end=files.end();
+
+ for(it=files.begin(); it!=end; ++it)
+ {
+ QCString realSrc=QFile::encodeName(*it);
+ KDE_struct_stat buffSrc;
+
+ if (-1==KDE_stat(realSrc.data(), &buffSrc))
+ {
+ error(EACCES==errno ? KIO::ERR_ACCESS_DENIED : KIO::ERR_DOES_NOT_EXIST, src.prettyURL());
+ return false;
+ }
+ if(S_ISDIR(buffSrc.st_mode))
+ {
+ error(KIO::ERR_IS_DIRECTORY, src.prettyURL());
+ return false;
+ }
+ if(S_ISFIFO(buffSrc.st_mode) || S_ISSOCK(buffSrc.st_mode))
+ {
+ error(KIO::ERR_CANNOT_OPEN_FOR_READING, src.prettyURL());
+ return false;
+ }
+ }
+ }
+ else
+ {
+ error(KIO::ERR_DOES_NOT_EXIST, src.prettyURL());
+ return false;
+ }
+
+ return true;
+}
+
+bool CKioFonts::checkDestFile(const KURL &src, const KURL &dest, EFolder destFolder, bool overwrite)
+{
+ if(!overwrite && (Misc::fExists(itsFolders[destFolder].location+src.fileName()) ||
+ Misc::fExists(itsFolders[destFolder].location+modifyName(src.fileName())) ) )
+ {
+ error(KIO::ERR_FILE_ALREADY_EXIST, dest.prettyURL());
+ return false;
+ }
+
+ return true;
+}
+
+bool CKioFonts::checkDestFiles(const KURL &src, QMap<QString, QString> &map, const KURL &dest, EFolder destFolder, bool overwrite)
+{
+ //
+ // Check whether files exist at destination...
+ //
+ if(dest.protocol()==src.protocol() &&
+ dest.directory()==src.directory()) // Check whether confirmUrl changed a "cp fonts:/System fonts:/"
+ // to "cp fonts:/System fonts:/System"
+ {
+ error(KIO::ERR_FILE_ALREADY_EXIST, dest.prettyURL());
+ return false;
+ }
+
+ if(!overwrite)
+ {
+ QMap<QString, QString>::Iterator fIt(map.begin()),
+ fEnd(map.end());
+
+ for(; fIt!=fEnd; ++fIt)
+ if(NULL!=getEntry(destFolder, fIt.data()) || NULL!=getEntry(destFolder, modifyName(fIt.data())))
+ {
+ error(KIO::ERR_FILE_ALREADY_EXIST, dest.prettyURL());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//
+// Gather the number and names of the font faces located in "files". If there is more than 1 face
+// (such as there would be for a TTC font), then ask the user for confirmation of the action.
+bool CKioFonts::confirmMultiple(const KURL &url, const QStringList &files, EFolder folder, EOp op)
+{
+ if(KFI_KIO_FONTS_PROTOCOL!=url.protocol())
+ return true;
+
+ QStringList::ConstIterator it,
+ end=files.end();
+ QStringList fonts;
+
+ for(it=files.begin(); it!=files.end(); ++it)
+ {
+ FcPattern *pat=getEntry(folder, *it, false);
+
+ if(pat)
+ {
+ QString name(CFcEngine::createName(pat));
+
+ if(-1==fonts.findIndex(name))
+ fonts.append(name);
+ }
+ }
+
+ if(fonts.count()>1)
+ {
+ QString out;
+ QStringList::Iterator it,
+ end=fonts.end();
+
+ for(it=fonts.begin(); it!=end; ++it)
+ out+=QString("<li>")+*it+QString("</li>");
+
+ if(KMessageBox::No==messageBox(QuestionYesNo,
+ OP_MOVE==op
+ ? i18n("<p>This font is located in a file alongside other fonts; in order "
+ "to proceed with the moving they will all have to be moved. "
+ "The other affected fonts are:</p><ul>%1</ul><p>\n Do you wish to "
+ "move all of these?</p>").arg(out)
+ : OP_COPY==op
+ ? i18n("<p>This font is located in a file alongside other fonts; in order "
+ "to proceed with the copying they will all have to be copied. "
+ "The other affected fonts are:</p><ul>%1</ul><p>\n Do you wish to "
+ "copy all of these?</p>").arg(out)
+ : i18n("<p>This font is located in a file alongside other fonts; in order "
+ "to proceed with the deleting they will all have to be deleted. "
+ "The other affected fonts are:</p><ul>%1</ul><p>\n Do you wish to "
+ "delete all of these?</p>").arg(out)))
+ {
+ error(KIO::ERR_USER_CANCELED, url.prettyURL());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CKioFonts::confirmMultiple(const KURL &url, QValueList<FcPattern *> *patterns, EFolder folder, EOp op)
+{
+ if(KFI_KIO_FONTS_PROTOCOL!=url.protocol())
+ return true;
+
+ QStringList files;
+
+ if(patterns && patterns->count())
+ {
+ QValueList<FcPattern *>::Iterator it,
+ end=patterns->end();
+
+ for(it=patterns->begin(); it!=end; ++it)
+ files.append(CFcEngine::getFcString(*it, FC_FILE));
+ }
+
+ return confirmMultiple(url, files, folder, op);
+}
+
+bool CKioFonts::checkUrl(const KURL &u, bool rootOk)
+{
+ if(KFI_KIO_FONTS_PROTOCOL==u.protocol() && (!rootOk || (rootOk && "/"!=u.path())))
+ {
+ QString sect(getSect(u.path()));
+
+ if(itsRoot)
+ {
+ if((isSysFolder(sect) || isUserFolder(sect)) &&
+ (itsFolders[FOLDER_SYS].fontMap.end()==itsFolders[FOLDER_SYS].fontMap.find(sect)))
+//CPD: TODO: || it has a font specified! e.g. fonts:/System/Times -> even in have a fonts:/System font, redirect
+//should still happen
+ {
+ redirection(getRedirect(u));
+ finished();
+ return false;
+ }
+ }
+ else
+ if(!isSysFolder(sect) && !isUserFolder(sect))
+ {
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Please specify \"%1\" or \"%2\".")
+ .arg(i18n(KFI_KIO_FONTS_USER)).arg(i18n(KFI_KIO_FONTS_SYS)));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CKioFonts::checkAllowed(const KURL &u)
+{
+ if (KFI_KIO_FONTS_PROTOCOL==u.protocol())
+ {
+ QString ds(Misc::dirSyntax(u.path()));
+
+ if(ds==QString(QChar('/')+i18n(KFI_KIO_FONTS_USER)+QChar('/')) ||
+ ds==QString(QChar('/')+i18n(KFI_KIO_FONTS_SYS)+QChar('/')) ||
+ ds==QString(QChar('/')+QString::fromLatin1(KFI_KIO_FONTS_USER)+QChar('/')) ||
+ ds==QString(QChar('/')+QString::fromLatin1(KFI_KIO_FONTS_SYS)+QChar('/')))
+ {
+ error(KIO::ERR_SLAVE_DEFINED, i18n("Sorry, you cannot rename, move, copy, or delete either \"%1\" or \"%2\".")
+ .arg(i18n(KFI_KIO_FONTS_USER)).arg(i18n(KFI_KIO_FONTS_SYS))); \
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//
+// Create an AFM from a Type 1 (pfa/pfb) font and its PFM file...
+void CKioFonts::createAfm(const QString &file, bool nrs, const QString &passwd)
+{
+ if(nrs && passwd.isEmpty())
+ return;
+
+ bool type1=isAType1(file),
+ pfm=!type1 && isAPfm(file); // No point checking if is pfm if its a type1
+
+ if(type1 || pfm)
+ {
+ QString afm=getMatch(file, "afm"); // pf2afm wants files with lowercase extension, so just check for lowercase!
+ // -- when a font is installed, the extensio is converted to lowercase anyway...
+
+ if(afm.isEmpty()) // No point creating if AFM already exists!
+ {
+ QString pfm,
+ t1;
+
+ if(type1) // Its a Type1, so look for existing PFM
+ {
+ pfm=getMatch(file, "pfm");
+ t1=file;
+ }
+ else // Its a PFM, so look for existing Type1
+ {
+ t1=getMatch(file, "pfa");
+ if(t1.isEmpty())
+ t1=getMatch(file, "pfb");
+ pfm=file;
+ }
+
+ if(!t1.isEmpty() && !pfm.isEmpty()) // Do we have both Type1 and PFM?
+ {
+ QString name(t1.left(t1.length()-4)); // pf2afm wants name without extension...
+
+ if(nrs)
+ {
+ QCString cmd("pf2afm ");
+ cmd+=QFile::encodeName(KProcess::quote(name));
+ doRootCmd(cmd, passwd);
+ }
+ else
+ Misc::doCmd("pf2afm", QFile::encodeName(name));
+ }
+ }
+ }
+}
+
+void CKioFonts::reparseConfig()
+{
+ KFI_DBUG << "reparseConfig" << endl;
+
+ itsKfiParams[0]=0;
+ if(!itsRoot)
+ {
+ itsNrsKfiParams[0]=0;
+ itsNrsNonMainKfiParams[0]=0;
+ }
+
+ if(itsRoot)
+ {
+ KConfig cfg(KFI_ROOT_CFG_FILE);
+ bool doX=cfg.readBoolEntry(KFI_CFG_X_KEY, KFI_DEFAULT_CFG_X),
+ doGs=cfg.readBoolEntry(KFI_CFG_GS_KEY, KFI_DEFAULT_CFG_GS);
+
+ if(doX || !doGs)
+ {
+ strcpy(itsKfiParams, doGs ? "-g" : "-");
+ if(doX)
+ {
+ if(!itsUsingXfsFpe)
+ strcat(itsKfiParams, "r");
+
+ if(!itsUsingFcFpe)
+ {
+ strcat(itsKfiParams, itsUsingXfsFpe ? "sx" : "x");
+ if(!itsHasSys)
+ strcat(itsKfiParams, "a");
+ }
+ }
+ }
+ }
+ else
+ {
+ KConfig rootCfg(KFI_ROOT_CFG_FILE);
+ bool rootDoX=rootCfg.readBoolEntry(KFI_CFG_X_KEY, KFI_DEFAULT_CFG_X),
+ rootDoGs=rootCfg.readBoolEntry(KFI_CFG_GS_KEY, KFI_DEFAULT_CFG_GS);
+
+ strcpy(itsNrsKfiParams, "-");
+
+ if(rootDoX || rootDoGs)
+ {
+ strcpy(itsNrsKfiParams, "-");
+ strcpy(itsNrsNonMainKfiParams, "-");
+
+ if(rootDoGs)
+ {
+ strcpy(itsNrsKfiParams, "g");
+ strcpy(itsNrsNonMainKfiParams, "g");
+ }
+
+ if(rootDoX && !itsUsingFcFpe)
+ {
+ strcat(itsNrsKfiParams, itsUsingXfsFpe ? "sx" : "x"); // Can't get root to refresh X, only xfs!
+ strcat(itsNrsNonMainKfiParams, itsUsingXfsFpe ? "sx" : "x");
+ if(!itsHasSys)
+ strcat(itsNrsKfiParams, "a");
+ }
+ if(0==itsNrsNonMainKfiParams[1])
+ itsNrsNonMainKfiParams[0]=0;
+ }
+
+ if(itsAddToSysFc)
+ strcpy(itsNrsKfiParams, "f");
+
+ if(0==itsNrsKfiParams[1])
+ itsNrsKfiParams[0]=0;
+
+ KConfig cfg(KFI_CFG_FILE);
+ bool doX=cfg.readBoolEntry(KFI_CFG_X_KEY, KFI_DEFAULT_CFG_X),
+ doGs=cfg.readBoolEntry(KFI_CFG_GS_KEY, KFI_DEFAULT_CFG_GS);
+
+ strcpy(itsKfiParams, doGs ? "-g" : "-");
+
+ if(doX)
+ strcat(itsKfiParams, itsUsingFcFpe ? "r" : "rx");
+ }
+
+ if(0==itsKfiParams[1])
+ itsKfiParams[0]=0;
+}
+
+}
diff --git a/kcontrol/kfontinst/kio/KioFonts.h b/kcontrol/kfontinst/kio/KioFonts.h
new file mode 100644
index 000000000..abfd6b042
--- /dev/null
+++ b/kcontrol/kfontinst/kio/KioFonts.h
@@ -0,0 +1,161 @@
+#ifndef __KIO_FONTS_H__
+#define __KIO_FONTS_H__
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Class Name : KFI::CKioFonts
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 05/03/2003
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+#include <fontconfig/fontconfig.h>
+#include <time.h>
+#include <kio/slavebase.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <qstring.h>
+#include <qcstring.h>
+#include <qmap.h>
+#include <qvaluelist.h>
+#include "Misc.h"
+#include "KfiConstants.h"
+
+namespace KFI
+{
+
+class CKioFonts : public KIO::SlaveBase
+{
+ private:
+
+ enum EConstants
+ {
+ KFI_PARAMS = 8
+ };
+
+ enum EDest
+ {
+ DEST_UNCHANGED,
+ DEST_SYS,
+ DEST_USER
+ };
+
+ enum EFolder
+ {
+ FOLDER_SYS,
+ FOLDER_USER,
+
+ FOLDER_COUNT
+ };
+
+ enum EOp
+ {
+ OP_COPY,
+ OP_MOVE,
+ OP_DELETE
+ };
+
+ class CDirList : public QStringList
+ {
+ public:
+
+ CDirList() { }
+ CDirList(const QString &str) : QStringList(str) { }
+
+ void add(const QString &d) { if (!contains(d)) append(d); }
+ };
+
+ struct TFolder
+ {
+ QString location;
+ CDirList modified;
+ QMap<QString, QValueList<FcPattern *> > fontMap; // Maps from "Times New Roman" -> $HOME/.fonts/times.ttf
+ };
+
+ public:
+
+ CKioFonts(const QCString &pool, const QCString &app);
+ virtual ~CKioFonts();
+
+ static QString getSect(const QString &f) { return f.section('/', 1, 1); }
+
+ void listDir(const KURL &url);
+ void stat(const KURL &url);
+ bool createStatEntry(KIO::UDSEntry &entry, const KURL &url, EFolder folder);
+ void get(const KURL &url);
+ void put(const KURL &url, int mode, bool overwrite, bool resume);
+ void copy(const KURL &src, const KURL &dest, int mode, bool overwrite);
+ void rename(const KURL &src, const KURL &dest, bool overwrite);
+ void del(const KURL &url, bool isFile);
+
+ private:
+
+ bool putReal(const QString &destOrig, const QCString &destOrigC, bool origExists, int mode, bool resume);
+ void modified(EFolder folder, bool clearList=true, const CDirList &dirs=CDirList());
+ void special(const QByteArray &a);
+ void createRootRefreshCmd(QCString &cmd, const CDirList &dirs=CDirList(), bool reparseCfg=true);
+ void doModified();
+ QString getRootPasswd(bool askPasswd=true);
+ bool doRootCmd(const char *cmd, const QString &passwd);
+ bool doRootCmd(const char *cmd, bool askPasswd=true) { return doRootCmd(cmd, getRootPasswd(askPasswd)); }
+ bool confirmUrl(KURL &url);
+ void clearFontList();
+ bool updateFontList();
+ EFolder getFolder(const KURL &url);
+ QMap<QString, QValueList<FcPattern *> >::Iterator getMap(const KURL &url);
+ QValueList<FcPattern *> * getEntries(const KURL &url);
+ FcPattern * getEntry(EFolder folder, const QString &file, bool full=false);
+ bool checkFile(const QString &file);
+ bool getSourceFiles(const KURL &src, QStringList &files);
+ bool checkDestFile(const KURL &src, const KURL &dest, EFolder destFolder, bool overwrite);
+ bool checkDestFiles(const KURL &src, QMap<QString, QString> &map, const KURL &dest, EFolder destFolder, bool overwrite);
+ bool confirmMultiple(const KURL &url, const QStringList &files, EFolder folder, EOp op);
+ bool confirmMultiple(const KURL &url, QValueList<FcPattern *> *patterns, EFolder folder, EOp op);
+ bool checkUrl(const KURL &u, bool rootOk=false);
+ bool checkAllowed(const KURL &u);
+ void createAfm(const QString &file, bool nrs=false, const QString &passwd=QString::null);
+ void reparseConfig();
+
+ private:
+
+ bool itsRoot,
+ itsCanStorePasswd,
+ itsUsingFcFpe,
+ itsUsingXfsFpe,
+ itsHasSys,
+ itsAddToSysFc;
+ QString itsPasswd;
+ unsigned int itsFontChanges;
+ EDest itsLastDest;
+ time_t itsLastDestTime,
+ itsLastFcCheckTime;
+ FcFontSet *itsFontList;
+ TFolder itsFolders[FOLDER_COUNT];
+ char itsNrsKfiParams[KFI_PARAMS],
+ itsNrsNonMainKfiParams[KFI_PARAMS],
+ itsKfiParams[KFI_PARAMS];
+};
+
+}
+
+#endif
diff --git a/kcontrol/kfontinst/kio/Makefile.am b/kcontrol/kfontinst/kio/Makefile.am
new file mode 100644
index 000000000..ad0f2ea8e
--- /dev/null
+++ b/kcontrol/kfontinst/kio/Makefile.am
@@ -0,0 +1,20 @@
+kde_module_LTLIBRARIES = kio_fonts.la
+kio_fonts_la_SOURCES = \
+KioFonts.cpp
+
+kio_fonts_la_LIBADD = ../../fonts/libkxftconfig.la $(LIBFONTCONFIG_LIBS) $(LIBFREETYPE_LIBS) $(LIB_KIO) -lkdesu ../lib/libkfontinst.la
+kio_fonts_la_LDFLAGS = $(KDE_PLUGIN) $(all_libraries) $(KDE_RPATH) $(LIBFONTCONFIG_RPATH) $(LIBFREETYPE_RPATH) -module -avoid-version -no-undefined
+AM_CPPFLAGS= -I$(srcdir)/../lib -I$(srcdir)/../../fonts $(all_includes) $(LIBFREETYPE_CFLAGS) $(LIBFONTCONFIG_CFLAGS) -D_LARGEFILE64_SOURCE
+
+# The kxftconfig stuf really belongs to kdebase/kcontrol/fonts - here only so that can distribute this as an archive.
+noinst_HEADERS = \
+KioFonts.h
+
+servicesdir = $(kde_servicesdir)
+services_DATA = fonts.protocol
+
+vfsdata_DATA = fonts.desktop
+vfsdatadir = $(kde_datadir)/konqsidebartng/virtual_folders/services
+
+mimetype_DATA = folder.desktop system-folder.desktop package.desktop
+mimetypedir = $(kde_mimedir)/fonts
diff --git a/kcontrol/kfontinst/kio/folder.desktop b/kcontrol/kfontinst/kio/folder.desktop
new file mode 100644
index 000000000..24e328ae8
--- /dev/null
+++ b/kcontrol/kfontinst/kio/folder.desktop
@@ -0,0 +1,80 @@
+[Desktop Entry]
+Comment=Fonts Folder
+Comment[af]=Skrif tipe Gids
+Comment[ar]=مجلد المحارف
+Comment[be]=Тэчка шрыфтоў
+Comment[bg]=Директория за шрифтове
+Comment[bn]=ফন্ট ফোল্ডার
+Comment[br]=Renkell ar fontoù
+Comment[bs]=Direktorij sa fontovima
+Comment[ca]=Carpeta de lletres
+Comment[cs]=Složka písem
+Comment[csb]=Katalog fòntów
+Comment[da]=Skrifttypemappe
+Comment[de]=Ordner für Schriftarten
+Comment[el]=Φάκελος γραμματοσειρών
+Comment[eo]=Tipardosierujo
+Comment[es]=Carpeta de tipos de letra
+Comment[et]=Fontide kataloog
+Comment[eu]=Letra-tipoen karpeta
+Comment[fa]=پوشۀ قلم
+Comment[fi]=Kirjasinkansio
+Comment[fr]=Dossier de polices de caractères
+Comment[fy]=Lettertypenmap
+Comment[ga]=Fillteán na gClónna
+Comment[gl]=Cartafol das Fontes
+Comment[he]=תיקיית גופנים
+Comment[hi]=फ़ॉन्ट्स फ़ोल्डर
+Comment[hr]=Mapa fontova
+Comment[hu]=Betűtípuskönyvtár
+Comment[id]=Folder Fonts
+Comment[is]=Leturmappa
+Comment[it]=Cartella dei caratteri
+Comment[ja]=フォントフォルダ
+Comment[ka]=ფონტების საქაღალდე
+Comment[kk]=Қаріп қапшығы
+Comment[km]=ថត​ពុម្ពអក្សរ
+Comment[ko]=홈 폴더
+Comment[lt]=Šriftų aplankas
+Comment[lv]=Fontu mape
+Comment[mk]=Папка со фонтови
+Comment[ms]=Folder Fon
+Comment[mt]=Direttorju tal-fonts
+Comment[nb]=Mappe for skrifttyper
+Comment[nds]=Schriftoorden-Orner
+Comment[ne]=फन्ट फोल्डर
+Comment[nl]=Lettertypenmap
+Comment[nn]=Skriftmappe
+Comment[pa]=ਫੋਂਟ ਫੋਲਡਰ
+Comment[pl]=Katalog czcionek
+Comment[pt]=Pasta de Tipos de Letra
+Comment[pt_BR]=Pasta de Fontes
+Comment[ro]=Folder de fonturi
+Comment[ru]=Папка шрифтов
+Comment[rw]=Ububiko bw'Imyandikire
+Comment[se]=Fontamáhppa
+Comment[sk]=Priečinok písiem
+Comment[sl]=Mapa za pisave
+Comment[sr]=Фасцикла за фонтове
+Comment[sr@Latn]=Fascikla za fontove
+Comment[sv]=Teckensnittskatalog
+Comment[ta]=எழுத்துருக்கள் அடைவு
+Comment[tg]=Феҳристи ҳарфҳо
+Comment[th]=โฟลเดอร์แฟ้มแบบอักษร
+Comment[tr]=Yazıtipi Klasörü
+Comment[tt]=Yazu lar Törgäge
+Comment[uk]=Тека шрифтів
+Comment[uz]=Shriftlarning jildi
+Comment[uz@cyrillic]=Шрифтларнинг жилди
+Comment[vi]=Thư mục Phông chữ
+Comment[wa]=Ridant di fontes
+Comment[zh_CN]=字体文件夹
+Comment[zh_TW]=字型資料夾
+Icon=folder
+Type=MimeType
+MimeType=fonts/folder
+Patterns=
+
+X-KDE-AutoEmbed=true
+X-KDE-IsAlso=inode/directory
+
diff --git a/kcontrol/kfontinst/kio/fonts.desktop b/kcontrol/kfontinst/kio/fonts.desktop
new file mode 100644
index 000000000..0095f49d2
--- /dev/null
+++ b/kcontrol/kfontinst/kio/fonts.desktop
@@ -0,0 +1,85 @@
+[Desktop Entry]
+Type=Link
+URL=fonts:/
+Icon=fonts
+Name=Fonts
+Name[af]=Skriftipes
+Name[ar]=المحارف
+Name[az]=Yazı növləri
+Name[be]=Шрыфты
+Name[bg]=Шрифтове
+Name[bn]=ফন্ট
+Name[br]=Fontoù
+Name[bs]=Fontovi
+Name[ca]=Lletres
+Name[cs]=Písma
+Name[csb]=Fòntë
+Name[cy]=Ffontiau
+Name[da]=Skrifttyper
+Name[de]=Schriftarten
+Name[el]=Γραμματοσειρές
+Name[eo]=Tiparoj
+Name[es]=Tipos de letra
+Name[et]=Fondid
+Name[eu]=Letra-tipoak
+Name[fa]=قلمها
+Name[fi]=Kirjasimet
+Name[fr]=Polices
+Name[fy]=Lettertypen
+Name[ga]=Clónna
+Name[gl]=Fontes
+Name[he]=גופנים
+Name[hi]=फ़ॉन्ट्स
+Name[hr]=Fontovi
+Name[hu]=Betűtípusok
+Name[is]=Letur
+Name[it]=Tipi di carattere
+Name[ja]=フォント
+Name[ka]=ფონტები
+Name[kk]=Қаріптер
+Name[km]=ពុម្ពអក្សរ
+Name[ko]=글꼴
+Name[lo]=ຮູບແບບຕົວອັກສອນ
+Name[lt]=Šriftai
+Name[lv]=Fonti
+Name[mk]=Фонтови
+Name[mn]=Бичгүүд
+Name[ms]=Fon
+Name[nb]=Skrifttype
+Name[nds]=Schriftoorden
+Name[ne]=फन्ट
+Name[nl]=Lettertypen
+Name[nn]=Skrifttypar
+Name[nso]=Difonto
+Name[pa]=ਫੋਂਟ
+Name[pl]=Czcionki
+Name[pt]=Tipos de Letra
+Name[pt_BR]=Fontes
+Name[ro]=Fonturi
+Name[ru]=Шрифты
+Name[rw]=Imyandikire
+Name[se]=Fonttat
+Name[sk]=Písma
+Name[sl]=Pisave
+Name[sr]=Фонтови
+Name[sr@Latn]=Fontovi
+Name[ss]=Timo tetinhlamvu temagama
+Name[sv]=Teckensnitt
+Name[ta]=எழுத்துருக்கள்
+Name[tg]=Ҳарфҳо
+Name[th]=แบบอักษร
+Name[tr]=Yazıtipleri
+Name[tt]=Yazu
+Name[uk]=Шрифти
+Name[uz]=Shriftlar
+Name[uz@cyrillic]=Шрифтлар
+Name[ven]=Fontu
+Name[vi]=Phông chữ
+Name[wa]=Fontes
+Name[xh]=Uhlobo lwamagama
+Name[zh_CN]=字体
+Name[zh_TW]=字型
+Name[zu]=Izinhlobo zamagama
+Open=false
+X-KDE-TreeModule=Directory
+X-KDE-KonqSidebarModule=konqsidebar_tree
diff --git a/kcontrol/kfontinst/kio/fonts.protocol b/kcontrol/kfontinst/kio/fonts.protocol
new file mode 100644
index 000000000..7f54dd0cc
--- /dev/null
+++ b/kcontrol/kfontinst/kio/fonts.protocol
@@ -0,0 +1,18 @@
+[Protocol]
+exec=kio_fonts
+protocol=fonts
+input=none
+output=filesystem
+listing=Name,Type,Size,Date,AccessDate,Access,Owner,Group,Link
+reading=true
+writing=true
+makedir=false
+deleting=true
+moving=true
+linking=false
+copyToFile=false
+copyFromFile=true
+Icon=fonts
+defaultMimetype=application/octet-stream
+maxInstances=1
+Class=:local
diff --git a/kcontrol/kfontinst/kio/package.desktop b/kcontrol/kfontinst/kio/package.desktop
new file mode 100644
index 000000000..4ee3543de
--- /dev/null
+++ b/kcontrol/kfontinst/kio/package.desktop
@@ -0,0 +1,74 @@
+[Desktop Entry]
+Type=MimeType
+MimeType=fonts/package
+Icon=font
+Patterns=*.fonts.tar.gz
+Comment=Fonts Package
+Comment[af]=Skriftipes Paket
+Comment[ar]=حزمة المحارف
+Comment[be]=Пакет шрыфтоў
+Comment[bg]=Пакет с шрифтове
+Comment[bn]=ফন্ট প্যাকেজ
+Comment[bs]=Paket fontova
+Comment[ca]=Paquet de lletres
+Comment[cs]=Balík písem
+Comment[csb]=Paczét fòntów
+Comment[da]=Skrifttypepakke
+Comment[de]=Schriftartenpaket
+Comment[el]=Πακέτο γραμματοσειρών
+Comment[eo]=Tiparpakaĵo
+Comment[es]=Paquete de tipos de letra
+Comment[et]=Fondipakett
+Comment[eu]=Letra-tipoen paketea
+Comment[fa]=بستۀ قلمها
+Comment[fi]=Kirjasinpaketti
+Comment[fr]=Paquet de polices
+Comment[fy]=Lettertypenpakket
+Comment[ga]=Pacáiste na gClónna
+Comment[gl]=Pacote das Fontes
+Comment[he]=חבילת גופנים
+Comment[hr]=Paket fontova
+Comment[hu]=Betűtípuscsomag
+Comment[id]=Paket Font
+Comment[is]=Leturpakki
+Comment[it]=Pacchetto tipi di caratteri
+Comment[ja]=フォントパッケージ
+Comment[ka]=შრიფტების პაკეტი
+Comment[kk]=Қаріп дестесі
+Comment[km]=កញ្ចប់​ពុម្ពអក្សរ
+Comment[lt]=Šriftų paketas
+Comment[mk]=Пакет со фонтови
+Comment[ms]=Pakej Fon
+Comment[nb]=Pakke for skrifttyper
+Comment[nds]=Schriftoorden-Paket
+Comment[ne]=फन्ट प्याकेज
+Comment[nl]=Lettertypenpakket
+Comment[nn]=Pakke for skrifter
+Comment[pa]=ਫੋਂਟ ਪੈਕੇਜ
+Comment[pl]=Pakiet czcionek
+Comment[pt]=Pacote de Tipos de Letra
+Comment[pt_BR]=Pacote de Fontes
+Comment[ro]=Pachet de fonturi
+Comment[ru]=Пакет шрифтов
+Comment[rw]=Rukomatanya y'Imyandikire
+Comment[se]=Fontapáhkka
+Comment[sk]=Balík písiem
+Comment[sl]=Paket pisav
+Comment[sr]=Пакет фонтова
+Comment[sr@Latn]=Paket fontova
+Comment[sv]=Teckensnittspaket
+Comment[tg]=Бастаи ҳарфҳо
+Comment[th]=แพคเกจแบบอักษร
+Comment[tr]=Yazıtipi Paketi
+Comment[tt]=Yazular Tuplaması
+Comment[uk]=Пакунок шрифтів
+Comment[uz]=Shrift
+Comment[uz@cyrillic]=Шрифт
+Comment[vi]=Gói Phông chữ
+Comment[wa]=Paket di fontes
+Comment[zh_CN]=字体包
+Comment[zh_TW]=字型套件
+
+[Property::X-KDE-LocalProtocol]
+Type=QString
+Value=tar
diff --git a/kcontrol/kfontinst/kio/system-folder.desktop b/kcontrol/kfontinst/kio/system-folder.desktop
new file mode 100644
index 000000000..07bf9d703
--- /dev/null
+++ b/kcontrol/kfontinst/kio/system-folder.desktop
@@ -0,0 +1,79 @@
+[Desktop Entry]
+Comment=System Fonts Folder
+Comment[af]=Stelsel Skrif tipe Gids
+Comment[ar]=مجلد محارف النظام
+Comment[be]=Тэчка сістэмных шрыфтоў
+Comment[bg]=Директория за системните шрифтове
+Comment[bn]=সিস্টেম ফন্ট ফোল্ডার
+Comment[br]=Renkell fontoù ar reizhiad
+Comment[bs]=Sistemski direktorij sa fontovima
+Comment[ca]=Carpeta de lletres del sistema
+Comment[cs]=Složka se systémovými písmy
+Comment[csb]=Katalog systemòwëch fòntów
+Comment[da]=Mappe til systemets skrifttyper
+Comment[de]=Ordner für Systemschriften
+Comment[el]=Φάκελος γραμματοσειρών συστήματος
+Comment[eo]=Sistema tipardosierujo
+Comment[es]=Carpeta de tipos de letra del sistema
+Comment[et]=Süsteemi fontide kataloog
+Comment[eu]=Sistemaren letra-tipoen karpeta
+Comment[fa]=پوشۀ قلمهای سیستم
+Comment[fi]=Järjestelmän kirjasinkansio
+Comment[fr]=Dossier système de polices de caractères
+Comment[fy]=Systeemlettertypenmap
+Comment[ga]=Fillteán Clónna an Chórais
+Comment[gl]=Cartafol das Fontes do Sistema
+Comment[he]=תיקיית גופני מערכת
+Comment[hi]=तंत्र फ़ॉन्ट्स फ़ोल्डर
+Comment[hr]=Mapa sistemskih fontova
+Comment[hu]=A rendszer betűtípusainak könyvtára
+Comment[id]=Folder Font Sistem
+Comment[is]=Kerfisleturmappa
+Comment[it]=Cartella dei caratteri di sistema
+Comment[ja]=システムフォントフォルダ
+Comment[ka]=სისტემური ფონტების საქაღალდე
+Comment[kk]=Жүйелік қаріптер қапшығы
+Comment[km]=ថត​ពុម្ពអក្សរ​ប្រព័ន្ធ
+Comment[lt]=Sistemos šriftų aplankas
+Comment[lv]=Sistēmas fontu mape
+Comment[mk]=Папка со системски фонтови
+Comment[ms]=Folder Fon Sistem
+Comment[mt]=Direttorju tal-fonts tas-sistema
+Comment[nb]=Mappe for systemskrifttyper
+Comment[nds]=Orner för de Systeemschriftoorden
+Comment[ne]=फन्ट फोल्डर प्रणाली
+Comment[nl]=Systeemlettertypenmap
+Comment[nn]=Systemskriftmappe
+Comment[pa]=ਸਿਸਟਮ ਫੋਂਟ ਫੋਲਡਰ
+Comment[pl]=Katalog czcionek systemowych
+Comment[pt]=Pasta de Tipos de Letra do Sistema
+Comment[pt_BR]=Pasta de Fontes do Sistema
+Comment[ro]=Folder fonturi de sistem
+Comment[ru]=Папка системных шрифтов
+Comment[rw]=Ububiko bw'Imyandikire Sisitemu
+Comment[se]=Vuogádatfontamáhppa
+Comment[sk]=Priečinok systémových písiem
+Comment[sl]=Mapa za sistemske pisave
+Comment[sr]=Фасцикла за системске фонтове
+Comment[sr@Latn]=Fascikla za sistemske fontove
+Comment[sv]=Systemteckensnittskatalog
+Comment[ta]=அமைப்பு எழுத்துருக்கள் அடைவு
+Comment[tg]=Системаи феҳристи ҳарфҳо
+Comment[th]=โฟลเดอร์แฟ้มแบบอักษรของระบบ
+Comment[tr]=Sistem Yazı Tipi Klasörü
+Comment[tt]=Sistem Yazular Törgäge
+Comment[uk]=Тека системних шрифтів
+Comment[uz]=Tizim shriftlarining jildi
+Comment[uz@cyrillic]=Тизим шрифтларининг жилди
+Comment[vi]=Thư mục Phông chữ Hệ thống
+Comment[wa]=Ridant di fontes do sistinme
+Comment[zh_CN]=系统字体文件夹
+Comment[zh_TW]=系統字型資料夾
+Icon=folder_red
+Type=MimeType
+MimeType=fonts/system-folder
+Patterns=
+
+X-KDE-AutoEmbed=true
+X-KDE-IsAlso=inode/directory
+