2 * KFontInst - KDE Font Installer
4 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
24 #include <config-workspace.h>
32 #include <sys/types.h>
33 #include <sys/errno.h>
37 #include <sys/resource.h>
40 #include <kio/ioslave_defaults.h>
41 #include <KDE/KMimeType>
42 #include <KDE/KMessageBox>
43 #include <QtCore/QDir>
44 #include <QtCore/QDataStream>
45 #include <QtCore/QTextStream>
46 #include <QtCore/QRegExp>
47 #include <QtGui/QFontDatabase>
48 #include <KDE/KComponentData>
50 #include <KDE/KTemporaryFile>
51 #include <KDE/SuProcess>
53 #include <KDE/KStandardDirs>
56 #include <KDE/KConfigGroup>
57 #include <kxftconfig.h>
58 #include <fontconfig/fontconfig.h>
59 #include "KfiConstants.h"
62 #if defined USE_POLICYKIT && USE_POLICYKIT==1
64 #include "PolicyKitAuthenticator.h"
65 #include <QtDBus/QtDBus>
66 #include <QtDBus/QDBusConnection>
74 // Enable the following so that all URLs are actually <family>, <style>, e.g.
75 // without #define: fonts:/arial.ttf
76 // with #define: fonts:/Arial, Regular.ttf
78 // Not enabled - as it messes things up a little with fonts/group files.
79 //#define KFI_KIO_ALL_URLS_HAVE_NAME
81 #define KFI_DBUG kDebug(7000) << '(' << time(NULL) << ')'
83 #define MAX_IPC_SIZE (1024*32)
84 #define DEFAULT_TIMEOUT 2 // Time between last mod and writing files...
85 #define FC_CACHE_CMD "fc-cache"
87 using namespace KDESu
;
89 static const int constMaxFcCheckTime
=10;
93 KDE_EXPORT
int kdemain(int argc
, char **argv
);
96 static KFI::CKioFonts
*slaveInstance
=NULL
;
98 void kioFontsExitHandler()
102 slaveInstance
->cleanup();
107 int kdemain(int argc
, char **argv
)
111 fprintf(stderr
, "Usage: kio_" KFI_KIO_FONTS_PROTOCOL
112 " protocol domain-socket1 domain-socket2\n");
116 KLocale::setMainCatalog(KFI_CATALOGUE
);
118 KComponentData
componentData("kio_" KFI_KIO_FONTS_PROTOCOL
);
119 KFI::CKioFonts
slave(argv
[2], argv
[3]);
121 atexit(kioFontsExitHandler
);
122 slave
.dispatchLoop();
130 static QString
urlString(const KUrl
&u
)
134 if(url
.hasUser() && KFI_KIO_FONTS_PROTOCOL
==url
.protocol() && KFI_SYS_USER
==url
.user())
135 url
.setUser(QString());
136 return url
.prettyUrl();
139 static bool addCreateFolderCmd(const QString
&folder
, QList
<CKioFonts::TCommand
> &cmd
)
141 if(!Misc::dExists(folder
))
143 cmd
.append(CKioFonts::TCommand(KFI::CMD_CREATE_DIR
, folder
));
150 inline bool isSysFolder(const QString
§
)
152 return i18n(KFI_KIO_FONTS_SYS
)==sect
|| KFI_KIO_FONTS_SYS
==sect
;
155 inline bool isUserFolder(const QString
§
)
157 return i18n(KFI_KIO_FONTS_USER
)==sect
|| KFI_KIO_FONTS_USER
==sect
;
160 inline bool isAllFolder(const QString
§
)
162 return i18n(KFI_KIO_FONTS_ALL
)==sect
|| KFI_KIO_FONTS_ALL
==sect
;
165 #ifdef KFI_KIO_ALL_URLS_HAVE_NAME
166 static const char *constExtensions
[]=
167 {".ttf", KFI_FONTS_PACKAGE
, ".otf", ".pfa", ".pfb", ".ttc",
168 ".pcf", ".pcf.gz", ".bdf", ".bdf.gz", NULL
};
170 static QString
removeKnownExtension(const KUrl
&url
)
172 QString
fname(url
.fileName());
175 for(int i
=0; constExtensions
[i
]; ++i
)
176 if(-1!=(pos
=fname
.lastIndexOf(QString::fromLatin1(constExtensions
[i
]), -1, Qt::CaseInsensitive
)))
177 return fname
.left(pos
);
181 #define removeMultipleExtension(A) removeKnownExtension(A)
182 static void addKnownExtension(QString
&url
, const CDisabledFonts::TFileList
&files
, const QString
&name
,
189 url
+=name
+QString::fromLatin1(KFI_FONTS_PACKAGE
);
193 QString
fileName(Misc::getFile(files
.first()));
196 for(int i
=0; constExtensions
[i
]; ++i
)
197 if(-1!=(pos
=fileName
.lastIndexOf(QString::fromLatin1(constExtensions
[i
]), -1,
198 Qt::CaseInsensitive
)))
202 url
+=name
+constExtensions
[i
];
209 static QString
removeMultipleExtension(const KUrl
&url
)
211 QString
fname(url
.fileName());
214 if(-1!=(pos
=fname
.lastIndexOf(QString::fromLatin1(KFI_FONTS_PACKAGE
))))
215 fname
=fname
.left(pos
);
221 static QString
modifyName(const QString
&fname
, bool toUpper
=false)
223 static const char constSymbols
[]={ '-', ' ', ':', ';', '/', '~', 0 };
225 QString
rv(toUpper
? fname
.toUpper() : fname
.toLower());
227 for(int s
=0; constSymbols
[s
]; ++s
)
228 rv
=rv
.replace(constSymbols
[s
], '_');
233 static bool checkFiles(const CDisabledFonts::TFileList
&files
)
235 CDisabledFonts::TFileList::ConstIterator
it(files
.begin()),
239 if(!Misc::fExists(*it
))
244 inline int getSize(KIO::UDSEntry
&entry
)
246 return entry
.numberValue(KIO::UDSEntry::UDS_SIZE
, 0);
249 static int getSize(const QByteArray
&file
)
251 KDE_struct_stat buff
;
253 if(-1!=KDE_lstat(file
, &buff
))
255 if (S_ISLNK(buff
.st_mode
))
258 int n
=readlink(file
, buffer2
, 1000);
262 if(-1==KDE_stat(file
, &buff
))
271 static int getSize(const CDisabledFonts::TFileList
&files
)
273 CDisabledFonts::TFileList::ConstIterator it
,
277 for(it
=files
.begin(); it
!=end
; ++it
)
278 size
+=getSize(QFile::encodeName(*it
));
284 // Return real filename
285 // if normal file, return file
286 // if link, return dest
287 static QString
getReal(const QString
&file
)
289 QByteArray
cPath(QFile::encodeName(file
));
290 KDE_struct_stat buff
;
292 if(-1!=KDE_lstat(cPath
, &buff
) && S_ISLNK(buff
.st_mode
))
295 int n
=readlink(cPath
, buffer2
, 1000);
301 if('.'==buffer2
[0]) // Relative link...
303 QString
linkDest(QString::fromLocal8Bit(buffer2
));
304 QDir
d(Misc::getDir(file
)+Misc::getDir(linkDest
));
306 return Misc::dirSyntax(d
.canonicalPath())+Misc::getFile(linkDest
);
309 return QString::fromLocal8Bit(buffer2
);
316 // Get the list of files associated with a list of entries...
317 // 1. get any associated afm or pfms
318 // 2. Resolve any symlinks
319 // 3. Remove duplicates (due to symlik and real being in list)
320 static void getFontFiles(const CDisabledFonts::TFileList
&entries
, CDisabledFonts::TFileList
&files
,
321 bool removeSymLinks
=true)
323 CDisabledFonts::TFileList::ConstIterator it
,
326 for(it
=entries
.begin(); it
!=end
; ++it
)
329 QString
file(removeSymLinks
? getReal(*it
) : (*it
).path
);
331 if(-1==files
.indexOf(file
) && Misc::fExists(file
))
332 files
.append(CDisabledFonts::TFile(file
, (*it
).face
, (*it
).foundry
));
334 Misc::getAssociatedFiles(*it
, assoc
);
338 QStringList::const_iterator fIt
,
339 fEnd
=assoc
.constEnd();
341 for(fIt
=assoc
.constBegin(); fIt
!=fEnd
; ++fIt
)
343 file
=removeSymLinks
? getReal(*fIt
) : *fIt
;
345 if(!files
.contains(file
) && Misc::fExists(file
))
346 files
.append(CDisabledFonts::TFile(file
));
352 static bool isScalable(const QString
&str
)
354 QByteArray
cFile(QFile::encodeName(str
));
356 return Misc::checkExt(cFile
, "ttf") || Misc::checkExt(cFile
, "otf") || Misc::checkExt(cFile
, "ttc") ||
357 Misc::checkExt(cFile
, "pfa") || Misc::checkExt(cFile
, "pfb");
360 static bool isATtc(const QByteArray
&file
)
363 // To speed things up, check the files extension 1st...
364 if(Misc::checkExt(file
, "ttc"))
368 // No '.ttc' exension match, so try querying with FreeType...
370 FcPattern
*pat
=FcFreeTypeQuery((const FcChar8
*)(QFile::encodeName(file
).constData()), 0, NULL
, &count
);
374 FcPatternDestroy(pat
);
375 return count
>1; // Only care if TTC has more than 1 face...
382 // ...src and dest are the *same* ttc file -> TTC copy
383 // ...or that src does not exist, and a new dest does -> TTC move
384 static bool isSameTtc(const QString
&src
, const QString
&dest
)
386 static const int constMaxTimeDiff
=20;
388 QByteArray
cDest(QFile::encodeName(dest
));
392 QByteArray
cSrc(QFile::encodeName(src
));
394 KDE_struct_stat srcStat
,
396 bool srcExists
=-1!=KDE_lstat(cSrc
, &srcStat
),
397 destExists
=-1!=KDE_lstat(cDest
, &destStat
);
399 // Check that file sizes are the same, and that the dest file is recent...
400 if(srcExists
&& destExists
)
402 if(srcStat
.st_size
==destStat
.st_size
&& abs(destStat
.st_atime
-time(NULL
))<constMaxTimeDiff
)
404 // Sizes match, so check md5 sums...
408 if(srcFile
.open(QIODevice::ReadOnly
) && destFile
.open(QIODevice::ReadOnly
))
413 return srcMd5
.update(srcFile
) && destMd5
.update(destFile
) &&
414 srcMd5
.verify(destMd5
.rawDigest());
418 else // In case of move, after the 1st, src won't exist, but dest should (and should be recent!)
419 return destExists
&& abs(destStat
.st_atime
-time(NULL
))<constMaxTimeDiff
;
432 static KUrl
getRedirect(const KUrl
&u
)
434 // Go from fonts:/System to fonts:/
437 QString
path(u
.path()),
438 sect(CKioFonts::getSect(path
));
441 path
.replace("//", "/");
442 redirect
.setPath(path
);
444 KFI_DBUG
<< "Redirect from " << u
.path() << " to " << redirect
.path();
448 static bool nonRootSys(const KUrl
&u
)
450 return !Misc::root() && isSysFolder(CKioFonts::getSect(u
.path()));
453 static bool writeAll(int fd
, const char *buf
, size_t len
)
457 ssize_t written
=write(fd
, buf
, len
);
458 if (written
<0 && EINTR
!=errno
)
466 static bool isAAfm(const QString
&fname
)
468 if(Misc::checkExt(QFile::encodeName(fname
), "afm")) // CPD? Is this a necessary check?
472 if(file
.open(QIODevice::ReadOnly
))
474 QTextStream
stream(&file
);
477 for(int lc
=0; lc
<30 && !stream
.atEnd(); ++lc
)
479 line
=stream
.readLine();
481 if(line
.contains("StartFontMetrics"))
495 static bool isAPfm(const QString
&fname
)
499 // I know extension checking is bad, but Ghostscript's pf2afm requires the pfm file to
500 // have the .pfm extension...
501 QByteArray
name(QFile::encodeName(fname
));
503 if(Misc::checkExt(name
, "pfm"))
506 // OK, the extension matches, so perform a little contents checking...
507 FILE *f
=fopen(name
.constData(), "r");
511 static const unsigned long constCopyrightLen
= 60;
512 static const unsigned long constTypeToExt
= 49;
513 static const unsigned long constExtToFname
= 20;
514 static const unsigned long constExtLen
= 30;
515 static const unsigned long constFontnameMin
= 75;
516 static const unsigned long constFontnameMax
= 512;
518 unsigned short version
=0,
521 unsigned long length
=0,
525 fseek(f
, 0, SEEK_END
);
527 fseek(f
, 0, SEEK_SET
);
529 if(2==fread(&version
, 1, 2, f
) && // Read version
530 4==fread(&length
, 1, 4, f
) && // length...
532 0==fseek(f
, constCopyrightLen
, SEEK_CUR
) && // Skip copyright notice...
533 2==fread(&type
, 1, 2, f
) &&
534 0==fseek(f
, constTypeToExt
, SEEK_CUR
) &&
535 2==fread(&extlen
, 1, 2, f
) &&
536 extlen
==constExtLen
&&
537 0==fseek(f
, constExtToFname
, SEEK_CUR
) &&
538 4==fread(&fontname
, 1, 4, f
) &&
539 fontname
>constFontnameMin
&& fontname
<constFontnameMax
)
548 // This function is *only* used for the generation of AFMs from PFMs.
549 static bool isAType1(const QString
&fname
)
551 static const char * constStr
="%!PS-AdobeFont-";
552 static const unsigned int constStrLen
=15;
553 static const unsigned int constPfbOffset
=6;
554 static const unsigned int constPfbLen
=constStrLen
+constPfbOffset
;
556 QByteArray
name(QFile::encodeName(fname
));
557 char buffer
[constPfbLen
];
560 if(Misc::checkExt(name
, "pfa"))
562 FILE *f
=fopen(name
.constData(), "r");
566 if(constStrLen
==fread(buffer
, 1, constStrLen
, f
))
567 match
=0==memcmp(buffer
, constStr
, constStrLen
);
571 else if(Misc::checkExt(name
, "pfb"))
573 static const char constPfbMarker
= static_cast<char>(0x80);
575 FILE *f
=fopen(name
.constData(), "r");
579 if(constPfbLen
==fread(buffer
, 1, constPfbLen
, f
))
580 match
=buffer
[0]==constPfbMarker
&& 0==memcmp(&buffer
[constPfbOffset
], constStr
,
589 static QString
getMatch(const QString
&file
, const char *extension
)
591 QString
f(Misc::changeExt(file
, extension
));
593 return Misc::fExists(f
) ? f
: QString();
600 Path(const QString
&p
=QString()) : orig(p
) { }
605 bool operator==(const Path
&p
) const { return p
.orig
==orig
; }
608 KfiFont(const QString
&n
=QString(), const QString
&p
=QString()) : name(n
)
609 { if(!p
.isEmpty()) paths
.append(Path(p
)); }
614 bool operator==(const KfiFont
&f
) const { return f
.name
==name
; }
617 struct KfiFontList
: public QList
<KfiFont
>
619 Iterator
locate(const KfiFont
&t
) { int i
= indexOf(t
); return (-1==i
? end() : (begin()+i
)); }
622 static void setName(const QString
&orig
, QString
&modified
, int pos
, bool hidden
)
624 modified
=orig
.mid(pos
);
625 modified
=modified
.replace('/', '_');
626 if(hidden
&& '.'!=modified
[0])
627 modified
='.'+modified
;
631 // This function returns a set of maping of from -> to for copy/move operations
632 static bool getFontList(const CDisabledFonts::TFileList
&files
, QMap
<QString
, QString
> &map
)
634 // First of all create a list of font files, and their paths
635 CDisabledFonts::TFileList::ConstIterator it
=files
.begin(),
641 QString
name(Misc::getFile(*it
)),
642 path(Misc::getDir(*it
));
643 KfiFontList::Iterator entry
=list
.locate(KfiFont(name
));
645 if(entry
!=list
.end())
647 if(!(*entry
).paths
.contains(path
))
648 (*entry
).paths
.append(path
);
651 list
.append(KfiFont(name
, path
));
654 KfiFontList::Iterator
fIt(list
.begin()),
657 for(; fIt
!=fEnd
; ++fIt
)
659 bool hidden
='.'==(*fIt
).name
[0];
660 QList
<KfiFont::Path
>::Iterator
pBegin((*fIt
).paths
.begin()),
662 pEnd((*fIt
).paths
.end());
665 if((*fIt
).paths
.count()>1)
667 // There's more than 1 file with the same name, but in a different location
668 // therefore, take the unique part of the path, and replace / with _
670 // /usr/X11R6/lib/X11/fonts/75dpi/times.pcf.gz
671 // /usr/X11R6/lib/X11/fonts/100dpi/times.pcf.gz
674 // 75dpi_times.pcf.gz
675 // 100dpi_times.pcf.gz
676 int beginLen((*pBegin
).orig
.length());
678 for(; pIt
!=pEnd
; ++pIt
)
680 unsigned int len
=qMin((*pIt
).orig
.length(), beginLen
);
683 for(unsigned int i
=0; i
<len
; ++i
)
684 if((*pIt
).orig
[i
]!=(*pBegin
).orig
[i
])
686 setName((*pIt
).orig
, (*pIt
).modified
, i
, hidden
);
687 if((*pBegin
).modified
.isEmpty())
688 setName((*pBegin
).orig
, (*pBegin
).modified
, i
, hidden
);
694 if(beginLen
>(*pIt
).orig
.length())
696 if((*pBegin
).modified
.isEmpty())
697 setName((*pBegin
).orig
, (*pBegin
).modified
, (*pIt
).orig
.length(), hidden
);
700 setName((*pIt
).orig
, (*pIt
).modified
, beginLen
, hidden
);
704 for(pIt
=(*fIt
).paths
.begin(); pIt
!=pEnd
; ++pIt
)
705 if(hidden
&& '.'==(*pIt
).modified
[0] && '.'==(*fIt
).name
[0])
706 map
[(*pIt
).orig
+(*fIt
).name
]=(*pIt
).modified
+(*fIt
).name
.mid(1);
708 map
[(*pIt
).orig
+(*fIt
).name
]=(*pIt
).modified
+(*fIt
).name
;
711 return list
.count() ? true : false;
714 inline QString
getDestFolder(const QString
&folder
, const QString
&file
)
716 return folder
+file
[0].toLower()+'/';
719 // Extract just the family from a font name
720 static QString
getFamily(const QString
&font
)
722 int commaPos
=font
.lastIndexOf(',');
723 return -1==commaPos
? font
: font
.left(commaPos
);
726 inline qulonglong
toBit(QFontDatabase::WritingSystem ws
)
728 return ((qulonglong
)1) << (int)ws
;
731 //.........the following section is inspired by qfontdatabase_x11.cpp / loadFontConfig
734 // Unfortunately FontConfig doesn't know about some languages. We have to test these through the
735 // charset. The lists below contain the systems where we need to do this.
738 QFontDatabase::WritingSystem ws
;
740 } sampleCharForWritingSystem
[] =
742 { QFontDatabase::Telugu
, 0xc15 },
743 { QFontDatabase::Kannada
, 0xc95 },
744 { QFontDatabase::Malayalam
, 0xd15 },
745 { QFontDatabase::Sinhala
, 0xd9a },
746 { QFontDatabase::Myanmar
, 0x1000 },
747 { QFontDatabase::Ogham
, 0x1681 },
748 { QFontDatabase::Runic
, 0x16a0 },
749 { QFontDatabase::Any
, 0x0 }
752 static qulonglong
getWritingSystems(FcPattern
*pat
)
756 FcLangSet
*langset(0);
757 const CDisabledFonts::LangWritingSystemMap
*langForWritingSystem(CDisabledFonts::languageForWritingSystemMap());
759 if (FcResultMatch
==FcPatternGetLangSet(pat
, FC_LANG
, 0, &langset
))
761 for (int i
= 0; langForWritingSystem
[i
].lang
; ++i
)
762 if (FcLangDifferentLang
!=FcLangSetHasLang(langset
, langForWritingSystem
[i
].lang
))
763 ws
|=toBit(langForWritingSystem
[i
].ws
);
766 ws
|=toBit(QFontDatabase::Other
);
770 if (FcResultMatch
== FcPatternGetCharSet(pat
, FC_CHARSET
, 0, &cs
))
772 // some languages are not supported by FontConfig, we rather check the
773 // charset to detect these
774 for (int i
= 0; QFontDatabase::Any
!=sampleCharForWritingSystem
[i
].ws
; ++i
)
775 if (FcCharSetHasChar(cs
, sampleCharForWritingSystem
[i
].ch
))
776 ws
|=toBit(sampleCharForWritingSystem
[i
].ws
);
782 static QString
obtainMimeType(const QString
&file
)
784 if(Misc::checkExt(file
, "ttf") || Misc::checkExt(file
, "ttc"))
785 return "application/x-font-ttf";
786 if(Misc::checkExt(file
, "otf"))
787 return "application/x-font-otf";
788 if(Misc::checkExt(file
, "pfa") || Misc::checkExt(file
, "pfb"))
789 return "application/x-font-type1";
790 if(Misc::checkExt(file
, "pcf.gz") || Misc::checkExt(file
, "pcf"))
791 return "application/x-font-pcf";
792 if(Misc::checkExt(file
, "bdf.gz") || Misc::checkExt(file
, "bdf"))
793 return "application/x-font-bdf";
795 // File extension check failed, use kmimetype to read contents...
796 return KMimeType::findByPath(file
)->name();
801 CKioFonts::CKioFonts(const QByteArray
&pool
, const QByteArray
&app
)
802 : KIO::SlaveBase(KFI_KIO_FONTS_PROTOCOL
, pool
, app
),
803 itsRoot(Misc::root()),
804 itsAddToSysFc(false),
805 itsLastFcCheckTime(0),
807 #if defined USE_POLICYKIT && USE_POLICYKIT==1
808 itsFontInstIface(0L),
819 #if !(defined USE_POLICYKIT && USE_POLICYKIT==1)
822 // Set core dump size to 0 because we will have
823 // root's password in memory.
825 rlim
.rlim_cur
=rlim
.rlim_max
=0;
826 setrlimit(RLIMIT_CORE
, &rlim
);
830 // Check with fontconfig for folder locations...
832 // 1. Get list of fontconfig dirs
833 // 2. For user, look for any starting with $HOME - but prefer $HOME/.fonts
834 // 3. For system, look for any starting with /usr/local/share - but prefer /usr/local/share/fonts
835 // 4. If either are not found, then add to local.conf / .fonts.conf
837 FcStrList
*list
=FcConfigGetFontDirs(FcInitLoadConfigAndFonts());
841 while((dir
=FcStrListNext(list
)))
842 dirs
.append(Misc::dirSyntax((const char *)dir
));
844 EFolder mainFolder
=FOLDER_SYS
;
848 QString
home(Misc::dirSyntax(QDir::homePath())),
849 defaultDir(Misc::dirSyntax(QDir::homePath()+"/.fonts/")),
850 dir(Misc::getFolder(defaultDir
, home
, dirs
));
852 if(dir
.isEmpty()) // Then no $HOME/ was found in fontconfigs dirs!
854 KXftConfig
xft(KXftConfig::Dirs
, false);
855 xft
.addDir(defaultDir
);
859 mainFolder
=FOLDER_USER
;
860 itsFolders
[FOLDER_USER
].setLocation(dir
, false);
863 QString
sysDefault(KFI_DEFAULT_SYS_FONTS_FOLDER
),
864 sysDir(Misc::getFolder(sysDefault
, "/usr/local/share/", dirs
));
870 KXftConfig
xft(KXftConfig::Dirs
, true);
871 xft
.addDir(sysDefault
);
880 itsFolders
[FOLDER_SYS
].setLocation(sysDir
, true);
884 if(!Misc::dExists(itsFolders
[mainFolder
].location
))
885 Misc::createDir(itsFolders
[mainFolder
].location
);
890 void CKioFonts::cleanup()
895 itsFolders
[FOLDER_USER
].disabled
->save();
897 #if defined USE_POLICYKIT && USE_POLICYKIT==1
898 delete itsFontInstIface
;
907 void CKioFonts::listDir(const KUrl
&url
)
909 KFI_DBUG
<< url
.path() << " query:" << url
.query();
911 clearFontList(); // Always refresh font list when listing...
912 if(updateFontList() && checkUrl(url
, true))
916 sections
=url
.path().split('/', QString::SkipEmptyParts
).count();
917 if(itsRoot
|| sections
!=0)
919 if(!itsRoot
&& isAllFolder(getSect(url
.path())))
921 totalSize(itsFolders
[FOLDER_SYS
].fontMap
.count()+itsFolders
[FOLDER_SYS
].disabled
->items().count()+
922 itsFolders
[FOLDER_USER
].fontMap
.count()+itsFolders
[FOLDER_USER
].disabled
->items().count());
923 listDir(FOLDER_SYS
, entry
);
924 listDir(FOLDER_USER
, entry
);
928 EFolder folder
=getFolder(url
);
930 totalSize(itsFolders
[folder
].fontMap
.count()+itsFolders
[folder
].disabled
->items().count());
931 listDir(folder
, entry
);
938 createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_USER
), itsFolders
[FOLDER_USER
].location
,
940 listEntry(entry
, false);
941 createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_SYS
), itsFolders
[FOLDER_SYS
].location
,
943 listEntry(entry
, false);
946 listEntry(size
? entry
: KIO::UDSEntry(), true);
950 KFI_DBUG
<< "finished!";
953 void CKioFonts::listDir(EFolder folder
, KIO::UDSEntry
&entry
)
955 if(itsFolders
[folder
].fontMap
.count())
957 TFontMap::Iterator it
=itsFolders
[folder
].fontMap
.begin(),
958 end
=itsFolders
[folder
].fontMap
.end();
960 for ( ; it
!= end
; ++it
)
963 if(createFontUDSEntry(entry
, it
.key(), it
.value().files
, it
.value().styleVal
,
964 it
.value().writingSystems
, FOLDER_SYS
==folder
))
965 listEntry(entry
, false);
969 CDisabledFonts::TFontList::Iterator
dIt(itsFolders
[folder
].disabled
->items().begin()),
970 dEnd(itsFolders
[folder
].disabled
->items().end());
972 for(; dIt
!=dEnd
; ++dIt
)
973 if(createFontUDSEntry(entry
, (*dIt
).getName(), (*dIt
).files
,
974 (*dIt
).styleInfo
, (*dIt
).writingSystems
, FOLDER_SYS
==folder
, true))
975 listEntry(entry
, false);
978 void CKioFonts::stat(const KUrl
&url
)
980 KFI_DBUG
<< url
.prettyUrl() << " query:" << url
.query();
985 if(checkUrl(url
, true, false))
987 QString
path(url
.path(KUrl::RemoveTrailingSlash
));
991 error(KIO::ERR_COULD_NOT_STAT
, urlString(url
));
995 QStringList
pathList(path
.split('/', QString::SkipEmptyParts
));
997 switch(pathList
.count())
1000 err
=!createFolderUDSEntry(entry
, i18n("Fonts"),
1001 itsFolders
[itsRoot
? FOLDER_SYS
: FOLDER_USER
].location
,
1006 err
=!createStatEntry(entry
, url
, FOLDER_SYS
);
1008 if(isUserFolder(pathList
[0]))
1009 err
=!createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_USER
),
1010 itsFolders
[FOLDER_USER
].location
, false);
1011 else if(isSysFolder(pathList
[0]))
1012 err
=!createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_SYS
),
1013 itsFolders
[FOLDER_SYS
].location
, true);
1014 else if(isAllFolder(pathList
[0]))
1015 err
=!createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_ALL
),
1016 itsFolders
[FOLDER_SYS
].location
, true);
1019 error(KIO::ERR_SLAVE_DEFINED
,
1020 i18n("Please specify \"%1\" or \"%2\".",
1021 i18n(KFI_KIO_FONTS_USER
), i18n(KFI_KIO_FONTS_SYS
)));
1026 err
=!createStatEntry(entry
, url
, getFolder(url
));
1029 else if(!itsRoot
&& 1==url
.path(KUrl::RemoveTrailingSlash
)
1030 .split('/', QString::SkipEmptyParts
).count())
1033 // If a user (non-root) copies a font to fonts:/, kio_fonts will redirect to fonts:/Personal
1034 // If the font already exists in fonts:/Personal, konqueror will then do a stat on
1035 // fonts:/<filename> to get its file size in the "overwrite" dialog.
1038 // But, the font will not exist in fonts:/<filename> - so we need to see if it exists
1039 // in fonts:/Personal/<filename> in order to get the correct size. Otherwise konqueror, etc,
1044 modUrl
.setPath(QChar('/')+i18n(KFI_KIO_FONTS_USER
)+QChar('/')+url
.fileName());
1045 err
=!createStatEntry(entry
, modUrl
, FOLDER_USER
);
1049 error(KIO::ERR_SLAVE_DEFINED
, i18n("Please specify \"%1\" or \"%2\".",
1050 i18n(KFI_KIO_FONTS_USER
), i18n(KFI_KIO_FONTS_SYS
)));
1056 error(KIO::ERR_DOES_NOT_EXIST
, urlString(url
));
1064 bool CKioFonts::createStatEntry(KIO::UDSEntry
&entry
, const KUrl
&url
, EFolder folder
)
1066 KFI_DBUG
<< url
.path();
1068 // First try to create stat entry without refreshing lists...
1069 bool ok
=createStatEntryReal(entry
, url
, folder
) && getSize(entry
)>0;
1071 // Hmm... well that failed, so refresh lists and try again!
1074 KFI_DBUG
<< "refresh font list";
1078 ok
=createStatEntryReal(entry
, url
, folder
) && getSize(entry
)>0;
1081 // Perhaps its not a valid font? Try to stat on location+name
1084 KFI_DBUG
<< "could not find";
1086 QStringList folders
;
1088 folders
.append(itsFolders
[folder
].location
);
1089 folders
.append(getDestFolder(itsFolders
[folder
].location
, url
.fileName()));
1091 QStringList::const_iterator
it(folders
.begin()),
1094 for(; it
!=end
; ++it
)
1095 for(int t
=0; t
<3 && !ok
; ++t
)
1097 CDisabledFonts::TFileList files
;
1098 QString fileName
=0==t
1100 : 1==t
? modifyName(url
.fileName()) // lowercase
1101 : modifyName(url
.fileName(), true); // uppercase
1103 files
.append(CDisabledFonts::TFile((*it
)+fileName
));
1105 ok
=createFontUDSEntry(entry
, i18n("Invalid Font"), files
,
1106 KFI_NO_STYLE_INFO
, 0, FOLDER_SYS
==folder
,
1107 Misc::isHidden(url
)) && getSize(entry
)>0;
1117 bool CKioFonts::createStatEntryReal(KIO::UDSEntry
&entry
, const KUrl
&url
, EFolder folder
)
1119 KFI_DBUG
<< url
.path();
1121 TFontMap::Iterator it
=getMap(url
);
1123 if(it
!=itsFolders
[folder
].fontMap
.end())
1125 KFI_DBUG
<< "its a normal font";
1126 return createFontUDSEntry(entry
, it
.key(), it
.value().files
, it
.value().styleVal
,
1127 it
.value().writingSystems
, FOLDER_SYS
==folder
);
1130 KFI_DBUG
<< "try looking in disabled fonts";
1132 QString name
=Misc::getFile(removeMultipleExtension(url
));
1133 CDisabledFonts::TFontList::Iterator dIt
=itsFolders
[folder
].disabled
->find(name
,
1134 Misc::getIntQueryVal(url
, KFI_KIO_FACE
, 0));
1136 if(dIt
!=itsFolders
[folder
].disabled
->items().end())
1138 KFI_DBUG
<< "its a disabled font";
1139 return createFontUDSEntry(entry
, (*dIt
).getName(), (*dIt
).files
, (*dIt
).styleInfo
,
1140 (*dIt
).writingSystems
, FOLDER_SYS
==folder
, true);
1146 void CKioFonts::get(const KUrl
&url
)
1148 KFI_DBUG
<< url
.path() << " query:" << url
.query();
1150 bool thumb
="1"==metaData("thumbnail");
1151 CDisabledFonts::TFileList srcFiles
;
1153 // Any error will be logged in getSourceFiles
1154 if(updateFontList() && checkUrl(url
) && getSourceFiles(url
, srcFiles
))
1157 // The thumbnail job always donwloads non-local files to /tmp/... and passes this file name to
1158 // the thumbnail creator. However, in the case of fonts which are split among many files, this
1159 // wont work. Therefore, when the thumbnail code asks for the font to donwload, just return
1160 // the family and style info for enabled fonts, and the filename for disabled fonts. This way
1161 // the font-thumbnail creator can read this and just ask Xft/fontconfig for the font data.
1165 QTextStream
stream(&array
, QIODevice::WriteOnly
);
1166 EFolder
folder(getFolder(url
));
1167 TFontMap::Iterator
it(getMap(url
)),
1168 end(itsFolders
[folder
].fontMap
.end());
1170 emit
mimeType("text/plain");
1175 // OK, its a disabled font - if possible try to return the location of the font file
1177 QString
name(Misc::getFile(removeMultipleExtension(url
)));
1178 CDisabledFonts::TFontList::Iterator
dIt(itsFolders
[folder
].disabled
1179 ->find(name
, Misc::getIntQueryVal(url
,
1181 dEnd(itsFolders
[folder
].disabled
->items().end());
1186 CDisabledFonts::TFileList::ConstIterator
fIt((*dIt
).files
.begin()),
1187 fEnd((*dIt
).files
.end());
1189 for(; fIt
!=fEnd
; ++fIt
)
1190 if(isScalable((*fIt
).path
))
1192 KFI_DBUG
<< "hasMetaData(\"thumbnail\"), so return FILE: "
1193 << (*fIt
).path
<< " / " << (*fIt
).face
;
1194 stream
<< KFI_PATH_KEY
<< (*fIt
).path
<< endl
1195 << KFI_FACE_KEY
<< (*fIt
).face
<< endl
;
1203 KFI_DBUG
<< "hasMetaData(\"thumbnail\"), so return Url: " << url
;
1204 stream
<< url
.prettyUrl();
1209 KFI_DBUG
<< "hasMetaData(\"thumbnail\"), so return DETAILS: " << it
.key() << " / "
1212 stream
<< KFI_NAME_KEY
<< it
.key() << endl
1213 << KFI_STYLE_KEY
<< (*it
).styleVal
<< endl
;
1215 if(1==(*it
).files
.count())
1217 CDisabledFonts::TFileList::ConstIterator
fIt((*it
).files
.begin());
1219 stream
<< KFI_PATH_KEY
<< (*fIt
).path
<< endl
1220 << KFI_FACE_KEY
<< (*fIt
).face
<< endl
;
1224 totalSize(array
.size());
1226 processedSize(array
.size());
1228 processedSize(array
.size());
1230 KFI_DBUG
<< "Finished thumbnail...";
1235 KDE_struct_stat buff
;
1236 bool multiple
=false;
1238 if(1==srcFiles
.count())
1239 realPath
=srcFiles
.first().path
;
1240 else // Font is made up of multiple files - so create .zip of them all!
1242 KTemporaryFile tmpFile
;
1246 KZip
zip(tmpFile
.fileName());
1248 tmpFile
.setAutoRemove(false);
1249 realPath
=tmpFile
.fileName();
1251 if(zip
.open(QIODevice::WriteOnly
))
1253 QMap
<QString
, QString
> map
;
1255 getFontList(srcFiles
, map
);
1257 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
1261 // Iterate through created list, and add to zip archive
1262 // ...unhide any hidden files
1263 for(; fIt
!=fEnd
; ++fIt
)
1264 zip
.addLocalFile(fIt
.key(), Misc::unhide(fIt
.value()));
1272 QByteArray
realPathC(QFile::encodeName(realPath
));
1273 KFI_DBUG
<< "real: " << realPathC
;
1275 if (-2==KDE_stat(realPathC
.constData(), &buff
))
1276 error(EACCES
==errno
? KIO::ERR_ACCESS_DENIED
: KIO::ERR_DOES_NOT_EXIST
, urlString(url
));
1277 else if (S_ISDIR(buff
.st_mode
))
1278 error(KIO::ERR_IS_DIRECTORY
, urlString(url
));
1279 else if (!S_ISREG(buff
.st_mode
))
1280 error(KIO::ERR_CANNOT_OPEN_FOR_READING
, urlString(url
));
1283 int fd
= KDE_open(realPathC
.constData(), O_RDONLY
);
1286 error(KIO::ERR_CANNOT_OPEN_FOR_READING
, urlString(url
));
1289 // Determine the mimetype of the file to be retrieved, and emit it.
1290 // This is mandatory in all slaves (for KRun/BrowserRun to work).
1291 emit
mimeType(KMimeType::findByPath(realPathC
, buff
.st_mode
)->name());
1293 totalSize(buff
.st_size
);
1295 KIO::filesize_t processed
=0;
1296 char buffer
[MAX_IPC_SIZE
];
1301 int n
=::read(fd
, buffer
, MAX_IPC_SIZE
);
1308 error(KIO::ERR_COULD_NOT_READ
, urlString(url
));
1311 ::unlink(realPathC
);
1317 array
=array
.fromRawData(buffer
, n
);
1322 processedSize(processed
);
1327 processedSize(buff
.st_size
);
1332 ::unlink(realPathC
);
1336 void CKioFonts::put(const KUrl
&u
, int mode
, KIO::JobFlags flags
)
1338 KFI_DBUG
<< u
.path() << " query:" << u
.query();
1340 if(Misc::isHidden(u
))
1342 error(KIO::ERR_SLAVE_DEFINED
, i18n("Cannot install %1\nHidden fonts cannot be "
1343 "installed.", urlString(u
)));
1347 // updateFontList(); // CPD: don't update font list upon a put - it's too slow. Just stat on
1349 //checkUrl(u) // CPD: Don't need to check Url, as the call to "confirmUrl()" below will sort out
1356 bool nrs(nonRootSys(url
)),
1357 clearList(!hasMetaData(KFI_KIO_NO_CLEAR
));
1358 EFolder
destFolder(getFolder(url
));
1359 QString
destFolderReal(getDestFolder(itsFolders
[destFolder
].location
, url
.fileName())),
1360 dest(destFolderReal
+modifyName(url
.fileName()));
1361 QByteArray
destC(QFile::encodeName(dest
));
1362 KDE_struct_stat buffDest
;
1363 bool destExists(KDE_lstat(destC
.constData(), &buffDest
)!= -1);
1365 if (destExists
&& !(flags
& KIO::Overwrite
) && !(flags
& KIO::Resume
))
1367 error(KIO::ERR_FILE_ALREADY_EXIST
, urlString(url
));
1371 if(nrs
&& !getRootPasswd(u
)) // Need to check can get root passwd before start download...
1373 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
1378 // As we don't get passed a mime-type the following needs to happen:
1380 // 1. Download to a temporary file
1381 // 2. Check with FreeType that the file is a font, or that it is
1382 // an AFM or PFM file
1383 KTemporaryFile tmpFile
;
1385 tmpFile
.setAutoRemove(true);
1387 if(putReal(tmpFile
))
1389 EFileType
type(checkFile(tmpFile
.fileName(), u
)); // error logged in checkFile
1391 if(FILE_UNKNOWN
==type
)
1394 int timeout(reconfigTimeout());
1396 if(nrs
) // Ask root to move the tmp font...
1398 QList
<TCommand
> cmd
;
1399 TCommand
c(KFI::CMD_MOVE_FILE
);
1401 addCreateFolderCmd(itsFolders
[FOLDER_SYS
].location
, cmd
);
1402 if(destFolderReal
!=itsFolders
[FOLDER_SYS
].location
)
1403 addCreateFolderCmd(destFolderReal
, cmd
);
1405 c
.args
.append(tmpFile
.fileName());
1406 c
.args
.append(dest
);
1412 // Get root to move this to fonts folder...
1413 if(doRootCmd(u
, cmd
, false)) // Already asked for passwd...
1415 tmpFile
.setAutoRemove(false);
1417 modified(timeout
, FOLDER_SYS
, clearList
, destFolderReal
);
1418 createAfm(dest
, true);
1422 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
1426 else // Move it to our font folder...
1428 tmpFile
.setAutoRemove(false);
1429 if(!Misc::dExists(destFolderReal
))
1430 Misc::createDir(destFolderReal
);
1431 if(0==::rename(QFile::encodeName(tmpFile
.fileName()).constData(), destC
.constData()))
1433 Misc::setFilePerms(destC
);
1435 modified(timeout
, FOLDER_USER
, clearList
, destFolderReal
);
1440 error(KIO::ERR_SLAVE_DEFINED
, i18n("Could not access \"%1\" folder.",
1441 i18n(KFI_KIO_FONTS_USER
)));
1450 QString
CKioFonts::getUserName(uid_t uid
)
1452 if (!itsUserCache
.contains(uid
))
1454 struct passwd
*user
= getpwuid(uid
);
1456 itsUserCache
.insert(uid
, QString::fromLatin1(user
->pw_name
));
1458 return QString::number(uid
);
1460 return itsUserCache
[uid
];
1463 QString
CKioFonts::getGroupName(gid_t gid
)
1465 if (!itsGroupCache
.contains(gid
))
1467 struct group
*grp
= getgrgid(gid
);
1469 itsGroupCache
.insert(gid
, QString::fromLatin1(grp
->gr_name
));
1471 return QString::number(gid
);
1473 return itsGroupCache
[gid
];
1476 bool CKioFonts::createFontUDSEntry(KIO::UDSEntry
&entry
, const QString
&name
,
1477 const CDisabledFonts::TFileList
&patterns
,
1478 quint32 styleVal
, qulonglong writingSystems
,
1479 bool sys
, bool hidden
)
1481 //KFI_DBUG << "name:" << name << " style:" << styleVal << " #"
1482 // << patterns.count();
1485 // First of all get list of real files - i.e. remove any duplicates due to symlinks
1486 CDisabledFonts::TFileList files
;
1488 getFontFiles(patterns
, files
);
1490 CDisabledFonts::TFileList::ConstIterator
it(files
.begin()),
1496 // Sort list of files - placing scalable ones first. This is because, when determening the
1497 // mimetype, the 1st valid file will be chosen. In case of mixed bitmap/scalable - prefer
1499 CDisabledFonts::TFileList sorted
;
1501 for(; it
!=end
; ++it
)
1503 sorted
.prepend(*it
);
1507 it
=files
.constBegin();
1508 end
=files
.constEnd();
1512 entry
.insert(KIO::UDSEntry::UDS_SIZE
, getSize(files
));
1514 for(; it
!=end
; ++it
)
1516 QByteArray
cPath(QFile::encodeName(*it
));
1517 KDE_struct_stat buff
;
1519 if(-1!=KDE_lstat(cPath
, &buff
))
1521 if(0==writingSystems
)
1522 writingSystems
=toBit(QFontDatabase::Other
);
1524 entry
.insert(KIO::UDSEntry::UDS_NAME
, name
);
1525 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, buff
.st_mode
&S_IFMT
);
1526 entry
.insert(KIO::UDSEntry::UDS_ACCESS
, buff
.st_mode
&07777);
1527 entry
.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME
, buff
.st_mtime
);
1528 entry
.insert(KIO::UDSEntry::UDS_USER
, getUserName(buff
.st_uid
));
1529 entry
.insert(KIO::UDSEntry::UDS_GROUP
, getGroupName(buff
.st_gid
));
1530 entry
.insert(KIO::UDSEntry::UDS_ACCESS_TIME
, buff
.st_atime
);
1531 entry
.insert(KIO::UDSEntry::UDS_MIME_TYPE
, obtainMimeType(*it
));
1532 entry
.insert(UDS_EXTRA_FC_STYLE
, styleVal
);
1533 entry
.insert(UDS_EXTRA_WRITING_SYSTEMS
, writingSystems
);
1536 entry
.insert(KIO::UDSEntry::UDS_HIDDEN
, 1);
1538 entry
.insert(UDS_EXTRA_FILE_NAME
, (*it
).path
);
1539 entry
.insert(UDS_EXTRA_FOUNDRY
, (*it
).foundry
);
1541 entry
.insert(UDS_EXTRA_FILE_LIST
, files
.toString(true));
1543 QString
url(KFI_KIO_FONTS_PROTOCOL
+QString::fromLatin1(":/"));
1547 url
+=sys
? i18n(KFI_KIO_FONTS_SYS
) : i18n(KFI_KIO_FONTS_USER
);
1548 url
+=QString::fromLatin1("/");
1551 #ifdef KFI_KIO_ALL_URLS_HAVE_NAME
1552 addKnownExtension(url
, files
, name
, hidden
);
1558 url
+=name
+QString::fromLatin1(KFI_FONTS_PACKAGE
);
1561 url
+=Misc::getFile(*it
);
1564 if(files
.count()==1 && (*it
).face
>0)
1568 kUrl
.setQuery("?"KFI_KIO_FACE
"="+QString::number((*it
).face
));
1569 entry
.insert(KIO::UDSEntry::UDS_URL
, kUrl
.url());
1572 entry
.insert(KIO::UDSEntry::UDS_URL
, url
);
1574 return true; // This file was OK, so use its values...
1580 bool CKioFonts::createFolderUDSEntry(KIO::UDSEntry
&entry
, const QString
&name
,
1581 const QString
&path
, bool sys
)
1583 KFI_DBUG
<< "name:" << name
<< " path:" << path
<< " sys?:" << sys
;
1585 KDE_struct_stat buff
;
1586 QByteArray
cPath(QFile::encodeName(path
));
1590 if(-1!=KDE_lstat(cPath
, &buff
))
1592 entry
.insert(KIO::UDSEntry::UDS_NAME
, name
);
1594 if (S_ISLNK(buff
.st_mode
))
1596 KFI_DBUG
<< path
<< " is a link";
1599 int n
=readlink(cPath
, buffer2
, 1000);
1603 if(-1==KDE_stat(cPath
, &buff
))
1605 // It is a link pointing to nowhere
1606 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, S_IFMT
- 1);
1607 entry
.insert(KIO::UDSEntry::UDS_ACCESS
, S_IRWXU
| S_IRWXG
| S_IRWXO
);
1608 entry
.insert(KIO::UDSEntry::UDS_SIZE
, 0);
1611 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
); // CPD Treat links as regular folder...
1614 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, buff
.st_mode
&S_IFMT
);
1615 entry
.insert(KIO::UDSEntry::UDS_ACCESS
, buff
.st_mode
&07777);
1616 entry
.insert(KIO::UDSEntry::UDS_SIZE
, buff
.st_size
);
1619 entry
.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME
, buff
.st_mtime
);
1620 entry
.insert(KIO::UDSEntry::UDS_USER
, getUserName(buff
.st_uid
));
1621 entry
.insert(KIO::UDSEntry::UDS_GROUP
, getGroupName(buff
.st_gid
));
1622 entry
.insert(KIO::UDSEntry::UDS_ACCESS_TIME
, buff
.st_atime
);
1623 entry
.insert(KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1("inode/directory"));
1626 else if (sys
&& !Misc::root()) // Default system fonts folder does not actually exist yet!
1628 KFI_DBUG
<< "Default system folder (" << path
1629 << ") does not yet exist, so create dummy entry";
1630 entry
.insert(KIO::UDSEntry::UDS_NAME
, name
);
1631 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
);
1632 entry
.insert(KIO::UDSEntry::UDS_ACCESS
, 0744);
1633 entry
.insert(KIO::UDSEntry::UDS_USER
, QString::fromLatin1("root"));
1634 entry
.insert(KIO::UDSEntry::UDS_GROUP
, QString::fromLatin1("root"));
1635 entry
.insert(KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1("inode/directory"));
1642 bool CKioFonts::putReal(KTemporaryFile
&dest
)
1646 error(EACCES
==errno
? KIO::ERR_WRITE_ACCESS_DENIED
: KIO::ERR_CANNOT_OPEN_FOR_WRITING
, dest
.fileName());
1651 // Loop until we got 0 (end of data)
1656 dataReq(); // Request for data
1657 result
= readData(buffer
);
1658 if(result
> 0 && !writeAll(dest
.handle(), buffer
.constData(), buffer
.size()))
1660 if(ENOSPC
==errno
) // disk full
1662 error(KIO::ERR_DISK_FULL
, dest
.fileName());
1663 result
= -2; // means: remove dest file
1667 error(KIO::ERR_COULD_NOT_WRITE
, dest
.fileName());
1683 void CKioFonts::copy(const KUrl
&src
, const KUrl
&d
, int mode
, KIO::JobFlags flags
)
1687 // Copying to fonts:/
1688 // Copying from fonts:/ and file:/
1690 KFI_DBUG
<< src
.prettyUrl() << " query:" << src
.query() << " - "
1691 << d
.prettyUrl() << " query:" << d
.query();
1693 if(Misc::isHidden(d
))
1695 error(KIO::ERR_SLAVE_DEFINED
,
1696 i18n("Cannot copy %1 to %2\nHidden/disabled fonts cannot be installed.",
1697 urlString(src
), urlString(d
)));
1701 bool fromFonts
=KFI_KIO_FONTS_PROTOCOL
==src
.protocol();
1703 // CPD: don't update font list upon a copy from file - it's too slow. Just stat on filename!
1704 if(!fromFonts
|| updateFontList() && checkUrl(src
) && checkAllowed(src
))
1706 //checkUrl(u) // CPD as per comment in ::put()
1708 CDisabledFonts::TFileList srcFiles
;
1709 int timeout(reconfigTimeout());
1711 if(getSourceFiles(src
, srcFiles
)) // Any error will be logged in getSourceFiles
1717 bool metrics(fromFonts
? false : Misc::isMetrics(src
.fileName())),
1718 clearList(!hasMetaData(KFI_KIO_NO_CLEAR
));
1719 EFolder
destFolder(getFolder(dest
));
1720 QMap
<QString
, QString
> map
;
1723 map
[src
.path()]=src
.fileName();
1725 // As above, if copying from file, then only stat on dest filename, but if from fonts to
1726 // fonts need to get the list of possible source files, etc.
1727 if(fromFonts
? confirmMultiple(src
, srcFiles
,
1728 FOLDER_SYS
==destFolder
? FOLDER_USER
: FOLDER_SYS
, OP_COPY
) &&
1729 getFontList(srcFiles
, map
) &&
1730 checkDestFiles(src
, map
, dest
, destFolder
, flags
)
1731 : checkDestFile(src
, dest
, destFolder
, flags
) )
1733 if(nonRootSys(dest
))
1735 QList
<TCommand
> cmd
;
1737 CDirList addedFolders
;
1738 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
1741 for(; fIt
!=fEnd
; ++fIt
)
1743 TCommand
c(KFI::CMD_COPY_FILE
);
1744 QString
destFolderReal(getDestFolder(itsFolders
[destFolder
].location
,
1745 Misc::getFile(*fIt
)));
1747 if(!addedFolders
.contains(itsFolders
[FOLDER_SYS
].location
) &&
1748 addCreateFolderCmd(itsFolders
[FOLDER_SYS
].location
, cmd
))
1749 addedFolders
.add(itsFolders
[FOLDER_SYS
].location
);
1751 if(!addedFolders
.contains(destFolderReal
) &&
1752 addCreateFolderCmd(destFolderReal
, cmd
))
1753 addedFolders
.add(destFolderReal
);
1755 c
.args
.append(fIt
.key());
1756 c
.args
.append(destFolderReal
+modifyName(fIt
.value()));
1759 int s
=getSize(QFile::encodeName(fIt
.key()));
1766 if(doRootCmd(d
, cmd
, true))
1769 modified(timeout
, destFolder
, clearList
, addedFolders
);
1770 processedSize(size
);
1771 if(src
.isLocalFile() && 1==srcFiles
.count())
1772 createAfm(itsFolders
[destFolder
].location
+modifyName(map
.begin().value()), true);
1776 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
1782 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
1784 QString destFolderReal
;
1786 for(; fIt
!=fEnd
; ++fIt
)
1788 destFolderReal
=getDestFolder(itsFolders
[destFolder
].location
,
1789 Misc::getFile(*fIt
));
1791 QByteArray
realSrc(QFile::encodeName(fIt
.key())),
1792 realDest(QFile::encodeName(destFolderReal
+
1793 modifyName(fIt
.value())));
1794 KDE_struct_stat buffSrc
;
1796 if(-1==KDE_stat(realSrc
.constData(), &buffSrc
))
1798 error(EACCES
==errno
? KIO::ERR_ACCESS_DENIED
: KIO::ERR_DOES_NOT_EXIST
,
1803 int srcFd
=KDE_open(realSrc
.constData(), O_RDONLY
);
1807 error(KIO::ERR_CANNOT_OPEN_FOR_READING
, urlString(src
));
1811 if(!Misc::dExists(destFolderReal
))
1812 Misc::createDir(destFolderReal
);
1814 // WABA: Make sure that we keep writing permissions ourselves,
1815 // otherwise we can be in for a surprise on NFS.
1816 int destFd
=KDE_open(realDest
.constData(), O_CREAT
| O_TRUNC
| O_WRONLY
,
1817 -1==mode
? 0666 : mode
| S_IWUSR
);
1822 ? KIO::ERR_WRITE_ACCESS_DENIED
1823 : KIO::ERR_CANNOT_OPEN_FOR_WRITING
, urlString(dest
));
1828 totalSize(buffSrc
.st_size
);
1830 KIO::filesize_t processed
= 0;
1831 char buffer
[MAX_IPC_SIZE
];
1836 int n
=::read(srcFd
, buffer
, MAX_IPC_SIZE
);
1840 error(KIO::ERR_COULD_NOT_READ
, urlString(src
));
1848 if(!writeAll(destFd
, buffer
, n
))
1852 if (ENOSPC
==errno
) // disk full
1854 error(KIO::ERR_DISK_FULL
, urlString(dest
));
1855 remove(realDest
.constData());
1858 error(KIO::ERR_COULD_NOT_WRITE
, urlString(dest
));
1863 processedSize(processed
);
1870 error(KIO::ERR_COULD_NOT_WRITE
, urlString(dest
));
1874 Misc::setFilePerms(realDest
);
1876 // copy access and modification time
1879 ut
.actime
= buffSrc
.st_atime
;
1880 ut
.modtime
= buffSrc
.st_mtime
;
1881 ::utime(realDest
.constData(), &ut
);
1883 processedSize(buffSrc
.st_size
);
1885 modified(timeout
, destFolder
, clearList
, destFolderReal
);
1888 if(src
.isLocalFile() && 1==srcFiles
.count())
1889 createAfm(destFolderReal
+modifyName(map
.begin().value()));
1898 void CKioFonts::rename(const KUrl
&src
, const KUrl
&d
, KIO::JobFlags flags
)
1900 KFI_DBUG
<< src
.prettyUrl() << " query:" << src
.query() << " - "
1901 << d
.prettyUrl() << " query:" << d
.query() << ", " << (flags
& KIO::Overwrite
);
1903 int timeout(reconfigTimeout());
1905 if(src
.directory()==d
.directory())
1907 if(!itsRoot
&& "/"==src
.directory())
1909 error(KIO::ERR_SLAVE_DEFINED
, i18n("You cannot rename font folders"));
1913 CDisabledFonts::TFontList::Iterator disabledIt
;
1914 TFontMap::Iterator enabledIt
;
1915 const CDisabledFonts::TFileList
*entries(getEntries(src
, enabledIt
, disabledIt
));
1919 KFI_DBUG
<< "No entries found, updating font list antry again...";
1921 entries
=getEntries(src
, enabledIt
, disabledIt
);
1926 QString
destFile(Misc::getFile(d
.path())),
1927 srcFile(Misc::getFile(src
.path())),
1928 destEn(destFile
.mid(1)),
1929 srcEn(srcFile
.mid(1));
1930 EFolder
folder(getFolder(d
));
1931 QString
srcName(Misc::getFile(removeMultipleExtension(src
)));
1932 bool clearList(!hasMetaData(KFI_KIO_NO_CLEAR
)),
1933 nrs(nonRootSys(src
)),
1934 enable(Misc::isHidden(srcFile
) && !Misc::isHidden(destFile
) && srcEn
==destFile
),
1935 disable(!Misc::isHidden(srcFile
) && Misc::isHidden(destFile
) &&
1938 if(enable
&& disabledIt
!=itsFolders
[folder
].disabled
->items().end())
1940 if(confirmMultiple(src
, (*disabledIt
).files
, folder
, OP_ENABLE
))
1943 CDisabledFonts::TFileList::ConstIterator
it((*disabledIt
).files
.begin()),
1944 end((*disabledIt
).files
.end());
1947 for(; it
!=end
; ++it
)
1948 folders
.add(Misc::getDir(*it
));
1952 TCommand
c(KFI::CMD_ENABLE_FONT
);
1954 c
.args
.append((*disabledIt
).family
);
1955 c
.args
.append((int)(*disabledIt
).styleInfo
);
1959 ok
=itsFolders
[folder
].disabled
->enable(disabledIt
);
1963 modified(timeout
, folder
, clearList
, folders
);
1968 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
1970 error(KIO::ERR_DOES_NOT_EXIST
, urlString(src
));
1974 else if (disable
&& disabledIt
==itsFolders
[folder
].disabled
->items().end())
1976 if(confirmMultiple(src
, (*enabledIt
).files
, folder
, OP_DISABLE
))
1979 QMap
<int, QString
> names
;
1980 CDisabledFonts::TFileList::ConstIterator
it((*enabledIt
).files
.begin()),
1981 end((*enabledIt
).files
.end());
1984 for(; it
!=end
; ++it
)
1985 folders
.add(Misc::getDir(*it
));
1988 // If there is only 1 file mapped to this fontname, see if this file maps
1989 // to multiple font names - as would be the case in a TTC file...
1990 if(1==(*enabledIt
).files
.count())
1991 names
=getFontIndexToNameEntries(folder
, (*((*enabledIt
).files
.begin())).path
);
1993 if(0==names
.count())
1994 names
[0]=enabledIt
.key(); // Multiple files -> cant use index :-(
1996 QMap
<int, QString
>::ConstIterator
nameIt(names
.begin()),
1997 nameEnd(names
.end());
1999 for(; nameIt
!=nameEnd
; ++nameIt
)
2002 TCommand
c(KFI::CMD_DISABLE_FONT
);
2004 c
.args
.append(getFamily(enabledIt
.key()));
2005 c
.args
.append((int)(*enabledIt
).styleVal
);
2006 c
.args
.append((*enabledIt
).writingSystems
);
2007 c
.args
.append((int)(nameIt
.key()));
2008 c
.args
.append((*enabledIt
).files
.count());
2009 for(it
=(*enabledIt
).files
.constBegin(); it
!=end
; ++it
)
2011 c
.args
.append((*it
).path
);
2012 c
.args
.append((*it
).foundry
);
2018 QString
fontStr(*nameIt
);
2019 int commaPos
=fontStr
.indexOf(',');
2020 CDisabledFonts::TFont
font(-1==commaPos
2022 : fontStr
.left(commaPos
),
2023 (*enabledIt
).styleVal
,
2024 (*enabledIt
).writingSystems
);
2026 font
.files
=(*enabledIt
).files
;
2027 if(1==font
.files
.count())
2028 (*(font
.files
.begin())).face
=nameIt
.key();
2029 ok
=itsFolders
[folder
].disabled
->disable(font
);
2034 modified(timeout
, folder
, clearList
, folders
);
2039 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2041 error(KIO::ERR_DOES_NOT_EXIST
, urlString(src
));
2044 error(KIO::ERR_SLAVE_DEFINED
, i18n("Internal error - could not find font."));
2047 else if(enable
|| disable
)
2048 error(KIO::ERR_SLAVE_DEFINED
, enable
2049 ? i18n("Could not enable %1\n"
2050 "An enabled font already exists, please delete the disabled one.",
2052 : i18n("Could not disable %1\n"
2053 "A disabled font already exists, please delete the enabled one.",
2056 error(KIO::ERR_SLAVE_DEFINED
, i18n("Sorry, fonts cannot be renamed."));
2060 error(KIO::ERR_DOES_NOT_EXIST
, urlString(src
));
2063 else if(itsRoot
) // Should never happen...
2065 error(KIO::ERR_UNSUPPORTED_ACTION
, unsupportedActionErrorString(mProtocol
, KIO::CMD_RENAME
));
2068 else if(Misc::isHidden(src
) || Misc::isHidden(d
))
2070 error(KIO::ERR_SLAVE_DEFINED
, i18n("Cannot move %1 to %2\nDisabled fonts cannot be moved.",
2071 urlString(src
), urlString(d
)));
2077 // Can't rename from/to file:/ -> therefore rename can only be from fonts:/System to
2078 // fonts:/Personal, or vice versa.
2079 CDisabledFonts::TFileList srcFiles
;
2081 if(getSourceFiles(src
, srcFiles
)) // Any error will be logged in getSourceFiles
2087 EFolder
destFolder(getFolder(dest
));
2088 QMap
<QString
, QString
> map
;
2090 if(confirmMultiple(src
, srcFiles
, FOLDER_SYS
==destFolder
? FOLDER_USER
: FOLDER_SYS
, OP_MOVE
) &&
2091 getFontList(srcFiles
, map
) && checkDestFiles(src
, map
, dest
, destFolder
, flags
))
2093 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
2095 bool askPasswd
=true,
2096 toSys
=FOLDER_SYS
==destFolder
;
2098 for(; fIt
!=fEnd
; ++fIt
)
2100 QString
destFolderReal(getDestFolder(itsFolders
[destFolder
].location
, fIt
.value()));
2101 QList
<TCommand
> cmd
;
2102 TCommand
c(KFI::CMD_MOVE_FILE
);
2106 addCreateFolderCmd(itsFolders
[FOLDER_SYS
].location
, cmd
);
2107 if(destFolderReal
!=itsFolders
[FOLDER_SYS
].location
)
2108 addCreateFolderCmd(destFolderReal
, cmd
);
2111 c
.args
.append(fIt
.key());
2112 c
.args
.append(destFolderReal
+fIt
.value());
2113 c
.args
.append((int)(toSys
? 0 : getuid()));
2114 c
.args
.append((int)(toSys
? 0 : getgid()));
2120 if(FOLDER_SYS
==destFolder
)
2122 sysDir
=destFolderReal
;
2123 userDir
=Misc::getDir(fIt
.key());
2127 userDir
=destFolderReal
;
2128 sysDir
=Misc::getDir(fIt
.key());
2131 if(doRootCmd(toSys
? d
: src
, cmd
, askPasswd
))
2133 modified(timeout
, FOLDER_SYS
, true, sysDir
);
2134 modified(timeout
, FOLDER_USER
, true, userDir
);
2135 askPasswd
=false; // Don't keep on asking for password...
2139 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2149 void CKioFonts::del(const KUrl
&url
, bool)
2151 KFI_DBUG
<< url
.path() << " query:" << url
.query();
2153 const CDisabledFonts::TFileList
*entries
;
2154 CDisabledFonts::TFontList::Iterator disabledIt
;
2155 TFontMap::Iterator enabledIt
;
2157 if(checkUrl(url
) && checkAllowed(url
) &&
2158 (( (entries
=getEntries(url
, enabledIt
, disabledIt
)) && entries
->count() && checkFiles(*entries
)) ||
2159 ( updateFontList() && (entries
=getEntries(url
, enabledIt
, disabledIt
)) && entries
->count() &&
2160 checkFiles(*entries
))) && confirmMultiple(url
, entries
, getFolder(url
), OP_DELETE
))
2162 CDisabledFonts::TFileList::ConstIterator it
,
2163 end(entries
->end());
2164 CDirList modifiedDirs
;
2165 bool clearList(!hasMetaData(KFI_KIO_NO_CLEAR
));
2166 int timeout(reconfigTimeout());
2170 if(disabledIt
!=itsFolders
[FOLDER_SYS
].disabled
->items().end())
2172 TCommand
c(KFI::CMD_DELETE_DISABLED_FONT
);
2174 c
.args
.append((*disabledIt
).family
);
2175 c
.args
.append((int)(*disabledIt
).styleInfo
);
2177 if(doRootCmd(url
, c
))
2178 itsFolders
[FOLDER_SYS
].disabled
->refresh();
2181 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2187 QList
<TCommand
> cmd
;
2189 for(it
=entries
->begin(); it
!=end
; ++it
)
2191 modifiedDirs
.add(Misc::getDir(*it
));
2192 cmd
.append(TCommand(KFI::CMD_DELETE_FILE
, (*it
).path
));
2196 Misc::getAssociatedFiles(*it
, files
);
2200 QStringList::const_iterator fIt
,
2201 fEnd
=files
.constEnd();
2203 for(fIt
=files
.constBegin(); fIt
!=fEnd
; ++fIt
)
2204 cmd
.append(TCommand(KFI::CMD_DELETE_FILE
, *fIt
));
2208 if(doRootCmd(url
, cmd
))
2209 modified(timeout
, FOLDER_SYS
, clearList
, modifiedDirs
);
2212 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2219 for(it
=entries
->begin(); it
!=end
; ++it
)
2221 if (0!=unlink(QFile::encodeName(*it
).constData()))
2222 error(EACCES
==errno
|| EPERM
==errno
2223 ? KIO::ERR_ACCESS_DENIED
2225 ? KIO::ERR_IS_DIRECTORY
2226 : KIO::ERR_CANNOT_DELETE
,
2230 modifiedDirs
.add(Misc::getDir(*it
));
2234 Misc::getAssociatedFiles(*it
, files
);
2238 QStringList::const_iterator fIt
,
2239 fEnd
=files
.constEnd();
2241 for(fIt
=files
.constBegin(); fIt
!=fEnd
; ++fIt
)
2242 unlink(QFile::encodeName(*fIt
).constData());
2247 if(disabledIt
!=itsFolders
[itsRoot
? FOLDER_SYS
: FOLDER_USER
].disabled
->items().end())
2249 itsFolders
[itsRoot
? FOLDER_SYS
: FOLDER_USER
].disabled
->remove(disabledIt
);
2250 itsFolders
[itsRoot
? FOLDER_SYS
: FOLDER_USER
].disabled
->refresh();
2253 modified(timeout
, itsRoot
? FOLDER_SYS
: FOLDER_USER
, clearList
, modifiedDirs
);
2257 else if(isATtc(QFile::encodeName(url
.fileName())))
2260 error(KIO::ERR_SLAVE_DEFINED
, i18n("Could not access \"%1\".", urlString(url
)));
2263 void CKioFonts::modified(int timeout
, EFolder folder
, bool clearList
, const CDirList
&dirs
)
2265 KFI_DBUG
<< "timout:" << timeout
<< " folder:" << (int)folder
<< " clearList:" << clearList
;
2269 CDirList::ConstIterator
it(dirs
.begin()),
2272 for(; it
!=end
; ++it
)
2273 itsFolders
[folder
].modified
.add(*it
);
2276 itsFolders
[folder
].modified
.add(itsFolders
[folder
].location
);
2277 setTimeoutSpecialCommand(timeout
? timeout
: -1);
2280 clearFontList(); // List of fonts has changed.../
2283 void CKioFonts::special(const QByteArray
&a
)
2289 QDataStream
stream(a
);
2296 case SPECIAL_RESCAN
:
2301 case SPECIAL_CONFIGURE
:
2310 itsFolders
[FOLDER_SYS
].disabled
->reload();
2311 if(0==itsFolders
[FOLDER_SYS
].modified
.count())
2312 configure(FOLDER_SYS
);
2321 if(url
.isEmpty() || !url
.isValid())
2324 QString
sect(getSect(url
.path()));
2326 if(isSysFolder(sect
))
2328 itsFolders
[FOLDER_SYS
].disabled
->reload();
2329 if(0==itsFolders
[FOLDER_SYS
].modified
.count())
2330 configure(FOLDER_SYS
);
2332 else if(isUserFolder(sect
))
2334 itsFolders
[FOLDER_USER
].disabled
->reload();
2335 if(0==itsFolders
[FOLDER_USER
].modified
.count())
2336 configure(FOLDER_USER
);
2340 if(itsFolders
[FOLDER_USER
].disabled
->modified())
2341 itsFolders
[FOLDER_USER
].disabled
->reload();
2349 error(KIO::ERR_UNSUPPORTED_ACTION
, QString::number(cmd
));
2356 bool CKioFonts::configure(EFolder folder
)
2358 bool refreshX(false);
2360 if(!itsRoot
&& FOLDER_SYS
==folder
)
2362 QList
<TCommand
> cmd
;
2366 itsAddToSysFc
=false;
2367 cmd
.append(TCommand(KFI::CMD_ADD_DIR_TO_FONTCONFIG
, itsFolders
[FOLDER_SYS
].location
));
2370 if(itsFolders
[FOLDER_SYS
].modified
.count())
2372 CDirList::ConstIterator
it(itsFolders
[FOLDER_SYS
].modified
.begin()),
2373 end(itsFolders
[FOLDER_SYS
].modified
.end());
2375 for(; it
!=end
; ++it
)
2376 if(Misc::fExists((*it
)+"fonts.dir"))
2378 cmd
.append(TCommand(KFI::CMD_CFG_DIR_FOR_X
, *it
));
2383 cmd
.append(TCommand(KFI::CMD_FC_CACHE
));
2384 doRootCmd(KUrl(), cmd
, false);
2388 Misc::doCmd(FC_CACHE_CMD
);
2389 KFI_DBUG
<< "RUN: " << FC_CACHE_CMD
;
2391 itsFolders
[folder
].disabled
->save();
2393 CDirList::ConstIterator
it(itsFolders
[folder
].modified
.begin()),
2394 end(itsFolders
[folder
].modified
.end());
2396 for(; it
!=end
; ++it
)
2397 if(Misc::fExists((*it
)+"fonts.dir"))
2399 Misc::configureForX11(*it
);
2406 void CKioFonts::doModified()
2409 bool refreshX(false),
2412 infoMessage(i18n("Configuring installed fonts..."));
2413 setTimeoutSpecialCommand(-1); // Cancel timer
2415 if(itsFolders
[FOLDER_SYS
].modified
.count())
2417 refreshX
=configure(FOLDER_SYS
);
2418 itsFolders
[FOLDER_SYS
].modified
.clear();
2422 if(!itsRoot
&& itsFolders
[FOLDER_USER
].modified
.count())
2424 refreshX
=configure(FOLDER_USER
);
2425 itsFolders
[FOLDER_USER
].modified
.clear();
2432 Misc::doCmd("xset", "fp", "rehash");
2433 infoMessage(QString());
2434 KFI_DBUG
<< "finished";
2437 bool CKioFonts::getRootPasswd(const KUrl
&url
, bool askPasswd
)
2441 #if defined USE_POLICYKIT && USE_POLICYKIT==1
2442 if(url
.hasUser() && !url
.pass().isEmpty() && KFI_SYS_USER
==url
.user())
2445 int v
=url
.pass().toInt(&ok
);
2451 KFI_DBUG
<< "askPasswd:" << askPasswd
<< " itsPid:" << itsPid
;
2453 // If we have a pid, check that its still alive!
2454 if(0!=itsPid
&& 0!=kill(itsPid
, 0))
2460 uint winId
=hasMetaData("window-id") ? metaData("window-id").toInt() : 0,
2461 pid
=0==itsPid
? getpid() : itsPid
;
2463 KFI_DBUG
<< "ObtainAuthorization pid:" << pid
<< " winId:" << winId
;
2465 if(PolicyKitAuthenticator::instance()->authenticate(KFI_IFACE
, winId
, pid
, false))
2467 KFI_DBUG
<< "Authorization obtained";
2472 // If pids do not match, its possible (probable!) that the calling app has already
2473 // authenticated, if so ObtainAuthorization returns false on sucessive attempts!
2474 return itsPid
!=getpid();
2476 if(url
.hasUser() && !url
.pass().isEmpty() && KFI_SYS_USER
==url
.user())
2478 itsPasswd
=url
.pass();
2479 return !itsPasswd
.isEmpty();
2483 return !itsPasswd
.isEmpty();
2485 KIO::AuthInfo authInfo
;
2486 SuProcess
proc(KFI_SYS_USER
);
2491 authInfo
.url
=KUrl(KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
"/");
2492 authInfo
.keepPassword
=false;
2493 authInfo
.caption
=i18n("Authorization Required");
2494 authInfo
.username
=i18n(KFI_AUTHINF_USER
);
2496 if(proc
.useUsersOwnPassword())
2497 authInfo
.prompt
=i18n("The requested action requires administrator privileges.\n"
2498 "If you have these privileges then please enter your password.");
2500 authInfo
.prompt
=i18n("The requested action requires administrator privileges.\n"
2501 "Please enter the system administrator's password.");
2503 if(!checkCachedAuthentication(authInfo
) && !askPasswd
)
2504 authInfo
.password
=itsPasswd
;
2508 while(!error
&& 0!=proc
.checkInstall(authInfo
.password
.toLocal8Bit()))
2510 KFI_DBUG
<< "ATTEMPT : " << attempts
;
2512 errorMsg
=i18n("Incorrect password.\n");
2513 if(attempts
>2 || !openPasswordDialog(authInfo
, errorMsg
))
2516 if(!error
&& authInfo
.keepPassword
)
2517 cacheAuthentication(authInfo
);
2520 error
=proc
.checkInstall(authInfo
.password
.toLocal8Bit()) ? true : false;
2522 itsPasswd
= error
? QString() : authInfo
.password
;
2523 return !itsPasswd
.isEmpty();
2527 #if !(defined USE_POLICYKIT && USE_POLICYKIT==1)
2528 void CKioFonts::quitHelper()
2530 if(itsServer
.isOpen() && itsSuProc
&& itsSocket
&& itsSuProc
->isRunning())
2533 if(itsSocket
->write(QVariant((int)KFI::CMD_QUIT
)))
2536 if(itsSocket
->read(res
, 10) && res
)
2538 itsSuProc
->terminate();
2539 itsSuProc
->wait(100);
2546 bool CKioFonts::doRootCmd(const KUrl
&url
, QList
<TCommand
> &cmd
, bool askPasswd
)
2550 if(cmd
.count() && getRootPasswd(url
, askPasswd
))
2552 #if defined USE_POLICYKIT && USE_POLICYKIT==1
2553 QList
<TCommand
>::ConstIterator
it(cmd
.begin()),
2557 if(!itsFontInstIface
)
2558 itsFontInstIface
=new org::kde::fontinst(KFI_IFACE
, "/FontInst", QDBusConnection::systemBus());
2560 for(; it
!=end
&& !error
; ++it
)
2564 KFI_DBUG
<< "do cmd " << (int)((*it
).cmd
);
2568 case CMD_ENABLE_FONT
:
2569 if(2==(*it
).args
.count())
2570 response
=itsFontInstIface
->enableFont(itsPid
, (*it
).args
[0].toString(),
2571 (*it
).args
[1].toUInt()).value();
2575 case CMD_DISABLE_FONT
:
2576 if((*it
).args
.count()>=7 && (*it
).args
.count()%2)
2578 QStringList fileData
;
2579 QList
<QVariant
>::ConstIterator
fit((*it
).args
.begin()),
2580 fend((*it
).args
.end());
2582 for(int i
=0; i
<5; ++i
)
2585 for(; fit
!=fend
; ++fit
)
2586 fileData
.append((*fit
).toString());
2588 response
=itsFontInstIface
->disableFont(itsPid
, (*it
).args
[0].toString(),
2589 (*it
).args
[1].toUInt(), (*it
).args
[2].toULongLong(),
2590 (*it
).args
[3].toUInt(), fileData
).value();
2595 case CMD_DELETE_DISABLED_FONT
:
2596 if(2==(*it
).args
.count())
2597 response
=itsFontInstIface
->deleteDisabledFont(itsPid
, (*it
).args
[0].toString(),
2598 (*it
).args
[1].toUInt()).value();
2602 case CMD_RELOAD_DISABLED_LIST
:
2603 if(0==(*it
).args
.count())
2604 response
=itsFontInstIface
->reloadDisabledList(itsPid
);
2609 if(2==(*it
).args
.count())
2610 response
=itsFontInstIface
->copyFont(itsPid
, (*it
).args
[0].toString(),
2611 (*it
).args
[1].toString()).value();
2616 if(4==(*it
).args
.count())
2617 response
=itsFontInstIface
->moveFont(itsPid
, (*it
).args
[0].toString(),
2618 (*it
).args
[1].toString(), (*it
).args
[2].toUInt(),
2619 (*it
).args
[3].toUInt()).value();
2623 case CMD_DELETE_FILE
:
2624 if(1==(*it
).args
.count())
2625 response
=itsFontInstIface
->deleteFont(itsPid
, (*it
).args
[0].toString()).value();
2629 case CMD_CREATE_DIR
:
2630 if(1==(*it
).args
.count())
2632 KFI_DBUG
<< "Create dir " << (*it
).args
[0].toString();
2633 response
=itsFontInstIface
->createDir(itsPid
, (*it
).args
[0].toString()).value();
2638 case CMD_CREATE_AFM
:
2639 if(1==(*it
).args
.count())
2640 response
=itsFontInstIface
->createAfm(itsPid
, (*it
).args
[0].toString()).value();
2645 if(0==(*it
).args
.count())
2646 response
=doLongRootCmd("fcCache");
2650 case CMD_ADD_DIR_TO_FONTCONFIG
:
2651 if(1==(*it
).args
.count())
2652 response
=itsFontInstIface
->addToFc(itsPid
, (*it
).args
[0].toString()).value();
2656 case CMD_CFG_DIR_FOR_X
:
2657 if(1==(*it
).args
.count())
2658 response
=doLongRootCmd("configureX", (*it
).args
[0].toString());
2669 if(FontInst::CommandOk
!=response
)
2672 KFI_DBUG
<< "Failed";
2675 KFI_DBUG
<< "Success";
2678 KFI_DBUG
<< "Parameter error";
2683 if(!itsServer
.isOpen())
2685 KFI_DBUG
<< "Open server socket";
2686 // Open socket for communication with helper app...
2690 if(itsServer
.isOpen())
2692 if(itsSuProc
&& !itsSuProc
->isRunning())
2694 KFI_DBUG
<< "Delete client socket";
2703 // Start helper app...
2704 KFI_DBUG
<< "Start helper...";
2705 itsSuProc
=new CSuProc(itsServer
.name(), itsPasswd
);
2711 // Wait for helper app to connect...
2712 KFI_DBUG
<< "Wait for client...";
2713 itsSocket
=itsServer
.waitForClient();
2718 // Write commands to helper, and wait for replies...
2719 QList
<TCommand
>::ConstIterator
it(cmd
.begin()),
2721 bool commsError(false);
2723 for(; it
!=end
&& !commsError
; ++it
)
2725 KFI_DBUG
<< "Send command #" << (*it
).cmd
;
2727 if(itsSocket
->write(QVariant((int)(*it
).cmd
)))
2729 QList
<QVariant
>::ConstIterator
argIt((*it
).args
.begin()),
2730 argEnd((*it
).args
.end());
2732 for(; argIt
!=argEnd
&& !commsError
; ++argIt
)
2733 if(!itsSocket
->write(*argIt
))
2735 KFI_DBUG
<< "Failed to write arg";
2739 if(!commsError
) // Wait for response!
2743 if(itsSocket
->read(res
, CMD_FC_CACHE
==(*it
).cmd
||
2744 CMD_CFG_DIR_FOR_X
==(*it
).cmd
2745 ? 600 // fc-cache can take a *long* time...
2749 CMD_ADD_DIR_TO_FONTCONFIG
!=(*it
).cmd
&&
2750 CMD_CFG_DIR_FOR_X
!=(*it
).cmd
)
2752 KFI_DBUG
<< "Command failed :-(";
2758 KFI_DBUG
<< "Failed to read response";
2765 KFI_DBUG
<< "Failed to write command id";
2776 KFI_DBUG
<< "No socket connection :-(";
2784 #if defined USE_POLICYKIT && USE_POLICYKIT==1
2785 int CKioFonts::doLongRootCmd(const QString
&method
, const QString
¶m
)
2787 static const int constDBusTimeout
=20*60*1000; // 20mins
2789 KFI_DBUG
<< method
<< param
;
2791 QList
<QVariant
> args
;
2792 QDBusMessage message
=QDBusMessage::createMethodCall(itsFontInstIface
->service(),
2793 itsFontInstIface
->path(),
2794 itsFontInstIface
->interface(),
2797 args
<< qVariantFromValue(itsPid
);
2799 if(!param
.isEmpty())
2800 args
<< qVariantFromValue(param
);
2802 message
.setArguments(args
);
2804 QDBusMessage reply
=itsFontInstIface
->connection().call(message
, QDBus::Block
, constDBusTimeout
);
2806 KFI_DBUG
<< "Got reply";
2808 if (QDBusMessage::ReplyMessage
==reply
.type())
2810 QDBusReply
<int> r(reply
);
2816 return FontInst::CommandFailed
;
2820 bool CKioFonts::doRootCmd(const KUrl
&url
, const TCommand
&cmd
, bool askPasswd
)
2822 QList
<TCommand
> cmds
;
2825 return doRootCmd(url
, cmds
, askPasswd
);
2828 void CKioFonts::correctUrl(KUrl
&url
)
2830 KFI_DBUG
<< url
.path();
2833 QString
sect(getSect(url
.path()));
2835 if(!isSysFolder(sect
) && !isUserFolder(sect
))
2837 url
.setPath(QChar('/')+i18n(KFI_KIO_FONTS_USER
)+QChar('/')+url
.fileName());
2838 KFI_DBUG
<< "Changed URL to:" << url
.path();
2843 void CKioFonts::clearFontList()
2848 FcFontSetDestroy(itsFontList
);
2851 itsFolders
[FOLDER_SYS
].fontMap
.clear();
2853 itsFolders
[FOLDER_USER
].fontMap
.clear();
2856 bool CKioFonts::updateFontList()
2860 // For some reason just the "!FcConfigUptoDate(0)" check does not always work :-(
2861 if(0!=itsLastFcCheckTime
&&
2862 (!itsFontList
|| !FcConfigUptoDate(0) ||
2863 (abs(time(NULL
)-itsLastFcCheckTime
)>constMaxFcCheckTime
)))
2865 KFI_DBUG
<< "itsFontList:" << (intptr_t)itsFontList
2866 << " FcConfigUptoDate:" << (int)FcConfigUptoDate(0)
2867 << " time diff:" << abs(time(NULL
)-itsLastFcCheckTime
)
2868 << " max:" << constMaxFcCheckTime
;
2869 FcInitReinitialize();
2875 #if defined USE_POLICYKIT && USE_POLICYKIT==1
2878 if(itsServer
.isOpen() && itsSuProc
&& itsSocket
)
2880 doRootCmd(KUrl(), TCommand(KFI::CMD_RELOAD_DISABLED_LIST
), false);
2881 itsFolders
[FOLDER_USER
].disabled
->refresh();
2883 itsFolders
[FOLDER_SYS
].disabled
->refresh();
2887 KFI_DBUG
<< "update list of fonts";
2889 itsLastFcCheckTime
=time(NULL
);
2891 FcPattern
*pat
= FcPatternCreate();
2892 FcObjectSet
*os
= FcObjectSetBuild(FC_FILE
, FC_FAMILY
,
2893 #ifdef KFI_USE_TRANSLATED_FAMILY_NAME
2896 FC_WEIGHT
, FC_LANG
, FC_CHARSET
,
2898 #ifndef KFI_FC_NO_WIDTHS
2901 FC_SLANT
, FC_INDEX
, FC_FOUNDRY
, (void*)0);
2903 itsFontList
=FcFontList(0, pat
, os
);
2905 FcPatternDestroy(pat
);
2906 FcObjectSetDestroy(os
);
2911 // defoma (DEbian FOnt MAnanager) installs sym links into /var/lib/defoma/fontconfig.d, but also
2912 // places this folder into fontconfigs search path. Leading to duplicate font files. Therefore, just
2913 // ignore defoma's sym links...
2914 // -> Can't just ignore these, as if a font is disabled fontconfig will still list it, as it sees the symlink
2915 //static const char * constDefomaLocation="/var/lib/defoma/fontconfig.d";
2917 QString
home(Misc::dirSyntax(QDir::homePath()));
2919 for (int i
= 0; i
< itsFontList
->nfont
; i
++)
2921 EFolder folder
=FOLDER_SYS
;
2922 QString
fileName(Misc::fileSyntax(FC::getFcString(itsFontList
->fonts
[i
], FC_FILE
)));
2924 if(!fileName
.isEmpty()) // && 0!=fileName.indexOf(constDefomaLocation))
2927 foundry(FC::getFcString(itsFontList
->fonts
[i
], FC_FOUNDRY
));
2931 if(!itsRoot
&& 0==fileName
.indexOf(home
))
2934 FC::getDetails(itsFontList
->fonts
[i
], name
, styleVal
, index
);
2936 TFontDetails
&details
=itsFolders
[folder
].fontMap
[name
];
2939 details
.styleVal
=styleVal
;
2940 details
.writingSystems
|=getWritingSystems(itsFontList
->fonts
[i
]);
2942 if(details
.files
.count()) // Check for duplicates...
2944 CDisabledFonts::TFileList::Iterator it
,
2945 end
=details
.files
.end();
2947 for(it
=details
.files
.begin(); use
&& it
!=end
; ++it
)
2952 details
.files
.append(CDisabledFonts::TFile(fileName
, index
, foundry
));
2957 KFI_DBUG
<< "updated list of fonts";
2960 if(NULL
==itsFontList
)
2962 error(KIO::ERR_SLAVE_DEFINED
, i18n("Internal fontconfig error."));
2969 CKioFonts::EFolder
CKioFonts::getFolder(const KUrl
&url
)
2971 return itsRoot
|| isSysFolder(getSect(url
.path())) ? FOLDER_SYS
: FOLDER_USER
;
2974 CKioFonts::TFontMap::Iterator
CKioFonts::getMap(const KUrl
&url
)
2976 KFI_DBUG
<< url
.prettyUrl();
2978 int face(Misc::getIntQueryVal(url
, KFI_KIO_FACE
, 0));
2979 EFolder
folder(getFolder(url
));
2980 TFontMap::Iterator it
=itsFolders
[folder
].fontMap
.find(removeMultipleExtension(url
)),
2981 end(itsFolders
[folder
].fontMap
.end());
2983 if(it
==end
) // Perhaps it was fonts:/System/times.ttf ???
2985 QString
fName(Misc::getFile(url
.path()));
2987 for(int t
=0; t
<3; ++t
)
2989 QString fileName
=0==t
2991 : 1==t
? modifyName(fName
) // lowercase
2992 : modifyName(fName
, true); // uppercase
2994 KFI_DBUG
<< "look for " << fileName
;
2996 for(it
=itsFolders
[folder
].fontMap
.begin(); it
!=end
; ++it
)
2998 CDisabledFonts::TFileList::Iterator
sIt((*it
).files
.begin()),
2999 sEnd((*it
).files
.end());
3001 for(;sIt
!=sEnd
; ++sIt
)
3002 if(Misc::getFile(*sIt
)==fileName
&& (*sIt
).face
==face
)
3011 const CDisabledFonts::TFileList
* CKioFonts::getEntries(const KUrl
&url
,
3012 TFontMap::Iterator
&enabledIt
,
3013 CDisabledFonts::TFontList::Iterator
&disabledIt
)
3015 KFI_DBUG
<< url
.prettyUrl();
3017 EFolder folder
=getFolder(url
);
3018 TFontMap::Iterator
it(getMap(url
)),
3019 end(itsFolders
[folder
].fontMap
.end());
3020 QString name
=Misc::getFile(removeMultipleExtension(url
));
3021 CDisabledFonts::TFontList::Iterator
dIt(itsFolders
[folder
].disabled
->find(name
,
3022 Misc::getIntQueryVal(url
, KFI_KIO_FACE
, 0))),
3023 dEnd(itsFolders
[folder
].disabled
->items().end());
3028 if(it
!=end
&& dIt
==dEnd
)
3030 KFI_DBUG
<< "found enabled";
3032 return &(it
.value().files
);
3034 else if (it
==end
&& dIt
!=dEnd
)
3037 KFI_DBUG
<< "found disabled";
3038 return &((*dIt
).files
);
3040 else if(it
!=end
&& dIt
!=dEnd
)
3042 KFI_DBUG
<< "found both!";
3044 // Oops... we have a match for both a hidden, and non-hidden font! Have to ask which one...
3045 // This should never really happen, as hidden fonts will start with a period.
3046 if(KMessageBox::Yes
==messageBox(QuestionYesNo
,
3047 i18n("The selected URL (%1) matches both an enabled, and disabled "
3048 "font. Which one do you wish to access?", url
.prettyUrl()),
3049 i18n("Duplicate Font"), i18n("Enabled Font"),
3050 i18n("Disabled Font")))
3053 return &(it
.value().files
);
3058 return &((*dIt
).files
);
3062 KFI_DBUG
<< "found none";
3066 QStringList
CKioFonts::getFontNameEntries(EFolder folder
, const QString
&file
, bool disabledFonts
)
3072 CDisabledFonts::TFontList::Iterator
it(itsFolders
[folder
].disabled
->items().begin()),
3073 end(itsFolders
[folder
].disabled
->items().end());
3075 for(; it
!=end
; ++it
)
3077 CDisabledFonts::TFileList::ConstIterator patIt
,
3078 patEnd
=(*it
).files
.end();
3080 for(patIt
=(*it
).files
.begin(); patIt
!=patEnd
; ++patIt
)
3081 if((*patIt
).path
==file
)
3083 rv
.append((*it
).name
);
3090 TFontMap::Iterator it
,
3091 end
=itsFolders
[folder
].fontMap
.end();
3093 for(it
=itsFolders
[folder
].fontMap
.begin(); it
!=end
; ++it
)
3095 CDisabledFonts::TFileList::ConstIterator patIt
,
3096 patEnd
=it
.value().files
.constEnd();
3098 for(patIt
=it
.value().files
.constBegin(); patIt
!=patEnd
; ++patIt
)
3099 if((*patIt
).path
==file
)
3101 rv
.append(it
.key());
3109 QMap
<int, QString
> CKioFonts::getFontIndexToNameEntries(EFolder folder
, const QString
&file
)
3111 QMap
<int, QString
> rv
;
3112 TFontMap::Iterator it
,
3113 end
=itsFolders
[folder
].fontMap
.end();
3115 for(it
=itsFolders
[folder
].fontMap
.begin(); it
!=end
; ++it
)
3117 CDisabledFonts::TFileList::Iterator patIt
,
3118 patEnd
=it
.value().files
.end();
3120 for(patIt
=it
.value().files
.begin(); patIt
!=patEnd
; ++patIt
)
3121 if((*patIt
).path
==file
)
3123 rv
[(*patIt
).face
]=it
.key();
3131 QString
* CKioFonts::getEntry(EFolder folder
, const QString
&file
, bool full
)
3133 TFontMap::Iterator it
,
3134 end
=itsFolders
[folder
].fontMap
.end();
3136 for(it
=itsFolders
[folder
].fontMap
.begin(); it
!=end
; ++it
)
3138 CDisabledFonts::TFileList::Iterator patIt
,
3139 patEnd
=it
.value().files
.end();
3141 for(patIt
=it
.value().files
.begin(); patIt
!=patEnd
; ++patIt
)
3142 if( (full
&& (*patIt
).path
==file
) ||
3143 (!full
&& Misc::getFile(*patIt
)==file
))
3144 return &((*patIt
).path
);
3150 CKioFonts::EFileType
CKioFonts::checkFile(const QString
&file
, const KUrl
&url
)
3153 // To speed things up, check the files extension 1st...
3154 if(Misc::checkExt(file
, "bdf") || Misc::checkExt(file
, "bdf.gz") ||
3155 Misc::checkExt(file
, "pcf") || Misc::checkExt(file
, "pcf.gz"))
3157 // Need to check whether bitmaps have been hidden from from fontconfig - as happens on KUbuntu...
3158 if(FC::bitmapsEnabled())
3161 error(KIO::ERR_SLAVE_DEFINED
, i18n("You cannot install bitmap fonts, as these have been "
3162 "disabled on your system."));
3164 else if(isAAfm(file
) || isAPfm(file
))
3165 return FILE_METRICS
;
3166 else if(Misc::isPackage(file
))
3167 error(KIO::ERR_SLAVE_DEFINED
, i18n("You cannot install a fonts package directly.\n"
3168 "Please extract %1, and install the components individually.",
3173 // Check that file is a font via FreeType...
3175 FcPattern
*pat
=FcFreeTypeQuery((const FcChar8
*)(QFile::encodeName(file
).constData()), 0, NULL
,
3182 if(FcResultMatch
==FcPatternGetBool(pat
, FC_SCALABLE
, 0, &scalable
) && scalable
)
3184 // check too see whether font is already installed!
3185 int weight(KFI_NULL_SETTING
), slant(KFI_NULL_SETTING
), width(KFI_NULL_SETTING
);
3187 FcPatternGetInteger(pat
, FC_WEIGHT
, 0, &weight
);
3188 FcPatternGetInteger(pat
, FC_SLANT
, 0, &slant
);
3189 #ifndef KFI_FC_NO_WIDTHS
3190 FcPatternGetInteger(pat
, FC_WIDTH
, 0, &width
);
3193 QString
name(FC::createName(pat
, weight
, width
, slant
));
3195 KFI_DBUG
<< "Check for name:" << name
;
3197 // TODO: CDisabledFonts need to find on family & style info? Also need a find() that does
3198 // not take into account face! Perhaps use -1?
3199 if(itsFolders
[FOLDER_SYS
].fontMap
.contains(name
) ||
3200 itsFolders
[FOLDER_SYS
].disabled
->items().end()!=
3201 itsFolders
[FOLDER_SYS
].disabled
->find(name
, 1) ||
3202 (!itsRoot
&& (itsFolders
[FOLDER_USER
].fontMap
.contains(name
) ||
3203 itsFolders
[FOLDER_USER
].disabled
->items().end()!=
3204 itsFolders
[FOLDER_USER
].disabled
->find(name
, 1))))
3206 FcPatternDestroy(pat
);
3207 error(KIO::ERR_SLAVE_DEFINED
, i18n("File %1 contains the font:\n%2\n"
3208 "A font with this name is already installed.\n",
3209 urlString(url
), name
));
3210 return FILE_UNKNOWN
;
3213 FcPatternDestroy(pat
);
3217 error(KIO::ERR_SLAVE_DEFINED
, i18n("Could not determine file type for: %1\n"
3218 "Only fonts may be installed.", urlString(url
)));
3220 return FILE_UNKNOWN
;
3223 bool CKioFonts::getSourceFiles(const KUrl
&src
, CDisabledFonts::TFileList
&files
, bool removeSymLinks
)
3225 if(KFI_KIO_FONTS_PROTOCOL
==src
.protocol())
3227 CDisabledFonts::TFontList::Iterator disabledIt
;
3228 TFontMap::Iterator enabledIt
;
3229 const CDisabledFonts::TFileList
*entries
=getEntries(src
, enabledIt
, disabledIt
);
3232 getFontFiles(*entries
, files
, removeSymLinks
);
3235 if(src
.isLocalFile())
3236 if(FILE_UNKNOWN
!=checkFile(src
.path(), src
))
3237 files
.append(CDisabledFonts::TFile(src
.path()));
3239 return false; // error logged in checkFile...
3243 CDisabledFonts::TFileList::Iterator it
,
3246 for(it
=files
.begin(); it
!=end
; ++it
)
3248 QByteArray realSrc
=QFile::encodeName(*it
);
3249 KDE_struct_stat buffSrc
;
3251 if (-1==KDE_stat(realSrc
.constData(), &buffSrc
))
3253 error(EACCES
==errno
? KIO::ERR_ACCESS_DENIED
: KIO::ERR_DOES_NOT_EXIST
,
3257 if(S_ISDIR(buffSrc
.st_mode
))
3259 error(KIO::ERR_IS_DIRECTORY
, urlString(src
));
3262 if(S_ISFIFO(buffSrc
.st_mode
) || S_ISSOCK(buffSrc
.st_mode
))
3264 error(KIO::ERR_CANNOT_OPEN_FOR_READING
, urlString(src
));
3271 error(KIO::ERR_DOES_NOT_EXIST
, urlString(src
));
3278 bool CKioFonts::checkDestFile(const KUrl
&src
, const KUrl
&dest
, EFolder destFolder
, KIO::JobFlags flags
)
3280 QStringList folders
;
3282 folders
.append(itsFolders
[destFolder
].location
);
3283 folders
.append(getDestFolder(itsFolders
[destFolder
].location
, src
.fileName()));
3285 QStringList::const_iterator
it(folders
.begin()),
3289 for(; it
!=end
; ++it
)
3291 if(!(flags
& KIO::Overwrite
) && (Misc::fExists(destFile
=(*it
)+src
.fileName()) ||
3292 Misc::fExists(destFile
=(*it
)+modifyName(src
.fileName())) ||
3293 Misc::fExists(destFile
=(*it
)+modifyName(src
.fileName(), true)) ) )
3295 // If copying / moving a TTC and it is the *same* file, then don't log an error, but
3296 // don't continue the transaction...
3298 // Reason being that fonts:/ lists the font names (not filenames) so for a TTC there'll
3299 // be multiple entries...
3300 if(isSameTtc(src
.path(), destFile
))
3303 error(KIO::ERR_FILE_ALREADY_EXIST
, urlString(dest
));
3307 bool isHidden
=Misc::isHidden(src
);
3308 QString
other(isHidden
? src
.fileName().mid(1)
3309 : QChar('.')+src
.fileName());
3311 if(Misc::fExists((*it
)+other
) ||
3312 Misc::fExists((*it
)+modifyName(other
)) ||
3313 Misc::fExists((*it
)+modifyName(other
, true)))
3315 error(KIO::ERR_SLAVE_DEFINED
,
3317 ? i18n("Could not install %1\nA matching enabled font already exists. "
3318 "Please disable that.", urlString(src
))
3319 : i18n("Could not install %1\nA matching disabled font already exists. "
3320 "Please enable that.", urlString(src
)));
3327 bool CKioFonts::checkDestFiles(const KUrl
&src
, QMap
<QString
, QString
> &map
, const KUrl
&dest
,
3328 EFolder destFolder
, KIO::JobFlags flags
)
3331 // Check whether files exist at destination...
3333 if(dest
.protocol()==src
.protocol() &&
3334 dest
.directory()==src
.directory()) // Check whether confirmUrl changed a "cp fonts:/System
3335 // fonts:/" to "cp fonts:/System fonts:/System"
3337 error(KIO::ERR_FILE_ALREADY_EXIST
, urlString(dest
));
3341 if(!(flags
& KIO::Overwrite
))
3343 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
3347 for(; fIt
!=fEnd
; ++fIt
)
3348 if(NULL
!=(destEntry
=getEntry(destFolder
, fIt
.value())) ||
3349 NULL
!=(destEntry
=getEntry(destFolder
, modifyName(fIt
.value()))) || // lowercase
3350 NULL
!=(destEntry
=getEntry(destFolder
, modifyName(fIt
.value()), true))) // uppercase
3352 // If copying / moving a TTC and it is the *same* file, then don't log an error, but
3353 // don't continue the transaction...
3355 // Reason being that fonts:/ lists the font names (not filenames) so for a TTC there'll
3356 // be multiple entries for a TTC...
3357 if(isSameTtc(src
.path(), *destEntry
))
3360 error(KIO::ERR_FILE_ALREADY_EXIST
, urlString(dest
));
3369 // Gather the number and names of the font faces located in "files". If there is more than 1 face
3370 // (such as there would be for a TTC font), then ask the user for confirmation of the action.
3371 bool CKioFonts::confirmMultiple(const KUrl
&url
, const CDisabledFonts::TFileList
&files
, EFolder folder
,
3374 if(KFI_KIO_FONTS_PROTOCOL
!=url
.protocol())
3377 CDisabledFonts::TFileList::ConstIterator it
,
3381 for(it
=files
.begin(); it
!=files
.end(); ++it
)
3383 QStringList
fn(getFontNameEntries(folder
, *it
, OP_ENABLE
==op
));
3384 QStringList::const_iterator
fnIt(fn
.begin()),
3387 for(; fnIt
!=fnEnd
; ++fnIt
)
3388 if(-1==fonts
.indexOf(*fnIt
))
3389 fonts
.append(*fnIt
);
3396 QStringList::const_iterator it
,
3397 end
=fonts
.constEnd();
3399 for(it
=fonts
.constBegin(); it
!=end
; ++it
)
3400 out
+=QString("<li>")+*it
+QString("</li>");
3405 question
=i18n("<p>You are attempting to move a font that is located in a file alongside "
3406 "other fonts; in order to proceed with the move they will "
3407 "all have to be moved. The affected fonts are:</p>"
3408 "<ul>%1</ul><p>\n Do you wish to move all of these?</p>", out
);
3411 question
=i18n("<p>You are attempting to copy a font that is located in a file alongside "
3412 "other fonts; in order to proceed with the copy they will "
3413 "all have to be copied. The affected fonts are:</p>"
3414 "<ul>%1</ul><p>\n Do you wish to copy all of these?</p>", out
);
3417 question
=i18n("<p>You are attempting to delete a font that is located in a file alongside "
3418 "other fonts; in order to proceed with the deletion they will "
3419 "all have to be deleted. The affected fonts are:</p>"
3420 "<ul>%1</ul><p>\n Do you wish to delete all of these?</p>", out
);
3423 question
=i18n("<p>You are attempting to enable a font that is located in a file alongside "
3424 "other fonts; in order to proceed with the enabling they will "
3425 "all have to be enabled. The affected fonts are:</p>"
3426 "<ul>%1</ul><p>\n Do you wish to enable all of these?</p>", out
);
3429 question
=i18n("<p>You are attempting to disable a font that is located in a file alongside "
3430 "other fonts; in order to proceed with the disabling they will "
3431 "all have to be disabled. The affected fonts are:</p>"
3432 "<ul>%1</ul><p>\n Do you wish to disable all of these?</p>", out
);
3436 if(KMessageBox::No
==messageBox(question
, QuestionYesNo
))
3438 error(KIO::ERR_USER_CANCELED
, urlString(url
));
3446 bool CKioFonts::confirmMultiple(const KUrl
&url
, const CDisabledFonts::TFileList
*patterns
,
3447 EFolder folder
, EOp op
)
3449 if(KFI_KIO_FONTS_PROTOCOL
!=url
.protocol())
3452 return patterns
? confirmMultiple(url
, *patterns
, folder
, op
) : false;
3455 bool CKioFonts::checkUrl(const KUrl
&u
, bool rootOk
, bool logError
)
3457 if(KFI_KIO_FONTS_PROTOCOL
==u
.protocol() && (!rootOk
|| (rootOk
&& "/"!=u
.path())))
3459 QString
sect(getSect(u
.path()));
3463 if((isSysFolder(sect
) || isUserFolder(sect
)) &&
3464 (itsFolders
[FOLDER_SYS
].fontMap
.end()==itsFolders
[FOLDER_SYS
].fontMap
.find(sect
)))
3465 //CPD: TODO: || it has a font specified! e.g. fonts:/System/Times -> even in have a
3466 // fonts:/System font, redirect should still happen
3468 redirection(getRedirect(u
));
3474 if(!isSysFolder(sect
) && !isUserFolder(sect
) && !isAllFolder(sect
) )
3477 error(KIO::ERR_SLAVE_DEFINED
, i18n("Please specify \"%1\" or \"%2\".",
3478 i18n(KFI_KIO_FONTS_USER
), i18n(KFI_KIO_FONTS_SYS
)));
3486 bool CKioFonts::checkAllowed(const KUrl
&u
)
3488 if (KFI_KIO_FONTS_PROTOCOL
==u
.protocol())
3490 QString
ds(Misc::dirSyntax(u
.path()));
3492 if(ds
==QString(QChar('/')+i18n(KFI_KIO_FONTS_USER
)+QChar('/')) ||
3493 ds
==QString(QChar('/')+i18n(KFI_KIO_FONTS_SYS
)+QChar('/')) ||
3494 ds
==QString(QChar('/')+QString::fromLatin1(KFI_KIO_FONTS_USER
)+QChar('/')) ||
3495 ds
==QString(QChar('/')+QString::fromLatin1(KFI_KIO_FONTS_SYS
)+QChar('/')))
3497 error(KIO::ERR_SLAVE_DEFINED
,
3498 i18n("You cannot rename, move, copy, or delete either \"%1\" or \"%2\".",
3499 i18n(KFI_KIO_FONTS_USER
), i18n(KFI_KIO_FONTS_SYS
))); \
3508 // Create an AFM from a Type 1 (pfa/pfb) font and its PFM file...
3509 void CKioFonts::createAfm(const QString
&file
, bool nrs
)
3511 #if defined USE_POLICYKIT && USE_POLICYKIT==1
3512 if(nrs
&& 0==itsPid
)
3515 if(nrs
&& itsPasswd
.isEmpty())
3519 bool type1
=isAType1(file
),
3520 pfm
=!type1
&& isAPfm(file
); // No point checking if is pfm if its a type1
3524 // pf2afm wants files with lowercase extension, so just check for lowercase!
3525 // -- when a font is installed, the extension is converted to lowercase anyway...
3526 QString afm
=getMatch(file
, "afm");
3528 if(afm
.isEmpty()) // No point creating if AFM already exists!
3533 if(type1
) // Its a Type1, so look for existing PFM
3535 pfm
=getMatch(file
, "pfm");
3538 else // Its a PFM, so look for existing Type1
3540 t1
=getMatch(file
, "pfa");
3542 t1
=getMatch(file
, "pfb");
3546 if(!t1
.isEmpty() && !pfm
.isEmpty()) // Do we have both Type1 and PFM?
3548 QString
name(t1
.left(t1
.length()-4)); // pf2afm wants name without extension...
3551 doRootCmd(KUrl(), TCommand(KFI::CMD_CREATE_AFM
, name
));
3553 Misc::doCmd("pf2afm", QFile::encodeName(name
));
3559 int CKioFonts::reconfigTimeout()
3561 return hasMetaData(KFI_KIO_TIMEOUT
)
3562 ? metaData(KFI_KIO_TIMEOUT
).toInt()
3566 void CKioFonts::TFolder::setLocation(const QString
&l
, bool sys
)
3570 disabled
=new CDisabledFonts(sys
);