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"
66 // Enable the following so that all URLs are actually <family>, <style>, e.g.
67 // without #define: fonts:/arial.ttf
68 // with #define: fonts:/Arial, Regular.ttf
70 // Not enabled - as it messes things up a little with fonts/group files.
71 //#define KFI_KIO_ALL_URLS_HAVE_NAME
73 #define KFI_DBUG kDebug(7000) << '(' << time(NULL) << ')'
75 #define MAX_IPC_SIZE (1024*32)
76 #define DEFAULT_TIMEOUT 2 // Time between last mod and writing files...
77 #define FC_CACHE_CMD "fc-cache"
79 using namespace KDESu
;
81 static const int constMaxFcCheckTime
=10;
85 KDE_EXPORT
int kdemain(int argc
, char **argv
);
88 static KFI::CKioFonts
*slaveInstance
=NULL
;
90 void kioFontsExitHandler()
94 slaveInstance
->cleanup();
99 int kdemain(int argc
, char **argv
)
103 fprintf(stderr
, "Usage: kio_" KFI_KIO_FONTS_PROTOCOL
104 " protocol domain-socket1 domain-socket2\n");
108 KLocale::setMainCatalog(KFI_CATALOGUE
);
110 KComponentData
componentData("kio_" KFI_KIO_FONTS_PROTOCOL
);
111 KFI::CKioFonts
slave(argv
[2], argv
[3]);
113 atexit(kioFontsExitHandler
);
114 slave
.dispatchLoop();
122 static bool addCreateFolderCmd(const QString
&folder
, QList
<CKioFonts::TCommand
> &cmd
)
124 if(!Misc::dExists(folder
))
126 cmd
.append(CKioFonts::TCommand(KFI::CMD_CREATE_DIR
, folder
));
133 inline bool isSysFolder(const QString
§
)
135 return i18n(KFI_KIO_FONTS_SYS
)==sect
|| KFI_KIO_FONTS_SYS
==sect
;
138 inline bool isUserFolder(const QString
§
)
140 return i18n(KFI_KIO_FONTS_USER
)==sect
|| KFI_KIO_FONTS_USER
==sect
;
143 inline bool isAllFolder(const QString
§
)
145 return i18n(KFI_KIO_FONTS_ALL
)==sect
|| KFI_KIO_FONTS_ALL
==sect
;
148 #ifdef KFI_KIO_ALL_URLS_HAVE_NAME
149 static const char *constExtensions
[]=
150 {".ttf", KFI_FONTS_PACKAGE
, ".otf", ".pfa", ".pfb", ".ttc",
151 ".pcf", ".pcf.gz", ".bdf", ".bdf.gz", NULL
};
153 static QString
removeKnownExtension(const KUrl
&url
)
155 QString
fname(url
.fileName());
158 for(int i
=0; constExtensions
[i
]; ++i
)
159 if(-1!=(pos
=fname
.lastIndexOf(QString::fromLatin1(constExtensions
[i
]), -1, Qt::CaseInsensitive
)))
160 return fname
.left(pos
);
164 #define removeMultipleExtension(A) removeKnownExtension(A)
165 static void addKnownExtension(QString
&url
, const CDisabledFonts::TFileList
&files
, const QString
&name
,
172 url
+=name
+QString::fromLatin1(KFI_FONTS_PACKAGE
);
176 QString
fileName(Misc::getFile(files
.first()));
179 for(int i
=0; constExtensions
[i
]; ++i
)
180 if(-1!=(pos
=fileName
.lastIndexOf(QString::fromLatin1(constExtensions
[i
]), -1,
181 Qt::CaseInsensitive
)))
185 url
+=name
+constExtensions
[i
];
192 static QString
removeMultipleExtension(const KUrl
&url
)
194 QString
fname(url
.fileName());
197 if(-1!=(pos
=fname
.lastIndexOf(QString::fromLatin1(KFI_FONTS_PACKAGE
))))
198 fname
=fname
.left(pos
);
204 static QString
modifyName(const QString
&fname
, bool toUpper
=false)
206 static const char constSymbols
[]={ '-', ' ', ':', ';', '/', '~', 0 };
208 QString
rv(toUpper
? fname
.toUpper() : fname
.toLower());
210 for(int s
=0; constSymbols
[s
]; ++s
)
211 rv
=rv
.replace(constSymbols
[s
], '_');
216 static bool checkFiles(const CDisabledFonts::TFileList
&files
)
218 CDisabledFonts::TFileList::ConstIterator
it(files
.begin()),
222 if(!Misc::fExists(*it
))
227 inline int getSize(KIO::UDSEntry
&entry
)
229 return entry
.numberValue(KIO::UDSEntry::UDS_SIZE
, 0);
232 static int getSize(const QByteArray
&file
)
234 KDE_struct_stat buff
;
236 if(-1!=KDE_lstat(file
, &buff
))
238 if (S_ISLNK(buff
.st_mode
))
241 int n
=readlink(file
, buffer2
, 1000);
245 if(-1==KDE_stat(file
, &buff
))
254 static int getSize(const CDisabledFonts::TFileList
&files
)
256 CDisabledFonts::TFileList::ConstIterator it
,
260 for(it
=files
.begin(); it
!=end
; ++it
)
261 size
+=getSize(QFile::encodeName(*it
));
267 // Return real filename
268 // if normal file, return file
269 // if link, return dest
270 static QString
getReal(const QString
&file
)
272 QByteArray
cPath(QFile::encodeName(file
));
273 KDE_struct_stat buff
;
275 if(-1!=KDE_lstat(cPath
, &buff
) && S_ISLNK(buff
.st_mode
))
278 int n
=readlink(cPath
, buffer2
, 1000);
284 if('.'==buffer2
[0]) // Relative link...
286 QString
linkDest(QString::fromLocal8Bit(buffer2
));
287 QDir
d(Misc::getDir(file
)+Misc::getDir(linkDest
));
289 return Misc::dirSyntax(d
.canonicalPath())+Misc::getFile(linkDest
);
292 return QString::fromLocal8Bit(buffer2
);
299 // Get the list of files associated with a list of entries...
300 // 1. get any associated afm or pfms
301 // 2. Resolve any symlinks
302 // 3. Remove duplicates (due to symlik and real being in list)
303 static void getFontFiles(const CDisabledFonts::TFileList
&entries
, CDisabledFonts::TFileList
&files
,
304 bool removeSymLinks
=true)
306 CDisabledFonts::TFileList::ConstIterator it
,
309 for(it
=entries
.begin(); it
!=end
; ++it
)
312 QString
file(removeSymLinks
? getReal(*it
) : (*it
).path
);
314 if(-1==files
.indexOf(file
) && Misc::fExists(file
))
317 Misc::getAssociatedFiles(*it
, assoc
);
321 QStringList::Iterator fIt
,
324 for(fIt
=assoc
.begin(); fIt
!=fEnd
; ++fIt
)
326 file
=removeSymLinks
? getReal(*fIt
) : *fIt
;
328 if(!files
.contains(file
) && Misc::fExists(file
))
329 files
.append(CDisabledFonts::TFile(file
));
335 static bool isScalable(const QString
&str
)
337 QByteArray
cFile(QFile::encodeName(str
));
339 return Misc::checkExt(cFile
, "ttf") || Misc::checkExt(cFile
, "otf") || Misc::checkExt(cFile
, "ttc") ||
340 Misc::checkExt(cFile
, "pfa") || Misc::checkExt(cFile
, "pfb");
343 static bool isATtc(const QByteArray
&file
)
346 // To speed things up, check the files extension 1st...
347 if(Misc::checkExt(file
, "ttc"))
351 // No '.ttc' exension match, so try querying with FreeType...
353 FcPattern
*pat
=FcFreeTypeQuery((const FcChar8
*)(QFile::encodeName(file
).constData()), 0, NULL
, &count
);
357 FcPatternDestroy(pat
);
358 return count
>1; // Only care if TTC has more than 1 face...
365 // ...src and dest are the *same* ttc file -> TTC copy
366 // ...or that src does not exist, and a new dest does -> TTC move
367 static bool isSameTtc(const QString
&src
, const QString
&dest
)
369 static const int constMaxTimeDiff
=20;
371 QByteArray
cDest(QFile::encodeName(dest
));
375 QByteArray
cSrc(QFile::encodeName(src
));
377 KDE_struct_stat srcStat
,
379 bool srcExists
=-1!=KDE_lstat(cSrc
, &srcStat
),
380 destExists
=-1!=KDE_lstat(cDest
, &destStat
);
382 // Check that file sizes are the same, and that the dest file is recent...
383 if(srcExists
&& destExists
)
385 if(srcStat
.st_size
==destStat
.st_size
&& abs(destStat
.st_atime
-time(NULL
))<constMaxTimeDiff
)
387 // Sizes match, so check md5 sums...
391 if(srcFile
.open(QIODevice::ReadOnly
) && destFile
.open(QIODevice::ReadOnly
))
396 return srcMd5
.update(srcFile
) && destMd5
.update(destFile
) &&
397 srcMd5
.verify(destMd5
.rawDigest());
401 else // In case of move, after the 1st, src won't exist, but dest should (and should be recent!)
402 return destExists
&& abs(destStat
.st_atime
-time(NULL
))<constMaxTimeDiff
;
415 static KUrl
getRedirect(const KUrl
&u
)
417 // Go from fonts:/System to fonts:/
420 QString
path(u
.path()),
421 sect(CKioFonts::getSect(path
));
424 path
.replace("//", "/");
425 redirect
.setPath(path
);
427 KFI_DBUG
<< "Redirect from " << u
.path() << " to " << redirect
.path();
431 static bool nonRootSys(const KUrl
&u
)
433 return !Misc::root() && isSysFolder(CKioFonts::getSect(u
.path()));
436 static bool writeAll(int fd
, const char *buf
, size_t len
)
440 ssize_t written
=write(fd
, buf
, len
);
441 if (written
<0 && EINTR
!=errno
)
449 static bool isAAfm(const QString
&fname
)
451 if(Misc::checkExt(QFile::encodeName(fname
), "afm")) // CPD? Is this a necessary check?
455 if(file
.open(QIODevice::ReadOnly
))
457 QTextStream
stream(&file
);
460 for(int lc
=0; lc
<30 && !stream
.atEnd(); ++lc
)
462 line
=stream
.readLine();
464 if(line
.contains("StartFontMetrics"))
478 static bool isAPfm(const QString
&fname
)
482 // I know extension checking is bad, but Ghostscript's pf2afm requires the pfm file to
483 // have the .pfm extension...
484 QByteArray
name(QFile::encodeName(fname
));
486 if(Misc::checkExt(name
, "pfm"))
489 // OK, the extension matches, so perform a little contents checking...
490 FILE *f
=fopen(name
.constData(), "r");
494 static const unsigned long constCopyrightLen
= 60;
495 static const unsigned long constTypeToExt
= 49;
496 static const unsigned long constExtToFname
= 20;
497 static const unsigned long constExtLen
= 30;
498 static const unsigned long constFontnameMin
= 75;
499 static const unsigned long constFontnameMax
= 512;
501 unsigned short version
=0,
504 unsigned long length
=0,
508 fseek(f
, 0, SEEK_END
);
510 fseek(f
, 0, SEEK_SET
);
512 if(2==fread(&version
, 1, 2, f
) && // Read version
513 4==fread(&length
, 1, 4, f
) && // length...
515 0==fseek(f
, constCopyrightLen
, SEEK_CUR
) && // Skip copyright notice...
516 2==fread(&type
, 1, 2, f
) &&
517 0==fseek(f
, constTypeToExt
, SEEK_CUR
) &&
518 2==fread(&extlen
, 1, 2, f
) &&
519 extlen
==constExtLen
&&
520 0==fseek(f
, constExtToFname
, SEEK_CUR
) &&
521 4==fread(&fontname
, 1, 4, f
) &&
522 fontname
>constFontnameMin
&& fontname
<constFontnameMax
)
531 // This function is *only* used for the generation of AFMs from PFMs.
532 static bool isAType1(const QString
&fname
)
534 static const char * constStr
="%!PS-AdobeFont-";
535 static const unsigned int constStrLen
=15;
536 static const unsigned int constPfbOffset
=6;
537 static const unsigned int constPfbLen
=constStrLen
+constPfbOffset
;
539 QByteArray
name(QFile::encodeName(fname
));
540 char buffer
[constPfbLen
];
543 if(Misc::checkExt(name
, "pfa"))
545 FILE *f
=fopen(name
.constData(), "r");
549 if(constStrLen
==fread(buffer
, 1, constStrLen
, f
))
550 match
=0==memcmp(buffer
, constStr
, constStrLen
);
554 else if(Misc::checkExt(name
, "pfb"))
556 static const char constPfbMarker
=0x80;
558 FILE *f
=fopen(name
.constData(), "r");
562 if(constPfbLen
==fread(buffer
, 1, constPfbLen
, f
))
563 match
=buffer
[0]==constPfbMarker
&& 0==memcmp(&buffer
[constPfbOffset
], constStr
,
572 static QString
getMatch(const QString
&file
, const char *extension
)
574 QString
f(Misc::changeExt(file
, extension
));
576 return Misc::fExists(f
) ? f
: QString();
583 Path(const QString
&p
=QString()) : orig(p
) { }
588 bool operator==(const Path
&p
) const { return p
.orig
==orig
; }
591 KfiFont(const QString
&n
=QString(), const QString
&p
=QString()) : name(n
)
592 { if(!p
.isEmpty()) paths
.append(Path(p
)); }
597 bool operator==(const KfiFont
&f
) const { return f
.name
==name
; }
600 struct KfiFontList
: public QList
<KfiFont
>
602 Iterator
locate(const KfiFont
&t
) { int i
= indexOf(t
); return (-1==i
? end() : (begin()+i
)); }
605 static void setName(const QString
&orig
, QString
&modified
, int pos
, bool hidden
)
607 modified
=orig
.mid(pos
);
608 modified
=modified
.replace('/', '_');
609 if(hidden
&& '.'!=modified
[0])
610 modified
='.'+modified
;
614 // This function returns a set of maping of from -> to for copy/move operations
615 static bool getFontList(const CDisabledFonts::TFileList
&files
, QMap
<QString
, QString
> &map
)
617 // First of all create a list of font files, and their paths
618 CDisabledFonts::TFileList::ConstIterator it
=files
.begin(),
624 QString
name(Misc::getFile(*it
)),
625 path(Misc::getDir(*it
));
626 KfiFontList::Iterator entry
=list
.locate(KfiFont(name
));
628 if(entry
!=list
.end())
630 if(!(*entry
).paths
.contains(path
))
631 (*entry
).paths
.append(path
);
634 list
.append(KfiFont(name
, path
));
637 KfiFontList::Iterator
fIt(list
.begin()),
640 for(; fIt
!=fEnd
; ++fIt
)
642 bool hidden
='.'==(*fIt
).name
[0];
643 QList
<KfiFont::Path
>::Iterator
pBegin((*fIt
).paths
.begin()),
645 pEnd((*fIt
).paths
.end());
648 if((*fIt
).paths
.count()>1)
650 // There's more than 1 file with the same name, but in a different location
651 // therefore, take the unique part of the path, and replace / with _
653 // /usr/X11R6/lib/X11/fonts/75dpi/times.pcf.gz
654 // /usr/X11R6/lib/X11/fonts/100dpi/times.pcf.gz
657 // 75dpi_times.pcf.gz
658 // 100dpi_times.pcf.gz
659 int beginLen((*pBegin
).orig
.length());
661 for(; pIt
!=pEnd
; ++pIt
)
663 unsigned int len
=qMin((*pIt
).orig
.length(), beginLen
);
666 for(unsigned int i
=0; i
<len
; ++i
)
667 if((*pIt
).orig
[i
]!=(*pBegin
).orig
[i
])
669 setName((*pIt
).orig
, (*pIt
).modified
, i
, hidden
);
670 if((*pBegin
).modified
.isEmpty())
671 setName((*pBegin
).orig
, (*pBegin
).modified
, i
, hidden
);
676 if(beginLen
>(*pIt
).orig
.length())
678 if((*pBegin
).modified
.isEmpty())
679 setName((*pBegin
).orig
, (*pBegin
).modified
, (*pIt
).orig
.length(), hidden
);
682 setName((*pIt
).orig
, (*pIt
).modified
, beginLen
, hidden
);
685 for(pIt
=(*fIt
).paths
.begin(); pIt
!=pEnd
; ++pIt
)
686 if(hidden
&& '.'==(*pIt
).modified
[0] && '.'==(*fIt
).name
[0])
687 map
[(*pIt
).orig
+(*fIt
).name
]=(*pIt
).modified
+(*fIt
).name
.mid(1);
689 map
[(*pIt
).orig
+(*fIt
).name
]=(*pIt
).modified
+(*fIt
).name
;
692 return list
.count() ? true : false;
695 inline QString
getDestFolder(const QString
&folder
, const QString
&file
)
697 return folder
+file
[0].toLower()+'/';
700 // Extract just the family from a font name
701 static QString
getFamily(const QString
&font
)
703 int commaPos
=font
.lastIndexOf(',');
704 return -1==commaPos
? font
: font
.left(commaPos
);
707 inline qulonglong
toBit(QFontDatabase::WritingSystem ws
)
709 return ((qulonglong
)1) << (int)ws
;
712 //.........the following section is inspired by qfontdatabase_x11.cpp / loadFontConfig
715 // Unfortunately FontConfig doesn't know about some languages. We have to test these through the
716 // charset. The lists below contain the systems where we need to do this.
719 QFontDatabase::WritingSystem ws
;
721 } sampleCharForWritingSystem
[] =
723 { QFontDatabase::Telugu
, 0xc15 },
724 { QFontDatabase::Kannada
, 0xc95 },
725 { QFontDatabase::Malayalam
, 0xd15 },
726 { QFontDatabase::Sinhala
, 0xd9a },
727 { QFontDatabase::Myanmar
, 0x1000 },
728 { QFontDatabase::Ogham
, 0x1681 },
729 { QFontDatabase::Runic
, 0x16a0 },
730 { QFontDatabase::Any
, 0x0 }
733 static qulonglong
getWritingSystems(FcPattern
*pat
)
737 FcLangSet
*langset(0);
738 const CDisabledFonts::LangWritingSystemMap
*langForWritingSystem(CDisabledFonts::languageForWritingSystemMap());
740 if (FcResultMatch
==FcPatternGetLangSet(pat
, FC_LANG
, 0, &langset
))
742 for (int i
= 0; langForWritingSystem
[i
].lang
; ++i
)
743 if (FcLangDifferentLang
!=FcLangSetHasLang(langset
, langForWritingSystem
[i
].lang
))
744 ws
|=toBit(langForWritingSystem
[i
].ws
);
747 ws
|=toBit(QFontDatabase::Other
);
751 if (FcResultMatch
== FcPatternGetCharSet(pat
, FC_CHARSET
, 0, &cs
))
753 // some languages are not supported by FontConfig, we rather check the
754 // charset to detect these
755 for (int i
= 0; QFontDatabase::Any
!=sampleCharForWritingSystem
[i
].ws
; ++i
)
756 if (FcCharSetHasChar(cs
, sampleCharForWritingSystem
[i
].ch
))
757 ws
|=toBit(sampleCharForWritingSystem
[i
].ws
);
763 static QString
obtainMimeType(const QString
&file
)
765 if(Misc::checkExt(file
, "ttf") || Misc::checkExt(file
, "ttc"))
766 return "application/x-font-ttf";
767 if(Misc::checkExt(file
, "otf"))
768 return "application/x-font-otf";
769 if(Misc::checkExt(file
, "pfa") || Misc::checkExt(file
, "pfb"))
770 return "application/x-font-type1";
771 if(Misc::checkExt(file
, "pcf.gz") || Misc::checkExt(file
, "pcf"))
772 return "application/x-font-pcf";
773 if(Misc::checkExt(file
, "bdf.gz") || Misc::checkExt(file
, "bdf"))
774 return "application/x-font-bdf";
776 // File extension check failed, use kmimetype to read contents...
777 return KMimeType::findByPath(file
)->name();
782 CKioFonts::CKioFonts(const QByteArray
&pool
, const QByteArray
&app
)
783 : KIO::SlaveBase(KFI_KIO_FONTS_PROTOCOL
, pool
, app
),
784 itsRoot(Misc::root()),
785 itsAddToSysFc(false),
786 itsLastFcCheckTime(0),
797 // Set core dump size to 0 because we will have
798 // root's password in memory.
800 rlim
.rlim_cur
=rlim
.rlim_max
=0;
801 setrlimit(RLIMIT_CORE
, &rlim
);
804 // Check with fontconfig for folder locations...
806 // 1. Get list of fontconfig dirs
807 // 2. For user, look for any starting with $HOME - but prefer $HOME/.fonts
808 // 3. For system, look for any starting with /usr/local/share - but prefer /usr/local/share/fonts
809 // 4. If either are not found, then add to local.conf / .fonts.conf
811 FcStrList
*list
=FcConfigGetFontDirs(FcInitLoadConfigAndFonts());
815 while((dir
=FcStrListNext(list
)))
816 dirs
.append(Misc::dirSyntax((const char *)dir
));
818 EFolder mainFolder
=FOLDER_SYS
;
822 QString
home(Misc::dirSyntax(QDir::homePath())),
823 defaultDir(Misc::dirSyntax(QDir::homePath()+"/.fonts/")),
824 dir(Misc::getFolder(defaultDir
, home
, dirs
));
826 if(dir
.isEmpty()) // Then no $HOME/ was found in fontconfigs dirs!
828 KXftConfig
xft(KXftConfig::Dirs
, false);
829 xft
.addDir(defaultDir
);
833 mainFolder
=FOLDER_USER
;
834 itsFolders
[FOLDER_USER
].setLocation(dir
, false);
837 QString
sysDefault("/usr/local/share/fonts/"),
838 sysDir(Misc::getFolder(sysDefault
, "/usr/local/share/", dirs
));
844 KXftConfig
xft(KXftConfig::Dirs
, true);
845 xft
.addDir(sysDefault
);
854 itsFolders
[FOLDER_SYS
].setLocation(sysDir
, true);
858 if(!Misc::dExists(itsFolders
[mainFolder
].location
))
859 Misc::createDir(itsFolders
[mainFolder
].location
);
864 void CKioFonts::cleanup()
869 itsFolders
[FOLDER_USER
].disabled
->save();
877 void CKioFonts::listDir(const KUrl
&url
)
879 KFI_DBUG
<< url
.path() << " query:" << url
.query();
881 clearFontList(); // Always refresh font list when listing...
882 if(updateFontList() && checkUrl(url
, true))
886 sections
=url
.path().split('/', QString::SkipEmptyParts
).count();
887 if(itsRoot
|| sections
!=0)
889 if(!itsRoot
&& isAllFolder(getSect(url
.path())))
891 totalSize(itsFolders
[FOLDER_SYS
].fontMap
.count()+itsFolders
[FOLDER_SYS
].disabled
->items().count()+
892 itsFolders
[FOLDER_USER
].fontMap
.count()+itsFolders
[FOLDER_USER
].disabled
->items().count());
893 listDir(FOLDER_SYS
, entry
);
894 listDir(FOLDER_USER
, entry
);
898 EFolder folder
=getFolder(url
);
900 totalSize(itsFolders
[folder
].fontMap
.count()+itsFolders
[folder
].disabled
->items().count());
901 listDir(folder
, entry
);
908 createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_USER
), itsFolders
[FOLDER_USER
].location
,
910 listEntry(entry
, false);
911 createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_SYS
), itsFolders
[FOLDER_SYS
].location
,
913 listEntry(entry
, false);
916 listEntry(size
? entry
: KIO::UDSEntry(), true);
920 KFI_DBUG
<< "finished!";
923 void CKioFonts::listDir(EFolder folder
, KIO::UDSEntry
&entry
)
925 if(itsFolders
[folder
].fontMap
.count())
927 TFontMap::Iterator it
=itsFolders
[folder
].fontMap
.begin(),
928 end
=itsFolders
[folder
].fontMap
.end();
930 for ( ; it
!= end
; ++it
)
933 if(createFontUDSEntry(entry
, it
.key(), it
.value().files
, it
.value().styleVal
,
934 it
.value().writingSystems
, FOLDER_SYS
==folder
))
935 listEntry(entry
, false);
939 CDisabledFonts::TFontList::Iterator
dIt(itsFolders
[folder
].disabled
->items().begin()),
940 dEnd(itsFolders
[folder
].disabled
->items().end());
942 for(; dIt
!=dEnd
; ++dIt
)
943 if(createFontUDSEntry(entry
, (*dIt
).getName(), (*dIt
).files
,
944 (*dIt
).styleInfo
, (*dIt
).writingSystems
, FOLDER_SYS
==folder
, true))
945 listEntry(entry
, false);
948 void CKioFonts::stat(const KUrl
&url
)
950 KFI_DBUG
<< url
.prettyUrl() << " query:" << url
.query();
955 if(checkUrl(url
, true, false))
957 QString
path(url
.path(KUrl::RemoveTrailingSlash
));
961 error(KIO::ERR_COULD_NOT_STAT
, url
.prettyUrl());
965 QStringList
pathList(path
.split('/', QString::SkipEmptyParts
));
967 switch(pathList
.count())
970 err
=!createFolderUDSEntry(entry
, i18n("Fonts"),
971 itsFolders
[itsRoot
? FOLDER_SYS
: FOLDER_USER
].location
,
976 err
=!createStatEntry(entry
, url
, FOLDER_SYS
);
978 if(isUserFolder(pathList
[0]))
979 err
=!createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_USER
),
980 itsFolders
[FOLDER_USER
].location
, false);
981 else if(isSysFolder(pathList
[0]))
982 err
=!createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_SYS
),
983 itsFolders
[FOLDER_SYS
].location
, true);
984 else if(isAllFolder(pathList
[0]))
985 err
=!createFolderUDSEntry(entry
, i18n(KFI_KIO_FONTS_ALL
),
986 itsFolders
[FOLDER_SYS
].location
, true);
989 error(KIO::ERR_SLAVE_DEFINED
,
990 i18n("Please specify \"%1\" or \"%2\".",
991 i18n(KFI_KIO_FONTS_USER
), i18n(KFI_KIO_FONTS_SYS
)));
996 err
=!createStatEntry(entry
, url
, getFolder(url
));
999 else if(!itsRoot
&& 1==url
.path(KUrl::RemoveTrailingSlash
)
1000 .split('/', QString::SkipEmptyParts
).count())
1003 // If a user (non-root) copies a font to fonts:/, kio_fonts will redirect to fonts:/Personal
1004 // If the font already exists in fonts:/Personal, konqueror will then do a stat on
1005 // fonts:/<filename> to get its file size in the "overwrite" dialog.
1008 // But, the font will not exist in fonts:/<filename> - so we need to see if it exists
1009 // in fonts:/Personal/<filename> in order to get the correct size. Otherwise konqueror, etc,
1014 modUrl
.setPath(QChar('/')+i18n(KFI_KIO_FONTS_USER
)+QChar('/')+url
.fileName());
1015 err
=!createStatEntry(entry
, modUrl
, FOLDER_USER
);
1019 error(KIO::ERR_SLAVE_DEFINED
, i18n("Please specify \"%1\" or \"%2\".",
1020 i18n(KFI_KIO_FONTS_USER
), i18n(KFI_KIO_FONTS_SYS
)));
1026 error(KIO::ERR_DOES_NOT_EXIST
, url
.prettyUrl());
1034 bool CKioFonts::createStatEntry(KIO::UDSEntry
&entry
, const KUrl
&url
, EFolder folder
)
1036 KFI_DBUG
<< url
.path();
1038 // First try to create stat entry without refreshing lists...
1039 bool ok
=createStatEntryReal(entry
, url
, folder
) && getSize(entry
)>0;
1041 // Hmm... well that failed, so refresh lists and try again!
1044 KFI_DBUG
<< "refresh font list";
1048 ok
=createStatEntryReal(entry
, url
, folder
) && getSize(entry
)>0;
1051 // Perhaps its not a valid font? Try to stat on location+name
1054 KFI_DBUG
<< "could not find";
1056 QStringList folders
;
1058 folders
.append(itsFolders
[folder
].location
);
1059 folders
.append(getDestFolder(itsFolders
[folder
].location
, url
.fileName()));
1061 QStringList::Iterator
it(folders
.begin()),
1064 for(; it
!=end
; ++it
)
1065 for(int t
=0; t
<3 && !ok
; ++t
)
1067 CDisabledFonts::TFileList files
;
1068 QString fileName
=0==t
1070 : 1==t
? modifyName(url
.fileName()) // lowercase
1071 : modifyName(url
.fileName(), true); // uppercase
1073 files
.append(CDisabledFonts::TFile((*it
)+fileName
));
1075 ok
=createFontUDSEntry(entry
, i18n("Invalid Font"), files
,
1076 KFI_NO_STYLE_INFO
, 0, FOLDER_SYS
==folder
,
1077 Misc::isHidden(url
)) && getSize(entry
)>0;
1087 bool CKioFonts::createStatEntryReal(KIO::UDSEntry
&entry
, const KUrl
&url
, EFolder folder
)
1089 KFI_DBUG
<< url
.path();
1091 TFontMap::Iterator it
=getMap(url
);
1093 if(it
!=itsFolders
[folder
].fontMap
.end())
1095 KFI_DBUG
<< "its a normal font";
1096 return createFontUDSEntry(entry
, it
.key(), it
.value().files
, it
.value().styleVal
,
1097 it
.value().writingSystems
, FOLDER_SYS
==folder
);
1100 KFI_DBUG
<< "try looking in disabled fonts";
1102 QString name
=Misc::getFile(removeMultipleExtension(url
));
1103 CDisabledFonts::TFontList::Iterator dIt
=itsFolders
[folder
].disabled
->find(name
,
1104 Misc::getIntQueryVal(url
, KFI_KIO_FACE
, 0));
1106 if(dIt
!=itsFolders
[folder
].disabled
->items().end())
1108 KFI_DBUG
<< "its a disabled font";
1109 return createFontUDSEntry(entry
, (*dIt
).getName(), (*dIt
).files
, (*dIt
).styleInfo
,
1110 (*dIt
).writingSystems
, FOLDER_SYS
==folder
, true);
1116 void CKioFonts::get(const KUrl
&url
)
1118 KFI_DBUG
<< url
.path() << " query:" << url
.query();
1120 bool thumb
="1"==metaData("thumbnail");
1121 CDisabledFonts::TFileList srcFiles
;
1123 // Any error will be logged in getSourceFiles
1124 if(updateFontList() && checkUrl(url
) && getSourceFiles(url
, srcFiles
))
1127 // The thumbnail job always donwloads non-local files to /tmp/... and passes this file name to
1128 // the thumbnail creator. However, in the case of fonts which are split among many files, this
1129 // wont work. Therefore, when the thumbnail code asks for the font to donwload, just return
1130 // the family and style info for enabled fonts, and the filename for disabled fonts. This way
1131 // the font-thumbnail creator can read this and just ask Xft/fontconfig for the font data.
1135 QTextStream
stream(&array
, QIODevice::WriteOnly
);
1136 EFolder
folder(getFolder(url
));
1137 TFontMap::Iterator
it(getMap(url
)),
1138 end(itsFolders
[folder
].fontMap
.end());
1140 emit
mimeType("text/plain");
1145 // OK, its a disabled font - if possible try to return the location of the font file
1147 QString
name(Misc::getFile(removeMultipleExtension(url
)));
1148 CDisabledFonts::TFontList::Iterator
dIt(itsFolders
[folder
].disabled
1149 ->find(name
, Misc::getIntQueryVal(url
,
1151 dEnd(itsFolders
[folder
].disabled
->items().end());
1156 CDisabledFonts::TFileList::ConstIterator
fIt((*dIt
).files
.begin()),
1157 fEnd((*dIt
).files
.end());
1159 for(; fIt
!=fEnd
; ++fIt
)
1160 if(isScalable((*fIt
).path
))
1162 KFI_DBUG
<< "hasMetaData(\"thumbnail\"), so return FILE: "
1163 << (*fIt
).path
<< " / " << (*fIt
).face
;
1164 stream
<< KFI_PATH_KEY
<< (*fIt
).path
<< endl
1165 << KFI_FACE_KEY
<< (*fIt
).face
<< endl
;
1173 KFI_DBUG
<< "hasMetaData(\"thumbnail\"), so return Url: " << url
;
1174 stream
<< url
.prettyUrl();
1179 KFI_DBUG
<< "hasMetaData(\"thumbnail\"), so return DETAILS: " << it
.key() << " / "
1182 stream
<< KFI_NAME_KEY
<< it
.key() << endl
1183 << KFI_STYLE_KEY
<< (*it
).styleVal
<< endl
;
1185 if(1==(*it
).files
.count())
1187 CDisabledFonts::TFileList::ConstIterator
fIt((*it
).files
.begin());
1189 stream
<< KFI_PATH_KEY
<< (*fIt
).path
<< endl
1190 << KFI_FACE_KEY
<< (*fIt
).face
<< endl
;
1194 totalSize(array
.size());
1196 processedSize(array
.size());
1198 processedSize(array
.size());
1200 KFI_DBUG
<< "Finished thumbnail...";
1205 KDE_struct_stat buff
;
1206 bool multiple
=false;
1208 if(1==srcFiles
.count())
1209 realPath
=srcFiles
.first().path
;
1210 else // Font is made up of multiple files - so create .zip of them all!
1212 KTemporaryFile tmpFile
;
1216 KZip
zip(tmpFile
.fileName());
1218 tmpFile
.setAutoRemove(false);
1219 realPath
=tmpFile
.fileName();
1221 if(zip
.open(QIODevice::WriteOnly
))
1223 QMap
<QString
, QString
> map
;
1225 getFontList(srcFiles
, map
);
1227 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
1231 // Iterate through created list, and add to zip archive
1232 // ...unhide any hidden files
1233 for(; fIt
!=fEnd
; ++fIt
)
1234 zip
.addLocalFile(fIt
.key(), Misc::unhide(fIt
.value()));
1242 QByteArray
realPathC(QFile::encodeName(realPath
));
1243 KFI_DBUG
<< "real: " << realPathC
;
1245 if (-2==KDE_stat(realPathC
.constData(), &buff
))
1246 error(EACCES
==errno
? KIO::ERR_ACCESS_DENIED
: KIO::ERR_DOES_NOT_EXIST
, url
.prettyUrl());
1247 else if (S_ISDIR(buff
.st_mode
))
1248 error(KIO::ERR_IS_DIRECTORY
, url
.prettyUrl());
1249 else if (!S_ISREG(buff
.st_mode
))
1250 error(KIO::ERR_CANNOT_OPEN_FOR_READING
, url
.prettyUrl());
1253 int fd
= KDE_open(realPathC
.constData(), O_RDONLY
);
1256 error(KIO::ERR_CANNOT_OPEN_FOR_READING
, url
.prettyUrl());
1259 // Determine the mimetype of the file to be retrieved, and emit it.
1260 // This is mandatory in all slaves (for KRun/BrowserRun to work).
1261 emit
mimeType(KMimeType::findByPath(realPathC
, buff
.st_mode
)->name());
1263 totalSize(buff
.st_size
);
1265 KIO::filesize_t processed
=0;
1266 char buffer
[MAX_IPC_SIZE
];
1271 int n
=::read(fd
, buffer
, MAX_IPC_SIZE
);
1278 error(KIO::ERR_COULD_NOT_READ
, url
.prettyUrl());
1281 ::unlink(realPathC
);
1287 array
=array
.fromRawData(buffer
, n
);
1292 processedSize(processed
);
1297 processedSize(buff
.st_size
);
1302 ::unlink(realPathC
);
1306 void CKioFonts::put(const KUrl
&u
, int mode
, KIO::JobFlags flags
)
1308 KFI_DBUG
<< u
.path() << " query:" << u
.query();
1310 if(Misc::isHidden(u
))
1312 error(KIO::ERR_SLAVE_DEFINED
, i18n("Cannot install %1\nHidden fonts cannot be "
1313 "installed.", u
.prettyUrl()));
1317 // updateFontList(); // CPD: don't update font list upon a put - it's too slow. Just stat on
1319 //checkUrl(u) // CPD: Don't need to check Url, as the call to "confirmUrl()" below will sort out
1326 bool nrs(nonRootSys(url
)),
1327 clearList(!hasMetaData(KFI_KIO_NO_CLEAR
));
1328 EFolder
destFolder(getFolder(url
));
1329 QString
destFolderReal(getDestFolder(itsFolders
[destFolder
].location
, url
.fileName())),
1330 dest(destFolderReal
+modifyName(url
.fileName()));
1331 QByteArray
destC(QFile::encodeName(dest
));
1332 KDE_struct_stat buffDest
;
1333 bool destExists(KDE_lstat(destC
.constData(), &buffDest
)!= -1);
1335 if (destExists
&& !(flags
& KIO::Overwrite
) && !(flags
& KIO::Resume
))
1337 error(KIO::ERR_FILE_ALREADY_EXIST
, url
.prettyUrl());
1341 if(nrs
&& !getRootPasswd()) // Need to check can get root passwd before start download...
1343 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
1348 // As we don't get passed a mime-type the following needs to happen:
1350 // 1. Download to a temporary file
1351 // 2. Check with FreeType that the file is a font, or that it is
1352 // an AFM or PFM file
1353 KTemporaryFile tmpFile
;
1354 QByteArray
tmpFileC(QFile::encodeName(tmpFile
.fileName()));
1356 tmpFile
.setAutoRemove(true);
1358 if(putReal(tmpFile
.fileName(), tmpFileC
, destExists
, mode
, flags
))
1360 EFileType
type(checkFile(tmpFile
.fileName(), u
)); // error logged in checkFile
1362 if(FILE_UNKNOWN
==type
)
1365 int timeout(reconfigTimeout());
1367 if(nrs
) // Ask root to move the tmp font...
1369 QList
<TCommand
> cmd
;
1370 TCommand
c(KFI::CMD_MOVE_FILE
);
1372 addCreateFolderCmd(itsFolders
[FOLDER_SYS
].location
, cmd
);
1373 if(destFolderReal
!=itsFolders
[FOLDER_SYS
].location
)
1374 addCreateFolderCmd(destFolderReal
, cmd
);
1376 c
.args
.append(tmpFile
.fileName());
1377 c
.args
.append(dest
);
1383 // Get root to move this to fonts folder...
1384 if(doRootCmd(cmd
, false)) // Already asked for passwd...
1386 tmpFile
.setAutoRemove(false);
1388 modified(timeout
, FOLDER_SYS
, clearList
, destFolderReal
);
1389 createAfm(dest
, true);
1393 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
1397 else // Move it to our font folder...
1399 tmpFile
.setAutoRemove(false);
1400 if(!Misc::dExists(destFolderReal
))
1401 Misc::createDir(destFolderReal
);
1402 if(0==::rename(tmpFileC
.constData(), destC
.constData()))
1404 Misc::setFilePerms(destC
);
1406 modified(timeout
, FOLDER_USER
, clearList
, destFolderReal
);
1411 error(KIO::ERR_SLAVE_DEFINED
, i18n("Could not access \"%1\" folder.",
1412 i18n(KFI_KIO_FONTS_USER
)));
1421 QString
CKioFonts::getUserName(uid_t uid
)
1423 if (!itsUserCache
.contains(uid
))
1425 struct passwd
*user
= getpwuid(uid
);
1427 itsUserCache
.insert(uid
, QString::fromLatin1(user
->pw_name
));
1429 return QString::number(uid
);
1431 return itsUserCache
[uid
];
1434 QString
CKioFonts::getGroupName(gid_t gid
)
1436 if (!itsGroupCache
.contains(gid
))
1438 struct group
*grp
= getgrgid(gid
);
1440 itsGroupCache
.insert(gid
, QString::fromLatin1(grp
->gr_name
));
1442 return QString::number(gid
);
1444 return itsGroupCache
[gid
];
1447 bool CKioFonts::createFontUDSEntry(KIO::UDSEntry
&entry
, const QString
&name
,
1448 const CDisabledFonts::TFileList
&patterns
,
1449 quint32 styleVal
, qulonglong writingSystems
,
1450 bool sys
, bool hidden
)
1452 //KFI_DBUG << "name:" << name << " style:" << styleVal << " #"
1453 // << patterns.count();
1456 // First of all get list of real files - i.e. remove any duplicates due to symlinks
1457 CDisabledFonts::TFileList files
;
1459 getFontFiles(patterns
, files
);
1461 CDisabledFonts::TFileList::ConstIterator
it(files
.begin()),
1467 // Sort list of files - placing scalable ones first. This is because, when determening the
1468 // mimetype, the 1st valid file will be chosen. In case of mixed bitmap/scalable - prefer
1470 CDisabledFonts::TFileList sorted
;
1472 for(; it
!=end
; ++it
)
1474 sorted
.prepend(*it
);
1483 entry
.insert(KIO::UDSEntry::UDS_SIZE
, getSize(files
));
1485 for(; it
!=end
; ++it
)
1487 QByteArray
cPath(QFile::encodeName(*it
));
1488 KDE_struct_stat buff
;
1490 if(-1!=KDE_lstat(cPath
, &buff
))
1492 if(0==writingSystems
)
1493 writingSystems
=toBit(QFontDatabase::Other
);
1495 entry
.insert(KIO::UDSEntry::UDS_NAME
, name
);
1496 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, buff
.st_mode
&S_IFMT
);
1497 entry
.insert(KIO::UDSEntry::UDS_ACCESS
, buff
.st_mode
&07777);
1498 entry
.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME
, buff
.st_mtime
);
1499 entry
.insert(KIO::UDSEntry::UDS_USER
, getUserName(buff
.st_uid
));
1500 entry
.insert(KIO::UDSEntry::UDS_GROUP
, getGroupName(buff
.st_gid
));
1501 entry
.insert(KIO::UDSEntry::UDS_ACCESS_TIME
, buff
.st_atime
);
1502 entry
.insert(KIO::UDSEntry::UDS_MIME_TYPE
, obtainMimeType(*it
));
1503 entry
.insert(UDS_EXTRA_FC_STYLE
, styleVal
);
1504 entry
.insert(UDS_EXTRA_WRITING_SYSTEMS
, writingSystems
);
1507 entry
.insert(KIO::UDSEntry::UDS_HIDDEN
, 1);
1509 entry
.insert(UDS_EXTRA_FILE_NAME
, (*it
).path
);
1510 entry
.insert(UDS_EXTRA_FOUNDRY
, (*it
).foundry
);
1512 entry
.insert(UDS_EXTRA_FILE_LIST
, files
.toString(true));
1514 QString
url(KFI_KIO_FONTS_PROTOCOL
+QString::fromLatin1(":/"));
1518 url
+=sys
? i18n(KFI_KIO_FONTS_SYS
) : i18n(KFI_KIO_FONTS_USER
);
1519 url
+=QString::fromLatin1("/");
1522 #ifdef KFI_KIO_ALL_URLS_HAVE_NAME
1523 addKnownExtension(url
, files
, name
, hidden
);
1529 url
+=name
+QString::fromLatin1(KFI_FONTS_PACKAGE
);
1532 url
+=Misc::getFile(*it
);
1535 if(files
.count()==1 && (*it
).face
>0)
1539 kUrl
.setQuery("?"KFI_KIO_FACE
"="+QString::number((*it
).face
));
1540 entry
.insert(KIO::UDSEntry::UDS_URL
, kUrl
.url());
1543 entry
.insert(KIO::UDSEntry::UDS_URL
, url
);
1545 return true; // This file was OK, so use its values...
1551 bool CKioFonts::createFolderUDSEntry(KIO::UDSEntry
&entry
, const QString
&name
,
1552 const QString
&path
, bool sys
)
1554 KFI_DBUG
<< "name:" << name
<< " path:" << path
<< " sys?:" << sys
;
1556 KDE_struct_stat buff
;
1557 QByteArray
cPath(QFile::encodeName(path
));
1561 if(-1!=KDE_lstat(cPath
, &buff
))
1563 entry
.insert(KIO::UDSEntry::UDS_NAME
, name
);
1565 if (S_ISLNK(buff
.st_mode
))
1567 KFI_DBUG
<< path
<< " is a link";
1570 int n
=readlink(cPath
, buffer2
, 1000);
1574 if(-1==KDE_stat(cPath
, &buff
))
1576 // It is a link pointing to nowhere
1577 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, S_IFMT
- 1);
1578 entry
.insert(KIO::UDSEntry::UDS_ACCESS
, S_IRWXU
| S_IRWXG
| S_IRWXO
);
1579 entry
.insert(KIO::UDSEntry::UDS_SIZE
, 0);
1582 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
); // CPD Treat links as regular folder...
1585 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, buff
.st_mode
&S_IFMT
);
1586 entry
.insert(KIO::UDSEntry::UDS_ACCESS
, buff
.st_mode
&07777);
1587 entry
.insert(KIO::UDSEntry::UDS_SIZE
, buff
.st_size
);
1590 entry
.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME
, buff
.st_mtime
);
1591 entry
.insert(KIO::UDSEntry::UDS_USER
, getUserName(buff
.st_uid
));
1592 entry
.insert(KIO::UDSEntry::UDS_GROUP
, getGroupName(buff
.st_gid
));
1593 entry
.insert(KIO::UDSEntry::UDS_ACCESS_TIME
, buff
.st_atime
);
1594 entry
.insert(KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1("inode/directory"));
1597 else if (sys
&& !Misc::root()) // Default system fonts folder does not actually exist yet!
1599 KFI_DBUG
<< "Default system folder (" << path
1600 << ") does not yet exist, so create dummy entry";
1601 entry
.insert(KIO::UDSEntry::UDS_NAME
, name
);
1602 entry
.insert(KIO::UDSEntry::UDS_FILE_TYPE
, S_IFDIR
);
1603 entry
.insert(KIO::UDSEntry::UDS_ACCESS
, 0744);
1604 entry
.insert(KIO::UDSEntry::UDS_USER
, QString::fromLatin1("root"));
1605 entry
.insert(KIO::UDSEntry::UDS_GROUP
, QString::fromLatin1("root"));
1606 entry
.insert(KIO::UDSEntry::UDS_MIME_TYPE
, QString::fromLatin1("inode/directory"));
1613 bool CKioFonts::putReal(const QString
&destOrig
, const QByteArray
&destOrigC
, bool origExists
,
1614 int mode
, KIO::JobFlags flags
)
1616 bool markPartial
=config()->readEntry("MarkPartial", true);
1621 QString
destPart(destOrig
+QString::fromLatin1(".part"));
1622 QByteArray
destPartC(QFile::encodeName(destPart
));
1626 KDE_struct_stat buffPart
;
1627 bool partExists
=(-1!=KDE_stat(destPartC
.constData(), &buffPart
));
1629 if (partExists
&& !(flags
& KIO::Resume
) && buffPart
.st_size
>0)
1631 // Maybe we can use this partial file for resuming
1632 // Tell about the size we have, and the app will tell us
1633 // if it's ok to resume or not.
1634 flags
|=canResume(buffPart
.st_size
) ? KIO::Resume
: KIO::DefaultFlags
;
1636 if (!(flags
& KIO::Resume
))
1637 if (!::remove(destPartC
.constData()))
1641 error(KIO::ERR_CANNOT_DELETE_PARTIAL
, destPart
);
1649 if (origExists
&& !(flags
& KIO::Resume
))
1650 ::remove(destOrigC
.constData());
1651 // Catch errors when we try to open the file.
1654 QByteArray
destC(QFile::encodeName(dest
));
1658 if (flags
& KIO::Resume
)
1660 fd
= KDE_open(destC
.constData(), O_RDWR
); // append if resuming
1661 KDE_lseek(fd
, 0, SEEK_END
); // Seek to end
1665 // WABA: Make sure that we keep writing permissions ourselves,
1666 // otherwise we can be in for a surprise on NFS.
1667 fd
= KDE_open(destC
.constData(), O_CREAT
| O_TRUNC
| O_WRONLY
,
1668 -1==mode
? 0666: mode
| S_IWUSR
| S_IRUSR
);
1673 error(EACCES
==errno
? KIO::ERR_WRITE_ACCESS_DENIED
: KIO::ERR_CANNOT_OPEN_FOR_WRITING
, dest
);
1678 // Loop until we got 0 (end of data)
1683 dataReq(); // Request for data
1684 result
= readData(buffer
);
1685 if(result
> 0 && !writeAll(fd
, buffer
.constData(), buffer
.size()))
1687 if(ENOSPC
==errno
) // disk full
1689 error(KIO::ERR_DISK_FULL
, destOrig
);
1690 result
= -2; // means: remove dest file
1694 error(KIO::ERR_COULD_NOT_WRITE
, destOrig
);
1705 ::remove(destC
.constData());
1706 else if (markPartial
)
1708 KDE_struct_stat buff
;
1710 if ((-1==KDE_stat(destC
.constData(), &buff
)) ||
1711 (buff
.st_size
<config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE
)))
1712 ::remove(destC
.constData());
1717 if (-1==fd
) // we got nothing to write out, so we never opened the file
1725 error(KIO::ERR_COULD_NOT_WRITE
, destOrig
);
1729 // after full download rename the file back to original name
1730 if (markPartial
&& ::rename(destC
.constData(), destOrigC
.constData()))
1732 error(KIO::ERR_CANNOT_RENAME_PARTIAL
, destOrig
);
1739 void CKioFonts::copy(const KUrl
&src
, const KUrl
&d
, int mode
, KIO::JobFlags flags
)
1743 // Copying to fonts:/
1744 // Copying from fonts:/ and file:/
1746 KFI_DBUG
<< src
.prettyUrl() << " query:" << src
.query() << " - "
1747 << d
.prettyUrl() << " query:" << d
.query();
1749 if(Misc::isHidden(d
))
1751 error(KIO::ERR_SLAVE_DEFINED
,
1752 i18n("Cannot copy %1 to %2\nHidden/disabled fonts cannot be installed.",
1753 src
.prettyUrl(), d
.prettyUrl()));
1757 bool fromFonts
=KFI_KIO_FONTS_PROTOCOL
==src
.protocol();
1759 // CPD: don't update font list upon a copy from file - it's too slow. Just stat on filename!
1760 if(!fromFonts
|| updateFontList() && checkUrl(src
) && checkAllowed(src
))
1762 //checkUrl(u) // CPD as per comment in ::put()
1764 CDisabledFonts::TFileList srcFiles
;
1765 int timeout(reconfigTimeout());
1767 if(getSourceFiles(src
, srcFiles
)) // Any error will be logged in getSourceFiles
1773 bool metrics(fromFonts
? false : Misc::isMetrics(src
.fileName())),
1774 clearList(!hasMetaData(KFI_KIO_NO_CLEAR
));
1775 EFolder
destFolder(getFolder(dest
));
1776 QMap
<QString
, QString
> map
;
1779 map
[src
.path()]=src
.fileName();
1781 // As above, if copying from file, then only stat on dest filename, but if from fonts to
1782 // fonts need to get the list of possible source files, etc.
1783 if(fromFonts
? confirmMultiple(src
, srcFiles
,
1784 FOLDER_SYS
==destFolder
? FOLDER_USER
: FOLDER_SYS
, OP_COPY
) &&
1785 getFontList(srcFiles
, map
) &&
1786 checkDestFiles(src
, map
, dest
, destFolder
, flags
)
1787 : checkDestFile(src
, dest
, destFolder
, flags
) )
1789 if(nonRootSys(dest
))
1791 QList
<TCommand
> cmd
;
1793 CDirList addedFolders
;
1794 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
1797 for(; fIt
!=fEnd
; ++fIt
)
1799 TCommand
c(KFI::CMD_COPY_FILE
);
1800 QString
destFolderReal(getDestFolder(itsFolders
[destFolder
].location
,
1801 Misc::getFile(*fIt
)));
1803 if(!addedFolders
.contains(itsFolders
[FOLDER_SYS
].location
) &&
1804 addCreateFolderCmd(itsFolders
[FOLDER_SYS
].location
, cmd
))
1805 addedFolders
.add(itsFolders
[FOLDER_SYS
].location
);
1807 if(!addedFolders
.contains(destFolderReal
) &&
1808 addCreateFolderCmd(destFolderReal
, cmd
))
1809 addedFolders
.add(destFolderReal
);
1811 c
.args
.append(fIt
.key());
1812 c
.args
.append(destFolderReal
+modifyName(fIt
.value()));
1815 int s
=getSize(QFile::encodeName(fIt
.key()));
1822 if(doRootCmd(cmd
, true))
1825 modified(timeout
, destFolder
, clearList
, addedFolders
);
1826 processedSize(size
);
1827 if(src
.isLocalFile() && 1==srcFiles
.count())
1828 createAfm(itsFolders
[destFolder
].location
+modifyName(map
.begin().value()), true);
1832 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
1838 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
1840 QString destFolderReal
;
1842 for(; fIt
!=fEnd
; ++fIt
)
1844 destFolderReal
=getDestFolder(itsFolders
[destFolder
].location
,
1845 Misc::getFile(*fIt
));
1847 QByteArray
realSrc(QFile::encodeName(fIt
.key())),
1848 realDest(QFile::encodeName(destFolderReal
+
1849 modifyName(fIt
.value())));
1850 KDE_struct_stat buffSrc
;
1852 if(-1==KDE_stat(realSrc
.constData(), &buffSrc
))
1854 error(EACCES
==errno
? KIO::ERR_ACCESS_DENIED
: KIO::ERR_DOES_NOT_EXIST
,
1859 int srcFd
=KDE_open(realSrc
.constData(), O_RDONLY
);
1863 error(KIO::ERR_CANNOT_OPEN_FOR_READING
, src
.prettyUrl());
1867 if(!Misc::dExists(destFolderReal
))
1868 Misc::createDir(destFolderReal
);
1870 // WABA: Make sure that we keep writing permissions ourselves,
1871 // otherwise we can be in for a surprise on NFS.
1872 int destFd
=KDE_open(realDest
.constData(), O_CREAT
| O_TRUNC
| O_WRONLY
,
1873 -1==mode
? 0666 : mode
| S_IWUSR
);
1878 ? KIO::ERR_WRITE_ACCESS_DENIED
1879 : KIO::ERR_CANNOT_OPEN_FOR_WRITING
, dest
.prettyUrl());
1884 totalSize(buffSrc
.st_size
);
1886 KIO::filesize_t processed
= 0;
1887 char buffer
[MAX_IPC_SIZE
];
1892 int n
=::read(srcFd
, buffer
, MAX_IPC_SIZE
);
1896 error(KIO::ERR_COULD_NOT_READ
, src
.prettyUrl());
1904 if(!writeAll(destFd
, buffer
, n
))
1908 if (ENOSPC
==errno
) // disk full
1910 error(KIO::ERR_DISK_FULL
, dest
.prettyUrl());
1911 remove(realDest
.constData());
1914 error(KIO::ERR_COULD_NOT_WRITE
, dest
.prettyUrl());
1919 processedSize(processed
);
1926 error(KIO::ERR_COULD_NOT_WRITE
, dest
.prettyUrl());
1930 Misc::setFilePerms(realDest
);
1932 // copy access and modification time
1935 ut
.actime
= buffSrc
.st_atime
;
1936 ut
.modtime
= buffSrc
.st_mtime
;
1937 ::utime(realDest
.constData(), &ut
);
1939 processedSize(buffSrc
.st_size
);
1941 modified(timeout
, destFolder
, clearList
, destFolderReal
);
1944 if(src
.isLocalFile() && 1==srcFiles
.count())
1945 createAfm(destFolderReal
+modifyName(map
.begin().value()));
1954 void CKioFonts::rename(const KUrl
&src
, const KUrl
&d
, KIO::JobFlags flags
)
1956 KFI_DBUG
<< src
.prettyUrl() << " query:" << src
.query() << " - "
1957 << d
.prettyUrl() << " query:" << d
.query() << ", " << (flags
& KIO::Overwrite
);
1959 int timeout(reconfigTimeout());
1961 if(src
.directory()==d
.directory())
1963 if(!itsRoot
&& "/"==src
.directory())
1965 error(KIO::ERR_SLAVE_DEFINED
, i18n("You cannot rename font folders"));
1969 CDisabledFonts::TFontList::Iterator disabledIt
;
1970 TFontMap::Iterator enabledIt
;
1971 const CDisabledFonts::TFileList
*entries(getEntries(src
, enabledIt
, disabledIt
));
1975 KFI_DBUG
<< "No entries found, updating font list antry again...";
1977 entries
=getEntries(src
, enabledIt
, disabledIt
);
1982 QString
destFile(Misc::getFile(d
.path())),
1983 srcFile(Misc::getFile(src
.path())),
1984 destEn(destFile
.mid(1)),
1985 srcEn(srcFile
.mid(1));
1986 EFolder
folder(getFolder(d
));
1987 QString
srcName(Misc::getFile(removeMultipleExtension(src
)));
1988 bool clearList(!hasMetaData(KFI_KIO_NO_CLEAR
)),
1989 nrs(nonRootSys(src
)),
1990 enable(Misc::isHidden(srcFile
) && !Misc::isHidden(destFile
) && srcEn
==destFile
),
1991 disable(!Misc::isHidden(srcFile
) && Misc::isHidden(destFile
) &&
1994 if(enable
&& disabledIt
!=itsFolders
[folder
].disabled
->items().end())
1996 if(confirmMultiple(src
, (*disabledIt
).files
, folder
, OP_ENABLE
))
1999 CDisabledFonts::TFileList::ConstIterator
it((*disabledIt
).files
.begin()),
2000 end((*disabledIt
).files
.end());
2003 for(; it
!=end
; ++it
)
2004 folders
.add(Misc::getDir(*it
));
2008 TCommand
c(KFI::CMD_ENABLE_FONT
);
2010 c
.args
.append((*disabledIt
).family
);
2011 c
.args
.append((int)(*disabledIt
).styleInfo
);
2015 ok
=itsFolders
[folder
].disabled
->enable(disabledIt
);
2019 modified(timeout
, folder
, clearList
, folders
);
2024 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2026 error(KIO::ERR_DOES_NOT_EXIST
, src
.prettyUrl());
2030 else if (disable
&& disabledIt
==itsFolders
[folder
].disabled
->items().end())
2032 if(confirmMultiple(src
, (*enabledIt
).files
, folder
, OP_DISABLE
))
2035 QMap
<int, QString
> names
;
2036 CDisabledFonts::TFileList::ConstIterator
it((*enabledIt
).files
.begin()),
2037 end((*enabledIt
).files
.end());
2040 for(; it
!=end
; ++it
)
2041 folders
.add(Misc::getDir(*it
));
2044 // If there is only 1 file mapped to this fontname, see if this file maps
2045 // to multiple font names - as would be the case in a TTC file...
2046 if(1==(*enabledIt
).files
.count())
2047 names
=getFontIndexToNameEntries(folder
, (*((*enabledIt
).files
.begin())).path
);
2049 if(0==names
.count())
2050 names
[0]=enabledIt
.key(); // Multiple files -> cant use index :-(
2052 QMap
<int, QString
>::ConstIterator
nameIt(names
.begin()),
2053 nameEnd(names
.end());
2055 for(; nameIt
!=nameEnd
; ++nameIt
)
2058 TCommand
c(KFI::CMD_DISABLE_FONT
);
2060 c
.args
.append(getFamily(enabledIt
.key()));
2061 c
.args
.append((int)(*enabledIt
).styleVal
);
2062 c
.args
.append((*enabledIt
).writingSystems
);
2063 c
.args
.append((int)(nameIt
.key()));
2064 c
.args
.append((*enabledIt
).files
.count());
2065 for(it
=(*enabledIt
).files
.begin(); it
!=end
; ++it
)
2067 c
.args
.append((*it
).path
);
2068 c
.args
.append((*it
).foundry
);
2074 QString
fontStr(*nameIt
);
2075 int commaPos
=fontStr
.indexOf(',');
2076 CDisabledFonts::TFont
font(-1==commaPos
2078 : fontStr
.left(commaPos
),
2079 (*enabledIt
).styleVal
,
2080 (*enabledIt
).writingSystems
);
2082 font
.files
=(*enabledIt
).files
;
2083 if(1==font
.files
.count())
2084 (*(font
.files
.begin())).face
=nameIt
.key();
2085 ok
=itsFolders
[folder
].disabled
->disable(font
);
2090 modified(timeout
, folder
, clearList
, folders
);
2095 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2097 error(KIO::ERR_DOES_NOT_EXIST
, src
.prettyUrl());
2100 error(KIO::ERR_SLAVE_DEFINED
, i18n("Sorry, internal error - could not find font."));
2103 else if(enable
|| disable
)
2104 error(KIO::ERR_SLAVE_DEFINED
, enable
2105 ? i18n("Could not enable %1\n"
2106 "An enabled font already exists, please delete the disabled one.",
2108 : i18n("Could not disable %1\n"
2109 "A disabled font already exists, please delete the enabled one.",
2112 error(KIO::ERR_SLAVE_DEFINED
, i18n("Sorry, fonts cannot be renamed."));
2116 error(KIO::ERR_DOES_NOT_EXIST
, src
.prettyUrl());
2119 else if(itsRoot
) // Should never happen...
2121 error(KIO::ERR_UNSUPPORTED_ACTION
, unsupportedActionErrorString(mProtocol
, KIO::CMD_RENAME
));
2124 else if(Misc::isHidden(src
) || Misc::isHidden(d
))
2126 error(KIO::ERR_SLAVE_DEFINED
, i18n("Cannot move %1 to %2\nDisabled fonts cannot be moved.",
2127 src
.prettyUrl(), d
.prettyUrl()));
2133 // Can't rename from/to file:/ -> therefore rename can only be from fonts:/System to
2134 // fonts:/Personal, or vice versa.
2135 CDisabledFonts::TFileList srcFiles
;
2137 if(getSourceFiles(src
, srcFiles
)) // Any error will be logged in getSourceFiles
2143 EFolder
destFolder(getFolder(dest
));
2144 QMap
<QString
, QString
> map
;
2146 if(confirmMultiple(src
, srcFiles
, FOLDER_SYS
==destFolder
? FOLDER_USER
: FOLDER_SYS
, OP_MOVE
) &&
2147 getFontList(srcFiles
, map
) && checkDestFiles(src
, map
, dest
, destFolder
, flags
))
2149 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
2151 bool askPasswd
=true,
2152 toSys
=FOLDER_SYS
==destFolder
;
2154 for(; fIt
!=fEnd
; ++fIt
)
2156 QString
destFolderReal(getDestFolder(itsFolders
[destFolder
].location
, fIt
.value()));
2157 QList
<TCommand
> cmd
;
2158 TCommand
c(KFI::CMD_MOVE_FILE
);
2162 addCreateFolderCmd(itsFolders
[FOLDER_SYS
].location
, cmd
);
2163 if(destFolderReal
!=itsFolders
[FOLDER_SYS
].location
)
2164 addCreateFolderCmd(destFolderReal
, cmd
);
2167 c
.args
.append(fIt
.key());
2168 c
.args
.append(destFolderReal
+fIt
.value());
2169 c
.args
.append((int)(toSys
? 0 : getuid()));
2170 c
.args
.append((int)(toSys
? 0 : getgid()));
2176 if(FOLDER_SYS
==destFolder
)
2178 sysDir
=destFolderReal
;
2179 userDir
=Misc::getDir(fIt
.key());
2183 userDir
=destFolderReal
;
2184 sysDir
=Misc::getDir(fIt
.key());
2187 if(doRootCmd(cmd
, askPasswd
))
2189 modified(timeout
, FOLDER_SYS
, true, sysDir
);
2190 modified(timeout
, FOLDER_USER
, true, userDir
);
2191 askPasswd
=false; // Don't keep on asking for password...
2195 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2205 void CKioFonts::del(const KUrl
&url
, bool)
2207 KFI_DBUG
<< url
.path() << " query:" << url
.query();
2209 const CDisabledFonts::TFileList
*entries
;
2210 CDisabledFonts::TFontList::Iterator disabledIt
;
2211 TFontMap::Iterator enabledIt
;
2213 if(checkUrl(url
) && checkAllowed(url
) &&
2214 (( (entries
=getEntries(url
, enabledIt
, disabledIt
)) && entries
->count() && checkFiles(*entries
)) ||
2215 ( updateFontList() && (entries
=getEntries(url
, enabledIt
, disabledIt
)) && entries
->count() &&
2216 checkFiles(*entries
))) && confirmMultiple(url
, entries
, getFolder(url
), OP_DELETE
))
2218 CDisabledFonts::TFileList::ConstIterator it
,
2219 end(entries
->end());
2220 CDirList modifiedDirs
;
2221 bool clearList(!hasMetaData(KFI_KIO_NO_CLEAR
));
2222 int timeout(reconfigTimeout());
2226 if(disabledIt
!=itsFolders
[FOLDER_SYS
].disabled
->items().end())
2228 TCommand
c(KFI::CMD_DELETE_DISABLED_FONT
);
2230 c
.args
.append((*disabledIt
).family
);
2231 c
.args
.append((int)(*disabledIt
).styleInfo
);
2234 itsFolders
[FOLDER_SYS
].disabled
->refresh();
2237 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2243 QList
<TCommand
> cmd
;
2245 for(it
=entries
->begin(); it
!=end
; ++it
)
2247 modifiedDirs
.add(Misc::getDir(*it
));
2248 cmd
.append(TCommand(KFI::CMD_DELETE_FILE
, (*it
).path
));
2252 Misc::getAssociatedFiles(*it
, files
);
2256 QStringList::Iterator fIt
,
2259 for(fIt
=files
.begin(); fIt
!=fEnd
; ++fIt
)
2260 cmd
.append(TCommand(KFI::CMD_DELETE_FILE
, *fIt
));
2265 modified(timeout
, FOLDER_SYS
, clearList
, modifiedDirs
);
2268 error(KIO::ERR_ACCESS_DENIED
, KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
);
2275 for(it
=entries
->begin(); it
!=end
; ++it
)
2277 if (0!=unlink(QFile::encodeName(*it
).constData()))
2278 error(EACCES
==errno
|| EPERM
==errno
2279 ? KIO::ERR_ACCESS_DENIED
2281 ? KIO::ERR_IS_DIRECTORY
2282 : KIO::ERR_CANNOT_DELETE
,
2286 modifiedDirs
.add(Misc::getDir(*it
));
2290 Misc::getAssociatedFiles(*it
, files
);
2294 QStringList::Iterator fIt
,
2297 for(fIt
=files
.begin(); fIt
!=fEnd
; ++fIt
)
2298 unlink(QFile::encodeName(*fIt
).constData());
2303 if(disabledIt
!=itsFolders
[itsRoot
? FOLDER_SYS
: FOLDER_USER
].disabled
->items().end())
2305 itsFolders
[itsRoot
? FOLDER_SYS
: FOLDER_USER
].disabled
->remove(disabledIt
);
2306 itsFolders
[itsRoot
? FOLDER_SYS
: FOLDER_USER
].disabled
->refresh();
2309 modified(timeout
, itsRoot
? FOLDER_SYS
: FOLDER_USER
, clearList
, modifiedDirs
);
2313 else if(isATtc(QFile::encodeName(url
.fileName())))
2316 error(KIO::ERR_SLAVE_DEFINED
, i18n("Could not access \"%1\".", url
.prettyUrl()));
2319 void CKioFonts::modified(int timeout
, EFolder folder
, bool clearList
, const CDirList
&dirs
)
2321 KFI_DBUG
<< "timout:" << timeout
<< " folder:" << (int)folder
<< " clearList:" << clearList
;
2323 if(FOLDER_SYS
!=folder
|| itsRoot
)
2327 CDirList::ConstIterator
it(dirs
.begin()),
2330 for(; it
!=end
; ++it
)
2331 itsFolders
[folder
].modified
.add(*it
);
2334 itsFolders
[folder
].modified
.add(itsFolders
[folder
].location
);
2335 setTimeoutSpecialCommand(timeout
? timeout
: -1);
2339 clearFontList(); // List of fonts has changed.../
2342 void CKioFonts::special(const QByteArray
&a
)
2348 QDataStream
stream(a
);
2355 case SPECIAL_RESCAN
:
2360 case SPECIAL_CONFIGURE
:
2369 itsFolders
[FOLDER_SYS
].disabled
->reload();
2370 if(0==itsFolders
[FOLDER_SYS
].modified
.count())
2371 configure(FOLDER_SYS
);
2380 if(url
.isEmpty() || !url
.isValid())
2383 QString
sect(getSect(url
.path()));
2385 if(isSysFolder(sect
))
2387 itsFolders
[FOLDER_SYS
].disabled
->reload();
2388 if(0==itsFolders
[FOLDER_SYS
].modified
.count())
2389 configure(FOLDER_SYS
);
2391 else if(isUserFolder(sect
))
2393 itsFolders
[FOLDER_USER
].disabled
->reload();
2394 if(0==itsFolders
[FOLDER_USER
].modified
.count())
2395 configure(FOLDER_USER
);
2399 if(itsFolders
[FOLDER_USER
].disabled
->modified())
2400 itsFolders
[FOLDER_USER
].disabled
->reload();
2408 error(KIO::ERR_UNSUPPORTED_ACTION
, QString::number(cmd
));
2415 bool CKioFonts::configure(EFolder folder
)
2417 bool refreshX(false);
2419 if(!itsRoot
&& FOLDER_SYS
==folder
)
2421 QList
<TCommand
> cmd
;
2425 itsAddToSysFc
=false;
2426 cmd
.append(TCommand(KFI::CMD_ADD_DIR_TO_FONTCONFIG
, itsFolders
[FOLDER_SYS
].location
));
2429 if(itsFolders
[FOLDER_SYS
].modified
.count())
2431 CDirList::ConstIterator
it(itsFolders
[FOLDER_SYS
].modified
.begin()),
2432 end(itsFolders
[FOLDER_SYS
].modified
.end());
2434 for(; it
!=end
; ++it
)
2435 if(Misc::fExists((*it
)+"fonts.dir"))
2437 cmd
.append(TCommand(KFI::CMD_CFG_DIR_FOR_X
, *it
));
2442 cmd
.append(TCommand(KFI::CMD_FC_CACHE
));
2443 doRootCmd(cmd
, false);
2447 Misc::doCmd(FC_CACHE_CMD
);
2448 KFI_DBUG
<< "RUN: " << FC_CACHE_CMD
;
2450 itsFolders
[folder
].disabled
->save();
2452 CDirList::ConstIterator
it(itsFolders
[folder
].modified
.begin()),
2453 end(itsFolders
[folder
].modified
.end());
2455 for(; it
!=end
; ++it
)
2456 if(Misc::fExists((*it
)+"fonts.dir"))
2458 Misc::configureForX11(*it
);
2465 void CKioFonts::doModified()
2468 bool refreshX(false),
2471 infoMessage(i18n("Configuring installed fonts..."));
2472 setTimeoutSpecialCommand(-1); // Cancel timer
2474 if(itsFolders
[FOLDER_SYS
].modified
.count())
2476 refreshX
=configure(FOLDER_SYS
);
2477 itsFolders
[FOLDER_SYS
].modified
.clear();
2481 if(!itsRoot
&& itsFolders
[FOLDER_USER
].modified
.count())
2483 refreshX
=configure(FOLDER_USER
);
2484 itsFolders
[FOLDER_USER
].modified
.clear();
2491 Misc::doCmd("xset", "fp", "rehash");
2492 infoMessage(QString());
2493 KFI_DBUG
<< "finished";
2496 bool CKioFonts::getRootPasswd(bool askPasswd
)
2500 if(hasMetaData(KFI_KIO_PASS
))
2502 itsPasswd
=metaData(KFI_KIO_PASS
);
2503 return !itsPasswd
.isEmpty();
2507 return !itsPasswd
.isEmpty();
2509 KIO::AuthInfo authInfo
;
2510 SuProcess
proc(KFI_SYS_USER
);
2515 authInfo
.url
=KUrl(KFI_KIO_FONTS_PROTOCOL
":/"KFI_KIO_FONTS_SYS
"/");
2516 authInfo
.keepPassword
=false;
2517 authInfo
.caption
=i18n("Authorisation Required");
2518 authInfo
.username
=i18n(KFI_AUTHINF_USER
);
2520 if(proc
.useUsersOwnPassword())
2521 authInfo
.prompt
=i18n("The requested action requires administrator privileges.\n"
2522 "If you have these privileges, then please enter your password.");
2524 authInfo
.prompt
=i18n("The requested action requires administrator privileges.\n"
2525 "Please enter the system administrator's password.");
2527 if(!checkCachedAuthentication(authInfo
) && !askPasswd
)
2528 authInfo
.password
=itsPasswd
;
2532 while(!error
&& 0!=proc
.checkInstall(authInfo
.password
.toLocal8Bit()))
2534 KFI_DBUG
<< "ATTEMPT : " << attempts
;
2536 errorMsg
=i18n("Incorrect password.\n");
2537 if(attempts
>2 || !openPasswordDialog(authInfo
, errorMsg
))
2540 if(!error
&& authInfo
.keepPassword
)
2541 cacheAuthentication(authInfo
);
2544 error
=proc
.checkInstall(authInfo
.password
.toLocal8Bit()) ? true : false;
2546 itsPasswd
= error
? QString() : authInfo
.password
;
2547 return !itsPasswd
.isEmpty();
2550 void CKioFonts::quitHelper()
2552 if(itsServer
.isOpen() && itsSuProc
&& itsSocket
&& itsSuProc
->isRunning())
2555 if(itsSocket
->write(QVariant((int)KFI::CMD_QUIT
)))
2558 if(itsSocket
->read(res
, 10) && res
)
2560 itsSuProc
->terminate();
2561 itsSuProc
->wait(100);
2567 bool CKioFonts::doRootCmd(QList
<TCommand
> &cmd
, bool askPasswd
)
2571 if(cmd
.count() && getRootPasswd(askPasswd
))
2573 if(!itsServer
.isOpen())
2575 KFI_DBUG
<< "Open server socket";
2576 // Open socket for communication with helper app...
2580 if(itsServer
.isOpen())
2582 if(itsSuProc
&& !itsSuProc
->isRunning())
2584 KFI_DBUG
<< "Delete client socket";
2593 // Start helper app...
2594 KFI_DBUG
<< "Start helper...";
2595 itsSuProc
=new CSuProc(itsServer
.name(), itsPasswd
);
2601 // Wait for helper app to connect...
2602 KFI_DBUG
<< "Wait for client...";
2603 itsSocket
=itsServer
.waitForClient();
2608 // Write commands to helper, and wait for replies...
2609 QList
<TCommand
>::ConstIterator
it(cmd
.begin()),
2611 bool commsError(false);
2613 for(; it
!=end
&& !commsError
; ++it
)
2615 KFI_DBUG
<< "Send command #" << (*it
).cmd
;
2617 if(itsSocket
->write(QVariant((int)(*it
).cmd
)))
2619 QList
<QVariant
>::ConstIterator
argIt((*it
).args
.begin()),
2620 argEnd((*it
).args
.end());
2622 for(; argIt
!=argEnd
&& !commsError
; ++argIt
)
2623 if(!itsSocket
->write(*argIt
))
2625 KFI_DBUG
<< "Failed to write arg";
2629 if(!commsError
) // Wait for response!
2633 if(itsSocket
->read(res
, CMD_FC_CACHE
==(*it
).cmd
||
2634 CMD_CFG_DIR_FOR_X
==(*it
).cmd
2635 ? 600 // fc-cache can take a *long* time...
2639 CMD_ADD_DIR_TO_FONTCONFIG
!=(*it
).cmd
&&
2640 CMD_CFG_DIR_FOR_X
!=(*it
).cmd
)
2642 KFI_DBUG
<< "Command failed :-(";
2648 KFI_DBUG
<< "Failed to read response";
2655 KFI_DBUG
<< "Failed to write command id";
2666 KFI_DBUG
<< "No socket connection :-(";
2673 bool CKioFonts::doRootCmd(const TCommand
&cmd
, bool askPasswd
)
2675 QList
<TCommand
> cmds
;
2678 return doRootCmd(cmds
, askPasswd
);
2681 void CKioFonts::correctUrl(KUrl
&url
)
2683 KFI_DBUG
<< url
.path();
2686 QString
sect(getSect(url
.path()));
2688 if(!isSysFolder(sect
) && !isUserFolder(sect
))
2690 url
.setPath(QChar('/')+i18n(KFI_KIO_FONTS_USER
)+QChar('/')+url
.fileName());
2691 KFI_DBUG
<< "Changed URL to:" << url
.path();
2696 void CKioFonts::clearFontList()
2701 FcFontSetDestroy(itsFontList
);
2704 itsFolders
[FOLDER_SYS
].fontMap
.clear();
2706 itsFolders
[FOLDER_USER
].fontMap
.clear();
2709 bool CKioFonts::updateFontList()
2713 // For some reason just the "!FcConfigUptoDate(0)" check does not always work :-(
2714 if(0!=itsLastFcCheckTime
&&
2715 (!itsFontList
|| !FcConfigUptoDate(0) ||
2716 (abs(time(NULL
)-itsLastFcCheckTime
)>constMaxFcCheckTime
)))
2718 KFI_DBUG
<< "itsFontList:" << (intptr_t)itsFontList
2719 << " FcConfigUptoDate:" << (int)FcConfigUptoDate(0)
2720 << " time diff:" << abs(time(NULL
)-itsLastFcCheckTime
)
2721 << " max:" << constMaxFcCheckTime
;
2722 FcInitReinitialize();
2728 if(itsServer
.isOpen() && itsSuProc
&& itsSocket
)
2729 doRootCmd(TCommand(KFI::CMD_RELOAD_DISABLED_LIST
), false);
2730 itsFolders
[FOLDER_USER
].disabled
->refresh();
2732 itsFolders
[FOLDER_SYS
].disabled
->refresh();
2736 KFI_DBUG
<< "update list of fonts";
2738 itsLastFcCheckTime
=time(NULL
);
2740 FcPattern
*pat
= FcPatternCreate();
2741 FcObjectSet
*os
= FcObjectSetBuild(FC_FILE
, FC_FAMILY
,
2742 #ifdef KFI_USE_TRANSLATED_FAMILY_NAME
2745 FC_WEIGHT
, FC_LANG
, FC_CHARSET
,
2747 #ifndef KFI_FC_NO_WIDTHS
2750 FC_SLANT
, FC_INDEX
, FC_FOUNDRY
, (void*)0);
2752 itsFontList
=FcFontList(0, pat
, os
);
2754 FcPatternDestroy(pat
);
2755 FcObjectSetDestroy(os
);
2760 // defoma (DEbian FOnt MAnanager) installs sym links into /var/lib/defoma/fontconfig.d, but also
2761 // places this folder into fontconfigs search path. Leading to duplicate font files. Therefore, just
2762 // ignore defoma's sym links...
2763 // -> Can't just ignore these, as if a font is disabled fontconfig will still list it, as it sees the symlink
2764 //static const char * constDefomaLocation="/var/lib/defoma/fontconfig.d";
2766 QString
home(Misc::dirSyntax(QDir::homePath()));
2768 for (int i
= 0; i
< itsFontList
->nfont
; i
++)
2770 EFolder folder
=FOLDER_SYS
;
2771 QString
fileName(Misc::fileSyntax(FC::getFcString(itsFontList
->fonts
[i
], FC_FILE
)));
2773 if(!fileName
.isEmpty()) // && 0!=fileName.indexOf(constDefomaLocation))
2776 foundry(FC::getFcString(itsFontList
->fonts
[i
], FC_FOUNDRY
));
2780 if(!itsRoot
&& 0==fileName
.indexOf(home
))
2783 FC::getDetails(itsFontList
->fonts
[i
], name
, styleVal
, index
);
2785 TFontDetails
&details
=itsFolders
[folder
].fontMap
[name
];
2788 details
.styleVal
=styleVal
;
2789 details
.writingSystems
|=getWritingSystems(itsFontList
->fonts
[i
]);
2791 if(details
.files
.count()) // Check for duplicates...
2793 CDisabledFonts::TFileList::Iterator it
,
2794 end
=details
.files
.end();
2796 for(it
=details
.files
.begin(); use
&& it
!=end
; ++it
)
2801 details
.files
.append(CDisabledFonts::TFile(fileName
, index
, foundry
));
2806 KFI_DBUG
<< "updated list of fonts";
2809 if(NULL
==itsFontList
)
2811 error(KIO::ERR_SLAVE_DEFINED
, i18n("Internal fontconfig error."));
2818 CKioFonts::EFolder
CKioFonts::getFolder(const KUrl
&url
)
2820 return itsRoot
|| isSysFolder(getSect(url
.path())) ? FOLDER_SYS
: FOLDER_USER
;
2823 CKioFonts::TFontMap::Iterator
CKioFonts::getMap(const KUrl
&url
)
2825 KFI_DBUG
<< url
.prettyUrl();
2827 int face(Misc::getIntQueryVal(url
, KFI_KIO_FACE
, 0));
2828 EFolder
folder(getFolder(url
));
2829 TFontMap::Iterator it
=itsFolders
[folder
].fontMap
.find(removeMultipleExtension(url
)),
2830 end(itsFolders
[folder
].fontMap
.end());
2832 if(it
==end
) // Perhaps it was fonts:/System/times.ttf ???
2834 QString
fName(Misc::getFile(url
.path()));
2836 for(int t
=0; t
<3; ++t
)
2838 QString fileName
=0==t
2840 : 1==t
? modifyName(fName
) // lowercase
2841 : modifyName(fName
, true); // uppercase
2843 KFI_DBUG
<< "look for " << fileName
;
2845 for(it
=itsFolders
[folder
].fontMap
.begin(); it
!=end
; ++it
)
2847 CDisabledFonts::TFileList::Iterator
sIt((*it
).files
.begin()),
2848 sEnd((*it
).files
.end());
2850 for(;sIt
!=sEnd
; ++sIt
)
2851 if(Misc::getFile(*sIt
)==fileName
&& (*sIt
).face
==face
)
2860 const CDisabledFonts::TFileList
* CKioFonts::getEntries(const KUrl
&url
,
2861 TFontMap::Iterator
&enabledIt
,
2862 CDisabledFonts::TFontList::Iterator
&disabledIt
)
2864 KFI_DBUG
<< url
.prettyUrl();
2866 EFolder folder
=getFolder(url
);
2867 TFontMap::Iterator
it(getMap(url
)),
2868 end(itsFolders
[folder
].fontMap
.end());
2869 QString name
=Misc::getFile(removeMultipleExtension(url
));
2870 CDisabledFonts::TFontList::Iterator
dIt(itsFolders
[folder
].disabled
->find(name
,
2871 Misc::getIntQueryVal(url
, KFI_KIO_FACE
, 0))),
2872 dEnd(itsFolders
[folder
].disabled
->items().end());
2877 if(it
!=end
&& dIt
==dEnd
)
2879 KFI_DBUG
<< "found enabled";
2881 return &(it
.value().files
);
2883 else if (it
==end
&& dIt
!=dEnd
)
2886 KFI_DBUG
<< "found disabled";
2887 return &((*dIt
).files
);
2889 else if(it
!=end
&& dIt
!=dEnd
)
2891 KFI_DBUG
<< "found both!";
2893 // Oops... we have a match for both a hidden, and non-hidden font! Have to ask which one...
2894 // This should never really happen, as hidden fonts will start with a period.
2895 if(KMessageBox::Yes
==messageBox(QuestionYesNo
,
2896 i18n("The selected URL (%1) matches both an enabled, and disabled "
2897 "font. Which one do you wish to access?", url
.prettyUrl()),
2898 i18n("Duplicate Font"), i18n("Enabled Font"),
2899 i18n("Disabled Font")))
2902 return &(it
.value().files
);
2907 return &((*dIt
).files
);
2911 KFI_DBUG
<< "found none";
2915 QStringList
CKioFonts::getFontNameEntries(EFolder folder
, const QString
&file
, bool disabledFonts
)
2921 CDisabledFonts::TFontList::Iterator
it(itsFolders
[folder
].disabled
->items().begin()),
2922 end(itsFolders
[folder
].disabled
->items().end());
2924 for(; it
!=end
; ++it
)
2926 CDisabledFonts::TFileList::ConstIterator patIt
,
2927 patEnd
=(*it
).files
.end();
2929 for(patIt
=(*it
).files
.begin(); patIt
!=patEnd
; ++patIt
)
2930 if((*patIt
).path
==file
)
2932 rv
.append((*it
).name
);
2939 TFontMap::Iterator it
,
2940 end
=itsFolders
[folder
].fontMap
.end();
2942 for(it
=itsFolders
[folder
].fontMap
.begin(); it
!=end
; ++it
)
2944 CDisabledFonts::TFileList::ConstIterator patIt
,
2945 patEnd
=it
.value().files
.end();
2947 for(patIt
=it
.value().files
.begin(); patIt
!=patEnd
; ++patIt
)
2948 if((*patIt
).path
==file
)
2950 rv
.append(it
.key());
2958 QMap
<int, QString
> CKioFonts::getFontIndexToNameEntries(EFolder folder
, const QString
&file
)
2960 QMap
<int, QString
> rv
;
2961 TFontMap::Iterator it
,
2962 end
=itsFolders
[folder
].fontMap
.end();
2964 for(it
=itsFolders
[folder
].fontMap
.begin(); it
!=end
; ++it
)
2966 CDisabledFonts::TFileList::Iterator patIt
,
2967 patEnd
=it
.value().files
.end();
2969 for(patIt
=it
.value().files
.begin(); patIt
!=patEnd
; ++patIt
)
2970 if((*patIt
).path
==file
)
2972 rv
[(*patIt
).face
]=it
.key();
2980 QString
* CKioFonts::getEntry(EFolder folder
, const QString
&file
, bool full
)
2982 TFontMap::Iterator it
,
2983 end
=itsFolders
[folder
].fontMap
.end();
2985 for(it
=itsFolders
[folder
].fontMap
.begin(); it
!=end
; ++it
)
2987 CDisabledFonts::TFileList::Iterator patIt
,
2988 patEnd
=it
.value().files
.end();
2990 for(patIt
=it
.value().files
.begin(); patIt
!=patEnd
; ++patIt
)
2991 if( (full
&& (*patIt
).path
==file
) ||
2992 (!full
&& Misc::getFile(*patIt
)==file
))
2993 return &((*patIt
).path
);
2999 CKioFonts::EFileType
CKioFonts::checkFile(const QString
&file
, const KUrl
&url
)
3002 // To speed things up, check the files extension 1st...
3003 if(Misc::checkExt(file
, "bdf") || Misc::checkExt(file
, "bdf.gz") ||
3004 Misc::checkExt(file
, "pcf") || Misc::checkExt(file
, "pcf.gz"))
3006 // Need to check whether bitmaps have been hidden from from fontconfig - as happens on KUbuntu...
3007 if(FC::bitmapsEnabled())
3010 error(KIO::ERR_SLAVE_DEFINED
, i18n("You cannot install bitmap fonts, as these have been "
3011 "disabled on your system."));
3013 else if(isAAfm(file
) || isAPfm(file
))
3014 return FILE_METRICS
;
3015 else if(Misc::isPackage(file
))
3016 error(KIO::ERR_SLAVE_DEFINED
, i18n("You cannot install a fonts package directly.\n"
3017 "Please extract %1, and install the components individually.",
3022 // Check that file is a font via FreeType...
3024 FcPattern
*pat
=FcFreeTypeQuery((const FcChar8
*)(QFile::encodeName(file
).constData()), 0, NULL
,
3031 if(FcResultMatch
==FcPatternGetBool(pat
, FC_SCALABLE
, 0, &scalable
) && scalable
)
3033 // check too see whether font is already installed!
3034 int weight(KFI_NULL_SETTING
), slant(KFI_NULL_SETTING
), width(KFI_NULL_SETTING
);
3036 FcPatternGetInteger(pat
, FC_WEIGHT
, 0, &weight
);
3037 FcPatternGetInteger(pat
, FC_SLANT
, 0, &slant
);
3038 #ifndef KFI_FC_NO_WIDTHS
3039 FcPatternGetInteger(pat
, FC_WIDTH
, 0, &width
);
3042 QString
name(FC::createName(pat
, weight
, width
, slant
));
3044 KFI_DBUG
<< "Check for name:" << name
;
3046 // TODO: CDisabledFonts need to find on family & style info? Also need a find() that does
3047 // not take into account face! Perhaps use -1?
3048 if(itsFolders
[FOLDER_SYS
].fontMap
.contains(name
) ||
3049 itsFolders
[FOLDER_SYS
].disabled
->items().end()!=
3050 itsFolders
[FOLDER_SYS
].disabled
->find(name
, 1) ||
3051 (!itsRoot
&& (itsFolders
[FOLDER_USER
].fontMap
.contains(name
) ||
3052 itsFolders
[FOLDER_USER
].disabled
->items().end()!=
3053 itsFolders
[FOLDER_USER
].disabled
->find(name
, 1))))
3055 FcPatternDestroy(pat
);
3056 error(KIO::ERR_SLAVE_DEFINED
, i18n("File %1 contains the font:\n%2\n"
3057 "A font with this name is already installed.\n",
3058 url
.prettyUrl(), name
));
3059 return FILE_UNKNOWN
;
3062 FcPatternDestroy(pat
);
3066 error(KIO::ERR_SLAVE_DEFINED
, i18n("Could not determine file type for: %1\n"
3067 "Only fonts may be installed.", url
.prettyUrl()));
3069 return FILE_UNKNOWN
;
3072 bool CKioFonts::getSourceFiles(const KUrl
&src
, CDisabledFonts::TFileList
&files
, bool removeSymLinks
)
3074 if(KFI_KIO_FONTS_PROTOCOL
==src
.protocol())
3076 CDisabledFonts::TFontList::Iterator disabledIt
;
3077 TFontMap::Iterator enabledIt
;
3078 const CDisabledFonts::TFileList
*entries
=getEntries(src
, enabledIt
, disabledIt
);
3081 getFontFiles(*entries
, files
, removeSymLinks
);
3084 if(src
.isLocalFile())
3085 if(FILE_UNKNOWN
!=checkFile(src
.path(), src
))
3086 files
.append(CDisabledFonts::TFile(src
.path()));
3088 return false; // error logged in checkFile...
3092 CDisabledFonts::TFileList::Iterator it
,
3095 for(it
=files
.begin(); it
!=end
; ++it
)
3097 QByteArray realSrc
=QFile::encodeName(*it
);
3098 KDE_struct_stat buffSrc
;
3100 if (-1==KDE_stat(realSrc
.constData(), &buffSrc
))
3102 error(EACCES
==errno
? KIO::ERR_ACCESS_DENIED
: KIO::ERR_DOES_NOT_EXIST
,
3106 if(S_ISDIR(buffSrc
.st_mode
))
3108 error(KIO::ERR_IS_DIRECTORY
, src
.prettyUrl());
3111 if(S_ISFIFO(buffSrc
.st_mode
) || S_ISSOCK(buffSrc
.st_mode
))
3113 error(KIO::ERR_CANNOT_OPEN_FOR_READING
, src
.prettyUrl());
3120 error(KIO::ERR_DOES_NOT_EXIST
, src
.prettyUrl());
3127 bool CKioFonts::checkDestFile(const KUrl
&src
, const KUrl
&dest
, EFolder destFolder
, KIO::JobFlags flags
)
3129 QStringList folders
;
3131 folders
.append(itsFolders
[destFolder
].location
);
3132 folders
.append(getDestFolder(itsFolders
[destFolder
].location
, src
.fileName()));
3134 QStringList::Iterator
it(folders
.begin()),
3138 for(; it
!=end
; ++it
)
3140 if(!(flags
& KIO::Overwrite
) && (Misc::fExists(destFile
=(*it
)+src
.fileName()) ||
3141 Misc::fExists(destFile
=(*it
)+modifyName(src
.fileName())) ||
3142 Misc::fExists(destFile
=(*it
)+modifyName(src
.fileName(), true)) ) )
3144 // If copying / moving a TTC and it is the *same* file, then don't log an error, but
3145 // don't continue the transaction...
3147 // Reason being that fonts:/ lists the font names (not filenames) so for a TTC there'll
3148 // be multiple entries...
3149 if(isSameTtc(src
.path(), destFile
))
3152 error(KIO::ERR_FILE_ALREADY_EXIST
, dest
.prettyUrl());
3156 bool isHidden
=Misc::isHidden(src
);
3157 QString
other(isHidden
? src
.fileName().mid(1)
3158 : QChar('.')+src
.fileName());
3160 if(Misc::fExists((*it
)+other
) ||
3161 Misc::fExists((*it
)+modifyName(other
)) ||
3162 Misc::fExists((*it
)+modifyName(other
, true)))
3164 error(KIO::ERR_SLAVE_DEFINED
,
3166 ? i18n("Could not install %1\nA matching enabled font already exists. "
3167 "Please disable that.", src
.prettyUrl())
3168 : i18n("Could not install %1\nA matching disabled font already exists. "
3169 "Please enable that.", src
.prettyUrl()));
3176 bool CKioFonts::checkDestFiles(const KUrl
&src
, QMap
<QString
, QString
> &map
, const KUrl
&dest
,
3177 EFolder destFolder
, KIO::JobFlags flags
)
3180 // Check whether files exist at destination...
3182 if(dest
.protocol()==src
.protocol() &&
3183 dest
.directory()==src
.directory()) // Check whether confirmUrl changed a "cp fonts:/System
3184 // fonts:/" to "cp fonts:/System fonts:/System"
3186 error(KIO::ERR_FILE_ALREADY_EXIST
, dest
.prettyUrl());
3190 if(!(flags
& KIO::Overwrite
))
3192 QMap
<QString
, QString
>::Iterator
fIt(map
.begin()),
3196 for(; fIt
!=fEnd
; ++fIt
)
3197 if(NULL
!=(destEntry
=getEntry(destFolder
, fIt
.value())) ||
3198 NULL
!=(destEntry
=getEntry(destFolder
, modifyName(fIt
.value()))) || // lowercase
3199 NULL
!=(destEntry
=getEntry(destFolder
, modifyName(fIt
.value()), true))) // uppercase
3201 // If copying / moving a TTC and it is the *same* file, then don't log an error, but
3202 // don't continue the transaction...
3204 // Reason being that fonts:/ lists the font names (not filenames) so for a TTC there'll
3205 // be multiple entries for a TTC...
3206 if(isSameTtc(src
.path(), *destEntry
))
3209 error(KIO::ERR_FILE_ALREADY_EXIST
, dest
.prettyUrl());
3218 // Gather the number and names of the font faces located in "files". If there is more than 1 face
3219 // (such as there would be for a TTC font), then ask the user for confirmation of the action.
3220 bool CKioFonts::confirmMultiple(const KUrl
&url
, const CDisabledFonts::TFileList
&files
, EFolder folder
,
3223 if(KFI_KIO_FONTS_PROTOCOL
!=url
.protocol())
3226 CDisabledFonts::TFileList::ConstIterator it
,
3230 for(it
=files
.begin(); it
!=files
.end(); ++it
)
3232 QStringList
fn(getFontNameEntries(folder
, *it
, OP_ENABLE
==op
));
3233 QStringList::Iterator
fnIt(fn
.begin()),
3236 for(; fnIt
!=fnEnd
; ++fnIt
)
3237 if(-1==fonts
.indexOf(*fnIt
))
3238 fonts
.append(*fnIt
);
3245 QStringList::Iterator it
,
3248 for(it
=fonts
.begin(); it
!=end
; ++it
)
3249 out
+=QString("<li>")+*it
+QString("</li>");
3254 question
=i18n("<p>You are attempting to move a font that is located in a file alongside "
3255 "other fonts; in order to proceed with the moving they will "
3256 "all have to be moved. The affected fonts are:</p>"
3257 "<ul>%1</ul><p>\n Do you wish to move all of these?</p>", out
);
3260 question
=i18n("<p>You are attempting to copy a font that is located in a file alongside "
3261 "other fonts; in order to proceed with the copying they will "
3262 "all have to be copied. The affected fonts are:</p>"
3263 "<ul>%1</ul><p>\n Do you wish to copy all of these?</p>", out
);
3266 question
=i18n("<p>You are attempting to delete a font that is located in a file alongside "
3267 "other fonts; in order to proceed with the deleting they will "
3268 "all have to be deleted. The affected fonts are:</p>"
3269 "<ul>%1</ul><p>\n Do you wish to delete all of these?</p>", out
);
3272 question
=i18n("<p>You are attempting to enable a font that is located in a file alongside "
3273 "other fonts; in order to proceed with the enabling they will "
3274 "all have to be enabled. The affected fonts are:</p>"
3275 "<ul>%1</ul><p>\n Do you wish to enable all of these?</p>", out
);
3278 question
=i18n("<p>You are attempting to disable a font that is located in a file alongside "
3279 "other fonts; in order to proceed with the disabling they will "
3280 "all have to be disabled. The affected fonts are:</p>"
3281 "<ul>%1</ul><p>\n Do you wish to disable all of these?</p>", out
);
3285 if(KMessageBox::No
==messageBox(question
, QuestionYesNo
))
3287 error(KIO::ERR_USER_CANCELED
, url
.prettyUrl());
3295 bool CKioFonts::confirmMultiple(const KUrl
&url
, const CDisabledFonts::TFileList
*patterns
,
3296 EFolder folder
, EOp op
)
3298 if(KFI_KIO_FONTS_PROTOCOL
!=url
.protocol())
3301 return patterns
? confirmMultiple(url
, *patterns
, folder
, op
) : false;
3304 bool CKioFonts::checkUrl(const KUrl
&u
, bool rootOk
, bool logError
)
3306 if(KFI_KIO_FONTS_PROTOCOL
==u
.protocol() && (!rootOk
|| (rootOk
&& "/"!=u
.path())))
3308 QString
sect(getSect(u
.path()));
3312 if((isSysFolder(sect
) || isUserFolder(sect
)) &&
3313 (itsFolders
[FOLDER_SYS
].fontMap
.end()==itsFolders
[FOLDER_SYS
].fontMap
.find(sect
)))
3314 //CPD: TODO: || it has a font specified! e.g. fonts:/System/Times -> even in have a
3315 // fonts:/System font, redirect should still happen
3317 redirection(getRedirect(u
));
3323 if(!isSysFolder(sect
) && !isUserFolder(sect
) && !isAllFolder(sect
) )
3326 error(KIO::ERR_SLAVE_DEFINED
, i18n("Please specify \"%1\" or \"%2\".",
3327 i18n(KFI_KIO_FONTS_USER
), i18n(KFI_KIO_FONTS_SYS
)));
3335 bool CKioFonts::checkAllowed(const KUrl
&u
)
3337 if (KFI_KIO_FONTS_PROTOCOL
==u
.protocol())
3339 QString
ds(Misc::dirSyntax(u
.path()));
3341 if(ds
==QString(QChar('/')+i18n(KFI_KIO_FONTS_USER
)+QChar('/')) ||
3342 ds
==QString(QChar('/')+i18n(KFI_KIO_FONTS_SYS
)+QChar('/')) ||
3343 ds
==QString(QChar('/')+QString::fromLatin1(KFI_KIO_FONTS_USER
)+QChar('/')) ||
3344 ds
==QString(QChar('/')+QString::fromLatin1(KFI_KIO_FONTS_SYS
)+QChar('/')))
3346 error(KIO::ERR_SLAVE_DEFINED
,
3347 i18n("Sorry, you cannot rename, move, copy, or delete either \"%1\" or \"%2\".",
3348 i18n(KFI_KIO_FONTS_USER
), i18n(KFI_KIO_FONTS_SYS
))); \
3357 // Create an AFM from a Type 1 (pfa/pfb) font and its PFM file...
3358 void CKioFonts::createAfm(const QString
&file
, bool nrs
)
3360 if(nrs
&& itsPasswd
.isEmpty())
3363 bool type1
=isAType1(file
),
3364 pfm
=!type1
&& isAPfm(file
); // No point checking if is pfm if its a type1
3368 // pf2afm wants files with lowercase extension, so just check for lowercase!
3369 // -- when a font is installed, the extension is converted to lowercase anyway...
3370 QString afm
=getMatch(file
, "afm");
3372 if(afm
.isEmpty()) // No point creating if AFM already exists!
3377 if(type1
) // Its a Type1, so look for existing PFM
3379 pfm
=getMatch(file
, "pfm");
3382 else // Its a PFM, so look for existing Type1
3384 t1
=getMatch(file
, "pfa");
3386 t1
=getMatch(file
, "pfb");
3390 if(!t1
.isEmpty() && !pfm
.isEmpty()) // Do we have both Type1 and PFM?
3392 QString
name(t1
.left(t1
.length()-4)); // pf2afm wants name without extension...
3395 doRootCmd(TCommand(KFI::CMD_CREATE_AFM
, name
));
3397 Misc::doCmd("pf2afm", QFile::encodeName(name
));
3403 int CKioFonts::reconfigTimeout()
3405 return hasMetaData(KFI_KIO_TIMEOUT
)
3406 ? metaData(KFI_KIO_TIMEOUT
).toInt()
3410 void CKioFonts::TFolder::setLocation(const QString
&l
, bool sys
)
3414 disabled
=new CDisabledFonts(sys
);