~ubuntu-branches/ubuntu/quantal/kde4libs/quantal

« back to all changes in this revision

Viewing changes to .pc/make_libkdeinit4_private.diff/kdecore/kernel/kstandarddirs.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer, Philip Muškovac, Jonathan Thomas, Felix Geyer
  • Date: 2011-05-29 17:19:55 UTC
  • mfrom: (1.14.5 upstream) (0.1.19 sid)
  • Revision ID: package-import@ubuntu.com-20110529171955-nodep1593tuwyu6k
Tags: 4:4.6.3-1ubuntu1
[ Philip Muškovac]
* Drop kubuntu_83_fix_solid_network_status.diff
* Update Vcs links as the branch is owned by kubuntu-packagers now

[ Jonathan Thomas ]
* Drop kubuntu_06_user_disk_mounting. We no longer compile the hal
  backend, so this patch is useless.

[ Felix Geyer ]
* Merge from Debian unstable, remaining changes:
  - no build-dep on libaspell-dev
  - no build-dep on libfam-dev
  - kdelibs5-data: don't install kspell_aspell.desktop and
    usr/lib/kde4/kspell_aspell.so
  - kdelibs5-dev: don't install preparetips
  - Pass -DKDESU_USE_SUDO_DEFAULT=true to configure
  - dh_fixperms: exclude /usr/lib/kde4/libexec/fileshareset
  - set export KUBUNTU_DESKTOP_POT=kdelibs
  - don't apply use_dejavu_as_default_font.diff
  - don't apply kconf_update_migrate_from_kde3_icon_theme.diff
    - kdelibs5-data.install: drop usr/share/kde4/apps/kconf_update/kdeui.upd
  - don't build depend on libglu1-mesa-dev, not needed due to
    kubuntu_no_direct_gl_usage.diff
  - Add kdelibs5-data.links: link from /usr/share/doc/kde4 to kde for
    backwards compatible with old docs location
  - Keep the kdelibs5 transitional package
  - kdelibs5-dev.install: install ksambasharedata.h
  - kdelibs5-plugins: recommend ttf-dejavu-core instead of ttf-dejavu to save
    CD space.
* Add Breaks in addition to Replaces for moving files between packages.
* Drop no longer needed Breaks and Replaces.
* Completely drop kubuntu_51_launchpad_integration.diff and
  kubuntu_68_remove_applet_confirmation.diff.
  + Also drop the launchpad and kubuntu icons.
* Remove sequence numbers from kubuntu patches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE libraries
 
2
   Copyright (C) 1999 Sirtaj Singh Kang <taj@kde.org>
 
3
   Copyright (C) 1999,2007 Stephan Kulow <coolo@kde.org>
 
4
   Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
 
5
   Copyright (C) 2009 David Faure <faure@kde.org>
 
6
 
 
7
   This library is free software; you can redistribute it and/or
 
8
   modify it under the terms of the GNU Library General Public
 
9
   License version 2 as published by the Free Software Foundation.
 
10
 
 
11
   This library is distributed in the hope that it will be useful,
 
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
   Library General Public License for more details.
 
15
 
 
16
   You should have received a copy of the GNU Library General Public License
 
17
   along with this library; see the file COPYING.LIB.  If not, write to
 
18
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
19
   Boston, MA 02110-1301, USA.
 
20
*/
 
21
 
 
22
/*
 
23
 * Author: Stephan Kulow <coolo@kde.org> and Sirtaj Singh Kang <taj@kde.org>
 
24
 * Generated: Thu Mar  5 16:05:28 EST 1998
 
25
 */
 
26
 
 
27
#include "kstandarddirs.h"
 
28
#include "kconfig.h"
 
29
#include "kconfiggroup.h"
 
30
#include "kdebug.h"
 
31
#include "kcomponentdata.h"
 
32
#include "kshell.h"
 
33
#include "kuser.h"
 
34
#include "kde_file.h"
 
35
#include "kkernel_win.h"
 
36
#include "kkernel_mac.h"
 
37
#include "klocale.h"
 
38
 
 
39
#include <config.h>
 
40
#include <config-prefix.h>
 
41
#include <config-kstandarddirs.h>
 
42
 
 
43
#include <stdlib.h>
 
44
#include <assert.h>
 
45
#include <errno.h>
 
46
#ifdef HAVE_SYS_STAT_H
 
47
#include <sys/stat.h>
 
48
#endif
 
49
#ifdef HAVE_UNISTD_H
 
50
#include <unistd.h>
 
51
#endif
 
52
#include <sys/param.h>
 
53
#include <sys/types.h>
 
54
#include <dirent.h>
 
55
#include <pwd.h>
 
56
#include <grp.h>
 
57
#ifdef Q_WS_WIN
 
58
#include <windows.h>
 
59
#ifdef _WIN32_WCE
 
60
#include <basetyps.h>
 
61
#endif
 
62
#ifdef Q_WS_WIN64
 
63
// FIXME: did not find a reliable way to fix with kdewin mingw header
 
64
#define interface struct
 
65
#endif
 
66
#include <shlobj.h>
 
67
#include <QtCore/QVarLengthArray>
 
68
#endif
 
69
 
 
70
#include <QtCore/QMutex>
 
71
#include <QtCore/QRegExp>
 
72
#include <QtCore/QDir>
 
73
#include <QtCore/QFileInfo>
 
74
#include <QtCore/QSettings>
 
75
 
 
76
class KStandardDirs::KStandardDirsPrivate
 
77
{
 
78
public:
 
79
    KStandardDirsPrivate(KStandardDirs* qq)
 
80
        : m_restrictionsActive(false),
 
81
          m_checkRestrictions(true),
 
82
          m_cacheMutex(QMutex::Recursive), // resourceDirs is recursive
 
83
          q(qq)
 
84
    { }
 
85
 
 
86
    bool hasDataRestrictions(const QString &relPath) const;
 
87
    QStringList resourceDirs(const char* type, const QString& subdirForRestrictions);
 
88
    void createSpecialResource(const char*);
 
89
 
 
90
    bool m_restrictionsActive : 1;
 
91
    bool m_checkRestrictions : 1;
 
92
    QMap<QByteArray, bool> m_restrictions;
 
93
 
 
94
    QStringList xdgdata_prefixes;
 
95
    QStringList xdgconf_prefixes;
 
96
    QStringList m_prefixes;
 
97
 
 
98
    // Directory dictionaries
 
99
    QMap<QByteArray, QStringList> m_absolutes; // For each resource type, the list of absolute paths, from most local (most priority) to most global
 
100
    QMap<QByteArray, QStringList> m_relatives; // Same with relative paths
 
101
    // The search path is "all relative paths" < "all absolute paths", from most priority to least priority.
 
102
 
 
103
    // Caches (protected by mutex in const methods, cf ctor docu)
 
104
    QMap<QByteArray, QStringList> m_dircache;
 
105
    QMap<QByteArray, QString> m_savelocations;
 
106
    QMutex m_cacheMutex;
 
107
 
 
108
    KStandardDirs* q;
 
109
};
 
110
 
 
111
/* If you add a new resource type here, make sure to
 
112
 * 1) regenerate using "kdesdk/scripts/generate_string_table.pl types < tmpfile" with the data below in tmpfile.
 
113
 * 2) update the KStandardDirs class documentation
 
114
 * 3) update the list in kde-config.cpp
 
115
 
 
116
data
 
117
share/apps
 
118
html
 
119
share/doc/HTML
 
120
icon
 
121
share/icons
 
122
config
 
123
share/config
 
124
pixmap
 
125
share/pixmaps
 
126
apps
 
127
share/applnk
 
128
sound
 
129
share/sounds
 
130
locale
 
131
share/locale
 
132
services
 
133
share/kde4/services
 
134
servicetypes
 
135
share/kde4/servicetypes
 
136
mime
 
137
share/mimelnk
 
138
cgi
 
139
cgi-bin
 
140
wallpaper
 
141
share/wallpapers
 
142
templates
 
143
share/templates
 
144
exe
 
145
bin
 
146
module
 
147
%lib/kde4
 
148
qtplugins
 
149
%lib/kde4/plugins
 
150
kcfg
 
151
share/config.kcfg
 
152
emoticons
 
153
share/emoticons
 
154
xdgdata-apps
 
155
applications
 
156
xdgdata-icon
 
157
icons
 
158
xdgdata-pixmap
 
159
pixmaps
 
160
xdgdata-dirs
 
161
desktop-directories
 
162
xdgdata-mime
 
163
mime
 
164
xdgconf-menu
 
165
menus
 
166
xdgconf-autostart
 
167
autostart
 
168
*/
 
169
 
 
170
static const char types_string[] =
 
171
    "data\0"
 
172
    "share/apps\0"
 
173
    "html\0"
 
174
    "share/doc/HTML\0"
 
175
    "icon\0"
 
176
    "share/icons\0"
 
177
    "config\0"
 
178
    "share/config\0"
 
179
    "pixmap\0"
 
180
    "share/pixmaps\0"
 
181
    "apps\0"
 
182
    "share/applnk\0"
 
183
    "sound\0"
 
184
    "share/sounds\0"
 
185
    "locale\0"
 
186
    "share/locale\0"
 
187
    "services\0"
 
188
    "share/kde4/services\0"
 
189
    "servicetypes\0"
 
190
    "share/kde4/servicetypes\0"
 
191
    "mime\0"
 
192
    "share/mimelnk\0"
 
193
    "cgi\0"
 
194
    "cgi-bin\0"
 
195
    "wallpaper\0"
 
196
    "share/wallpapers\0"
 
197
    "templates\0"
 
198
    "share/templates\0"
 
199
    "exe\0"
 
200
    "bin\0"
 
201
    "module\0"
 
202
    "%lib/kde4\0"
 
203
    "qtplugins\0"
 
204
    "%lib/kde4/plugins\0"
 
205
    "kcfg\0"
 
206
    "share/config.kcfg\0"
 
207
    "emoticons\0"
 
208
    "share/emoticons\0"
 
209
    "xdgdata-apps\0"
 
210
    "applications\0"
 
211
    "xdgdata-icon\0"
 
212
    "icons\0"
 
213
    "xdgdata-pixmap\0"
 
214
    "pixmaps\0"
 
215
    "xdgdata-dirs\0"
 
216
    "desktop-directories\0"
 
217
    "xdgdata-mime\0"
 
218
    "xdgconf-menu\0"
 
219
    "menus\0"
 
220
    "xdgconf-autostart\0"
 
221
    "autostart\0"
 
222
    "\0";
 
223
 
 
224
static const int types_indices[] = {
 
225
    0,    5,   16,   21,   36,   41,   53,   60,
 
226
    73,   80,   94,   99,  112,  118,  131,  138,
 
227
    151,  160,  180,  193,  217,  222,  236,  240,
 
228
    248,  258,  275,  285,  301,  305,  309,  316,
 
229
    326,  336,  354,  359,  377,  387,  403,  416,
 
230
    429,  442,  448,  463,  471,  484,  504,  217,
 
231
    517,  530,  536,  554,  -1
 
232
};
 
233
 
 
234
static void tokenize(QStringList& token, const QString& str,
 
235
                     const QString& delim);
 
236
 
 
237
KStandardDirs::KStandardDirs()
 
238
    : d(new KStandardDirsPrivate(this))
 
239
{
 
240
    addKDEDefaults();
 
241
}
 
242
 
 
243
KStandardDirs::~KStandardDirs()
 
244
{
 
245
    delete d;
 
246
}
 
247
 
 
248
bool KStandardDirs::isRestrictedResource(const char *type, const QString& relPath) const
 
249
{
 
250
    if (!d->m_restrictionsActive)
 
251
        return false;
 
252
 
 
253
    if (d->m_restrictions.value(type, false))
 
254
        return true;
 
255
 
 
256
    if (strcmp(type, "data")==0 && d->hasDataRestrictions(relPath))
 
257
        return true;
 
258
 
 
259
    return false;
 
260
}
 
261
 
 
262
bool KStandardDirs::KStandardDirsPrivate::hasDataRestrictions(const QString &relPath) const
 
263
{
 
264
    QString key;
 
265
    const int i = relPath.indexOf(QLatin1Char('/'));
 
266
    if (i != -1)
 
267
        key = QString::fromLatin1("data_") + relPath.left(i);
 
268
    else
 
269
        key = QString::fromLatin1("data_") + relPath;
 
270
 
 
271
    return m_restrictions.value(key.toLatin1(), false);
 
272
}
 
273
 
 
274
 
 
275
QStringList KStandardDirs::allTypes() const
 
276
{
 
277
    QStringList list;
 
278
    for (int i = 0; types_indices[i] != -1; i += 2)
 
279
        list.append(QLatin1String(types_string + types_indices[i]));
 
280
    // Those are added manually by addKDEDefaults
 
281
    list.append(QString::fromLatin1("lib"));
 
282
    //list.append(QString::fromLatin1("home")); // undocumented on purpose, said Waldo in r113855.
 
283
 
 
284
    // Those are handled by resourceDirs() itself
 
285
    list.append(QString::fromLatin1("socket"));
 
286
    list.append(QString::fromLatin1("tmp"));
 
287
    list.append(QString::fromLatin1("cache"));
 
288
    // Those are handled by installPath()
 
289
    list.append(QString::fromLatin1("include"));
 
290
 
 
291
    // If you add anything here, make sure kde-config.cpp has a description for it.
 
292
 
 
293
    return list;
 
294
}
 
295
 
 
296
static void priorityAdd(QStringList &prefixes, const QString& dir, bool priority)
 
297
{
 
298
    if (priority && !prefixes.isEmpty())
 
299
    {
 
300
        // Add in front but behind $KDEHOME
 
301
        QStringList::iterator it = prefixes.begin();
 
302
        it++;
 
303
        prefixes.insert(it, dir);
 
304
    }
 
305
    else
 
306
    {
 
307
        prefixes.append(dir);
 
308
    }
 
309
}
 
310
 
 
311
void KStandardDirs::addPrefix( const QString& _dir )
 
312
{
 
313
    addPrefix(_dir, false);
 
314
}
 
315
 
 
316
void KStandardDirs::addPrefix( const QString& _dir, bool priority )
 
317
{
 
318
    if (_dir.isEmpty())
 
319
        return;
 
320
 
 
321
    QString dir = _dir;
 
322
    if (dir.at(dir.length() - 1) != QLatin1Char('/'))
 
323
        dir += QLatin1Char('/');
 
324
 
 
325
    if (!d->m_prefixes.contains(dir)) {
 
326
        priorityAdd(d->m_prefixes, dir, priority);
 
327
        d->m_dircache.clear();
 
328
    }
 
329
}
 
330
 
 
331
void KStandardDirs::addXdgConfigPrefix( const QString& _dir )
 
332
{
 
333
    addXdgConfigPrefix(_dir, false);
 
334
}
 
335
 
 
336
void KStandardDirs::addXdgConfigPrefix( const QString& _dir, bool priority )
 
337
{
 
338
    if (_dir.isEmpty())
 
339
        return;
 
340
 
 
341
    QString dir = _dir;
 
342
    if (dir.at(dir.length() - 1) != QLatin1Char('/'))
 
343
        dir += QLatin1Char('/');
 
344
 
 
345
    if (!d->xdgconf_prefixes.contains(dir)) {
 
346
        priorityAdd(d->xdgconf_prefixes, dir, priority);
 
347
        d->m_dircache.clear();
 
348
    }
 
349
}
 
350
 
 
351
void KStandardDirs::addXdgDataPrefix( const QString& _dir )
 
352
{
 
353
    addXdgDataPrefix(_dir, false);
 
354
}
 
355
 
 
356
void KStandardDirs::addXdgDataPrefix( const QString& _dir, bool priority )
 
357
{
 
358
    if (_dir.isEmpty())
 
359
        return;
 
360
 
 
361
    QString dir = _dir;
 
362
    if (dir.at(dir.length() - 1) != QLatin1Char('/'))
 
363
        dir += QLatin1Char('/');
 
364
 
 
365
    if (!d->xdgdata_prefixes.contains(dir)) {
 
366
        priorityAdd(d->xdgdata_prefixes, dir, priority);
 
367
        d->m_dircache.clear();
 
368
    }
 
369
}
 
370
 
 
371
QString KStandardDirs::kfsstnd_prefixes()
 
372
{
 
373
    return d->m_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
 
374
}
 
375
 
 
376
QString KStandardDirs::kfsstnd_xdg_conf_prefixes()
 
377
{
 
378
    return d->xdgconf_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
 
379
}
 
380
 
 
381
QString KStandardDirs::kfsstnd_xdg_data_prefixes()
 
382
{
 
383
    return d->xdgdata_prefixes.join(QString(QLatin1Char(KPATH_SEPARATOR)));
 
384
}
 
385
 
 
386
#ifndef KDE_NO_DEPRECATED
 
387
bool KStandardDirs::addResourceType( const char *type,
 
388
                                     const QString& relativename,
 
389
                                     bool priority )
 
390
{
 
391
    return addResourceType( type, 0, relativename, priority);
 
392
}
 
393
#endif
 
394
 
 
395
bool KStandardDirs::addResourceType( const char *type,
 
396
                                     const char *basetype,
 
397
                                     const QString& relativename,
 
398
                                     bool priority )
 
399
{
 
400
    if (relativename.isEmpty())
 
401
        return false;
 
402
 
 
403
    QString copy = relativename;
 
404
    if (basetype)
 
405
        copy = QLatin1Char('%') + QString::fromLatin1(basetype) + QLatin1Char('/') + relativename;
 
406
 
 
407
    if (!copy.endsWith(QLatin1Char('/')))
 
408
        copy += QLatin1Char('/');
 
409
 
 
410
    QStringList& rels = d->m_relatives[type]; // find or insert
 
411
 
 
412
    if (!rels.contains(copy)) {
 
413
        if (priority)
 
414
            rels.prepend(copy);
 
415
        else
 
416
            rels.append(copy);
 
417
        // clean the caches
 
418
        d->m_dircache.remove(type);
 
419
        d->m_savelocations.remove(type);
 
420
        return true;
 
421
    }
 
422
    return false;
 
423
}
 
424
 
 
425
bool KStandardDirs::addResourceDir( const char *type,
 
426
                                    const QString& absdir,
 
427
                                    bool priority)
 
428
{
 
429
    if (absdir.isEmpty() || !type)
 
430
      return false;
 
431
    // find or insert entry in the map
 
432
    QString copy = absdir;
 
433
    if (copy.at(copy.length() - 1) != QLatin1Char('/'))
 
434
        copy += QLatin1Char('/');
 
435
 
 
436
    QStringList &paths = d->m_absolutes[type];
 
437
    if (!paths.contains(copy)) {
 
438
        if (priority)
 
439
            paths.prepend(copy);
 
440
        else
 
441
            paths.append(copy);
 
442
        // clean the caches
 
443
        d->m_dircache.remove(type);
 
444
        d->m_savelocations.remove(type);
 
445
        return true;
 
446
    }
 
447
    return false;
 
448
}
 
449
 
 
450
QString KStandardDirs::findResource( const char *type,
 
451
                                     const QString& _filename ) const
 
452
{
 
453
    if (!QDir::isRelativePath(_filename))
 
454
      return !KGlobal::hasLocale() ? _filename // absolute dirs are absolute dirs, right? :-/
 
455
                                   : KGlobal::locale()->localizedFilePath(_filename); // -- almost.
 
456
 
 
457
#if 0
 
458
    kDebug(180) << "Find resource: " << type;
 
459
    for (QStringList::ConstIterator pit = m_prefixes.begin();
 
460
         pit != m_prefixes.end();
 
461
         ++pit)
 
462
    {
 
463
        kDebug(180) << "Prefix: " << *pit;
 
464
    }
 
465
#endif
 
466
 
 
467
    QString filename(_filename);
 
468
#ifdef Q_OS_WIN
 
469
    if(strcmp(type, "exe") == 0) {
 
470
      if(!filename.endsWith(QLatin1String(".exe")))
 
471
        filename += QLatin1String(".exe");
 
472
    }
 
473
#endif
 
474
    const QString dir = findResourceDir(type, filename);
 
475
    if (dir.isEmpty())
 
476
      return dir;
 
477
    else
 
478
      return !KGlobal::hasLocale() ? dir + filename
 
479
                                   : KGlobal::locale()->localizedFilePath(dir + filename);
 
480
}
 
481
 
 
482
static quint32 updateHash(const QString &file, quint32 hash)
 
483
{
 
484
    KDE_struct_stat buff;
 
485
    if ((KDE::access(file, R_OK) == 0) && (KDE::stat(file, &buff) == 0) && (S_ISREG(buff.st_mode))) {
 
486
        hash = hash + static_cast<quint32>(buff.st_ctime);
 
487
    }
 
488
    return hash;
 
489
}
 
490
 
 
491
quint32 KStandardDirs::calcResourceHash( const char *type,
 
492
                                         const QString& filename,
 
493
                                         SearchOptions options ) const
 
494
{
 
495
    quint32 hash = 0;
 
496
 
 
497
    if (!QDir::isRelativePath(filename))
 
498
    {
 
499
        // absolute dirs are absolute dirs, right? :-/
 
500
        return updateHash(filename, hash);
 
501
    }
 
502
    QStringList candidates = d->resourceDirs(type, filename);
 
503
 
 
504
    foreach ( const QString& candidate, candidates )
 
505
    {
 
506
        hash = updateHash(candidate + filename, hash);
 
507
        if (  !( options & Recursive ) && hash ) {
 
508
            return hash;
 
509
        }
 
510
    }
 
511
    return hash;
 
512
}
 
513
 
 
514
 
 
515
QStringList KStandardDirs::findDirs( const char *type,
 
516
                                     const QString& reldir ) const
 
517
{
 
518
    QDir testdir;
 
519
    QStringList list;
 
520
    if (!QDir::isRelativePath(reldir))
 
521
    {
 
522
        testdir.setPath(reldir);
 
523
        if (testdir.exists())
 
524
        {
 
525
            if (reldir.endsWith(QLatin1Char('/')))
 
526
                list.append(reldir);
 
527
            else
 
528
                list.append(reldir+QLatin1Char('/'));
 
529
        }
 
530
        return list;
 
531
    }
 
532
 
 
533
    const QStringList candidates = d->resourceDirs(type, reldir);
 
534
 
 
535
    for (QStringList::ConstIterator it = candidates.begin();
 
536
         it != candidates.end(); ++it) {
 
537
        testdir.setPath(*it + reldir);
 
538
        if (testdir.exists())
 
539
            list.append(testdir.absolutePath() + QLatin1Char('/'));
 
540
    }
 
541
 
 
542
    return list;
 
543
}
 
544
 
 
545
QString KStandardDirs::findResourceDir( const char *type,
 
546
                                        const QString& _filename) const
 
547
{
 
548
#ifndef NDEBUG
 
549
    if (_filename.isEmpty()) {
 
550
        kWarning() << "filename for type " << type << " in KStandardDirs::findResourceDir is not supposed to be empty!!";
 
551
        return QString();
 
552
    }
 
553
#endif
 
554
 
 
555
    QString filename(_filename);
 
556
#ifdef Q_OS_WIN
 
557
    if(strcmp(type, "exe") == 0) {
 
558
      if(!filename.endsWith(QLatin1String(".exe")))
 
559
        filename += QLatin1String(".exe");
 
560
    }
 
561
#endif
 
562
    const QStringList candidates = d->resourceDirs(type, filename);
 
563
 
 
564
    for (QStringList::ConstIterator it = candidates.begin();
 
565
         it != candidates.end(); ++it) {
 
566
        if (exists(*it + filename)) {
 
567
            return *it;
 
568
        }
 
569
    }
 
570
 
 
571
#ifndef NDEBUG
 
572
    if(false && strcmp(type, "locale"))
 
573
        kDebug(180) << "KStdDirs::findResDir(): can't find \"" << filename << "\" in type \"" << type << "\".";
 
574
#endif
 
575
 
 
576
    return QString();
 
577
}
 
578
 
 
579
bool KStandardDirs::exists(const QString &fullPath)
 
580
{
 
581
#ifdef Q_OS_WIN
 
582
    // access() and stat() give a stupid error message to the user
 
583
    // if the path is not accessible at all (e.g. no disk in A:/ and
 
584
    // we do stat("A:/.directory")
 
585
    if (fullPath.endsWith(QLatin1Char('/')))
 
586
        return QDir(fullPath).exists();
 
587
    return QFileInfo(fullPath).exists();
 
588
#else
 
589
    KDE_struct_stat buff;
 
590
    QByteArray cFullPath = QFile::encodeName(fullPath);
 
591
    if (access(cFullPath, R_OK) == 0 && KDE_stat( cFullPath, &buff ) == 0) {
 
592
        if (!fullPath.endsWith(QLatin1Char('/'))) {
 
593
            if (S_ISREG( buff.st_mode ))
 
594
                return true;
 
595
        } else
 
596
            if (S_ISDIR( buff.st_mode ))
 
597
                return true;
 
598
    }
 
599
    return false;
 
600
#endif
 
601
}
 
602
 
 
603
static void lookupDirectory(const QString& path, const QString &relPart,
 
604
                            const QRegExp &regexp,
 
605
                            QStringList& list,
 
606
                            QStringList& relList,
 
607
                            bool recursive, bool unique)
 
608
{
 
609
    const QString pattern = regexp.pattern();
 
610
    if (recursive || pattern.contains(QLatin1Char('?')) || pattern.contains(QLatin1Char('*')))
 
611
    {
 
612
        if (path.isEmpty()) //for sanity
 
613
            return;
 
614
#ifdef Q_WS_WIN
 
615
        QString path_ = path + QLatin1String( "*.*" );
 
616
        WIN32_FIND_DATA findData;
 
617
        HANDLE hFile = FindFirstFile( (LPWSTR)path_.utf16(), &findData );
 
618
        if( hFile == INVALID_HANDLE_VALUE )
 
619
            return;
 
620
        do {
 
621
            const int len = wcslen( findData.cFileName );
 
622
            if (!( findData.cFileName[0] == '.' &&
 
623
                   findData.cFileName[1] == '\0' ) &&
 
624
                !( findData.cFileName[0] == '.' &&
 
625
                   findData.cFileName[1] == '.' &&
 
626
                   findData.cFileName[2] == '\0' ) &&
 
627
                 ( findData.cFileName[len-1] != '~' ) ) {
 
628
                QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
 
629
                if (!recursive && !regexp.exactMatch(fn))
 
630
                    continue; // No match
 
631
                QString pathfn = path + fn;
 
632
                bool bIsDir = ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY );
 
633
                if ( recursive ) {
 
634
                    if ( bIsDir ) {
 
635
                        lookupDirectory(pathfn + QLatin1Char('/'),
 
636
                                        relPart + fn + QLatin1Char('/'),
 
637
                                        regexp, list, relList, recursive, unique);
 
638
                    }
 
639
                    if (!regexp.exactMatch(fn))
 
640
                        continue; // No match
 
641
                }
 
642
                if ( !bIsDir )
 
643
                {
 
644
                    if ( !unique || !relList.contains(relPart + fn) )
 
645
                    {
 
646
                        list.append( pathfn );
 
647
                        relList.append( relPart + fn );
 
648
                    }
 
649
                }
 
650
            }
 
651
        } while( FindNextFile( hFile, &findData ) != 0 );
 
652
        FindClose( hFile );
 
653
#else
 
654
        // We look for a set of files.
 
655
        DIR *dp = opendir( QFile::encodeName(path));
 
656
        if (!dp)
 
657
            return;
 
658
 
 
659
        assert(path.endsWith(QLatin1Char('/')));
 
660
 
 
661
        struct dirent *ep;
 
662
 
 
663
        while( ( ep = readdir( dp ) ) != 0L )
 
664
        {
 
665
            QString fn( QFile::decodeName(ep->d_name));
 
666
            if (fn == QString::fromLatin1(".") || fn == QString::fromLatin1("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
 
667
                continue;
 
668
 
 
669
            if (!recursive && !regexp.exactMatch(fn))
 
670
                continue; // No match
 
671
 
 
672
            bool isDir;
 
673
            bool isReg;
 
674
 
 
675
            QString pathfn = path + fn;
 
676
#ifdef HAVE_DIRENT_D_TYPE
 
677
            isDir = ep->d_type == DT_DIR;
 
678
            isReg = ep->d_type == DT_REG;
 
679
 
 
680
            if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
 
681
#endif
 
682
            {
 
683
                KDE_struct_stat buff;
 
684
                if ( KDE::stat( pathfn, &buff ) != 0 ) {
 
685
                    kDebug(180) << "Error stat'ing " << pathfn << " : " << perror;
 
686
                    continue; // Couldn't stat (e.g. no read permissions)
 
687
                }
 
688
                isReg = S_ISREG (buff.st_mode);
 
689
                isDir = S_ISDIR (buff.st_mode);
 
690
            }
 
691
 
 
692
            if ( recursive ) {
 
693
                if ( isDir ) {
 
694
                    lookupDirectory(pathfn + QLatin1Char('/'), relPart + fn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
 
695
                }
 
696
                if (!regexp.exactMatch(fn))
 
697
                    continue; // No match
 
698
            }
 
699
            if ( isReg )
 
700
            {
 
701
                if (!unique || !relList.contains(relPart + fn))
 
702
                {
 
703
                    list.append( pathfn );
 
704
                    relList.append( relPart + fn );
 
705
                }
 
706
            }
 
707
        }
 
708
        closedir( dp );
 
709
#endif
 
710
    }
 
711
    else
 
712
    {
 
713
        // We look for a single file.
 
714
        QString fn = pattern;
 
715
        QString pathfn = path + fn;
 
716
        KDE_struct_stat buff;
 
717
        if ( KDE::stat( pathfn, &buff ) != 0 )
 
718
            return; // File not found
 
719
        if ( S_ISREG( buff.st_mode))
 
720
        {
 
721
            if (!unique || !relList.contains(relPart + fn))
 
722
            {
 
723
                list.append( pathfn );
 
724
                relList.append( relPart + fn );
 
725
            }
 
726
        }
 
727
    }
 
728
}
 
729
 
 
730
static void lookupPrefix(const QString& prefix, const QString& relpath,
 
731
                         const QString& relPart,
 
732
                         const QRegExp &regexp,
 
733
                         QStringList& list,
 
734
                         QStringList& relList,
 
735
                         bool recursive, bool unique)
 
736
{
 
737
    if (relpath.isEmpty()) {
 
738
        if (recursive)
 
739
            Q_ASSERT(prefix != QLatin1String("/")); // we don't want to recursively list the whole disk!
 
740
        lookupDirectory(prefix, relPart, regexp, list,
 
741
                        relList, recursive, unique);
 
742
        return;
 
743
    }
 
744
    QString path;
 
745
    QString rest;
 
746
 
 
747
    int slash = relpath.indexOf(QLatin1Char('/'));
 
748
    if (slash < 0)
 
749
        rest = relpath.left(relpath.length() - 1);
 
750
    else {
 
751
        path = relpath.left(slash);
 
752
        rest = relpath.mid(slash + 1);
 
753
    }
 
754
 
 
755
    if (prefix.isEmpty()) //for sanity
 
756
        return;
 
757
#ifndef Q_WS_WIN
 
758
    // what does this assert check ?
 
759
    assert(prefix.endsWith(QLatin1Char('/')));
 
760
#endif
 
761
    if (path.contains(QLatin1Char('*')) || path.contains(QLatin1Char('?'))) {
 
762
 
 
763
        QRegExp pathExp(path, Qt::CaseSensitive, QRegExp::Wildcard);
 
764
 
 
765
#ifdef Q_WS_WIN
 
766
        QString prefix_ = prefix + QLatin1String( "*.*" );
 
767
        WIN32_FIND_DATA findData;
 
768
        HANDLE hFile = FindFirstFile( (LPWSTR)prefix_.utf16(), &findData );
 
769
        if( hFile == INVALID_HANDLE_VALUE )
 
770
            return;
 
771
        do {
 
772
            const int len = wcslen( findData.cFileName );
 
773
            if (!( findData.cFileName[0] == '.' &&
 
774
                   findData.cFileName[1] == '\0' ) &&
 
775
                !( findData.cFileName[0] == '.' &&
 
776
                   findData.cFileName[1] == '.' &&
 
777
                   findData.cFileName[2] == '\0' ) &&
 
778
                 ( findData.cFileName[len-1] != '~' ) ) {
 
779
                const QString fn = QString::fromUtf16( (const unsigned short*)findData.cFileName );
 
780
                if ( !pathExp.exactMatch(fn) )
 
781
                    continue; // No match
 
782
                if ( ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY )
 
783
                    lookupPrefix(prefix + fn + QLatin1Char('/'),
 
784
                                 rest, relPart + fn + QLatin1Char('/'),
 
785
                                 regexp, list, relList, recursive, unique);
 
786
            }
 
787
        } while( FindNextFile( hFile, &findData ) != 0 );
 
788
        FindClose( hFile );
 
789
#else
 
790
        DIR *dp = opendir( QFile::encodeName(prefix) );
 
791
        if (!dp) {
 
792
            return;
 
793
        }
 
794
 
 
795
        struct dirent *ep;
 
796
 
 
797
        while( ( ep = readdir( dp ) ) != 0L )
 
798
        {
 
799
            QString fn( QFile::decodeName(ep->d_name));
 
800
            if (fn == QLatin1String(".") || fn == QLatin1String("..") || fn.at(fn.length() - 1) == QLatin1Char('~'))
 
801
                continue;
 
802
 
 
803
            if ( !pathExp.exactMatch(fn) )
 
804
                continue; // No match
 
805
            QString rfn = relPart+fn;
 
806
            fn = prefix + fn;
 
807
 
 
808
            bool isDir;
 
809
 
 
810
#ifdef HAVE_DIRENT_D_TYPE
 
811
            isDir = ep->d_type == DT_DIR;
 
812
 
 
813
            if (ep->d_type == DT_UNKNOWN || ep->d_type == DT_LNK)
 
814
#endif
 
815
            {
 
816
                QString pathfn = path + fn;
 
817
                KDE_struct_stat buff;
 
818
                if ( KDE::stat( fn, &buff ) != 0 ) {
 
819
                    kDebug(180) << "Error stat'ing " << fn << " : " << perror;
 
820
                    continue; // Couldn't stat (e.g. no read permissions)
 
821
                }
 
822
                isDir = S_ISDIR (buff.st_mode);
 
823
            }
 
824
            if ( isDir )
 
825
                lookupPrefix(fn + QLatin1Char('/'), rest, rfn + QLatin1Char('/'), regexp, list, relList, recursive, unique);
 
826
        }
 
827
 
 
828
        closedir( dp );
 
829
#endif
 
830
    } else {
 
831
        // Don't stat, if the dir doesn't exist we will find out
 
832
        // when we try to open it.
 
833
        lookupPrefix(prefix + path + QLatin1Char('/'), rest,
 
834
                     relPart + path + QLatin1Char('/'), regexp, list,
 
835
                     relList, recursive, unique);
 
836
    }
 
837
}
 
838
 
 
839
QStringList
 
840
KStandardDirs::findAllResources( const char *type,
 
841
                                 const QString& filter,
 
842
                                 SearchOptions options,
 
843
                                 QStringList &relList) const
 
844
{
 
845
    QString filterPath;
 
846
    QString filterFile;
 
847
 
 
848
    if ( !filter.isEmpty() )
 
849
    {
 
850
        int slash = filter.lastIndexOf(QLatin1Char('/'));
 
851
        if (slash < 0) {
 
852
            filterFile = filter;
 
853
        } else {
 
854
            filterPath = filter.left(slash + 1);
 
855
            filterFile = filter.mid(slash + 1);
 
856
        }
 
857
    }
 
858
 
 
859
    QStringList candidates;
 
860
    if ( !QDir::isRelativePath(filter) ) // absolute path
 
861
    {
 
862
#ifdef Q_OS_WIN
 
863
        candidates << filterPath.left(3); //e.g. "C:\"
 
864
        filterPath = filterPath.mid(3);
 
865
#else
 
866
        candidates << QString::fromLatin1("/");
 
867
        filterPath = filterPath.mid(1);
 
868
#endif
 
869
    }
 
870
    else
 
871
    {
 
872
        candidates = d->resourceDirs(type, filter);
 
873
    }
 
874
 
 
875
    if (filterFile.isEmpty()) {
 
876
        filterFile = QString(QLatin1Char('*'));
 
877
    }
 
878
 
 
879
    QRegExp regExp(filterFile, Qt::CaseSensitive, QRegExp::Wildcard);
 
880
 
 
881
    QStringList list;
 
882
    foreach ( const QString& candidate, candidates )
 
883
    {
 
884
        lookupPrefix(candidate, filterPath, QString(), regExp, list,
 
885
                     relList, options & Recursive, options & NoDuplicates);
 
886
    }
 
887
 
 
888
    return list;
 
889
}
 
890
 
 
891
QStringList
 
892
KStandardDirs::findAllResources( const char *type,
 
893
                                 const QString& filter,
 
894
                                 SearchOptions options ) const
 
895
{
 
896
    QStringList relList;
 
897
    return findAllResources(type, filter, options, relList);
 
898
}
 
899
 
 
900
// ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
 
901
// aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
 
902
//         and this method is often used with the expectation for it to work
 
903
//         even if the directory doesn't exist. so ... no, we can't drop this
 
904
//         yet
 
905
QString
 
906
KStandardDirs::realPath(const QString &dirname)
 
907
{
 
908
#ifdef Q_WS_WIN
 
909
    const QString strRet = realFilePath(dirname);
 
910
    if (!strRet.endsWith(QLatin1Char('/')))
 
911
        return strRet + QLatin1Char('/');
 
912
    return strRet;
 
913
#else
 
914
    if (dirname.isEmpty() || (dirname.size() == 1 && dirname.at(0) == QLatin1Char('/')))
 
915
       return dirname;
 
916
 
 
917
    if (dirname.at(0) != QLatin1Char('/')) {
 
918
        qWarning("realPath called with a relative path '%s', please fix", qPrintable(dirname));
 
919
        return dirname;
 
920
    }
 
921
 
 
922
    char realpath_buffer[MAXPATHLEN + 1];
 
923
    memset(realpath_buffer, 0, MAXPATHLEN + 1);
 
924
 
 
925
    /* If the path contains symlinks, get the real name */
 
926
    if (realpath( QFile::encodeName(dirname).constData(), realpath_buffer) != 0) {
 
927
        // success, use result from realpath
 
928
        int len = strlen(realpath_buffer);
 
929
        realpath_buffer[len] = '/';
 
930
        realpath_buffer[len+1] = 0;
 
931
        return QFile::decodeName(realpath_buffer);
 
932
    }
 
933
 
 
934
    // Does not exist yet; resolve symlinks in parent dirs then.
 
935
    // This ensures that once the directory exists, it will still be resolved
 
936
    // the same way, so that the general rule that KStandardDirs always returns
 
937
    // canonical paths stays true, and app code can compare paths more easily.
 
938
    QString dir = dirname;
 
939
    if (!dir.endsWith(QLatin1Char('/')))
 
940
        dir += QLatin1Char('/');
 
941
    QString relative;
 
942
    while (!KStandardDirs::exists(dir)) {
 
943
        //qDebug() << "does not exist:" << dir;
 
944
        const int pos = dir.lastIndexOf(QLatin1Char('/'), -2);
 
945
        Q_ASSERT(pos >= 0); // what? even "/" doesn't exist?
 
946
        relative.prepend(dir.mid(pos+1)); // keep "subdir/"
 
947
        dir = dir.left(pos+1);
 
948
        Q_ASSERT(dir.endsWith(QLatin1Char('/')));
 
949
    }
 
950
    Q_ASSERT(!relative.isEmpty()); // infinite recursion ahead
 
951
    if (!relative.isEmpty()) {
 
952
        //qDebug() << "done, resolving" << dir << "and adding" << relative;
 
953
        dir = realPath(dir) + relative;
 
954
    }
 
955
    return dir;
 
956
#endif
 
957
}
 
958
 
 
959
// ####### KDE4: should this be removed, in favor of QDir::canonicalPath()?
 
960
// aseigo: QDir::canonicalPath returns QString() if the dir doesn't exist
 
961
//         and this method is often used with the expectation for it to work
 
962
//         even if the directory doesn't exist. so ... no, we can't drop this
 
963
//         yet
 
964
QString
 
965
KStandardDirs::realFilePath(const QString &filename)
 
966
{
 
967
#ifdef Q_WS_WIN
 
968
    LPCWSTR lpIn = (LPCWSTR)filename.utf16();
 
969
    QVarLengthArray<WCHAR, MAX_PATH> buf(MAX_PATH);
 
970
    DWORD len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
 
971
    if (len > (DWORD)buf.size()) {
 
972
        buf.resize(len);
 
973
        len = GetFullPathNameW(lpIn, buf.size(), buf.data(), NULL);
 
974
    }
 
975
    if (len == 0)
 
976
        return QString();
 
977
    return QString::fromUtf16((const unsigned short*)buf.data()).replace(QLatin1Char('\\'),QLatin1Char('/')).toLower();
 
978
#else
 
979
    char realpath_buffer[MAXPATHLEN + 1];
 
980
    memset(realpath_buffer, 0, MAXPATHLEN + 1);
 
981
 
 
982
    /* If the path contains symlinks, get the real name */
 
983
    if (realpath( QFile::encodeName(filename).constData(), realpath_buffer) != 0) {
 
984
        // success, use result from realpath
 
985
        return QFile::decodeName(realpath_buffer);
 
986
    }
 
987
 
 
988
    return filename;
 
989
#endif
 
990
}
 
991
 
 
992
 
 
993
void KStandardDirs::KStandardDirsPrivate::createSpecialResource(const char *type)
 
994
{
 
995
    char hostname[256];
 
996
    hostname[0] = 0;
 
997
    gethostname(hostname, 255);
 
998
    const QString localkdedir = m_prefixes.first();
 
999
    QString dir = localkdedir + QString::fromLatin1(type) + QLatin1Char('-') + QString::fromLocal8Bit(hostname);
 
1000
    char link[1024];
 
1001
    link[1023] = 0;
 
1002
    int result = readlink(QFile::encodeName(dir).constData(), link, 1023);
 
1003
    bool relink = (result == -1) && (errno == ENOENT);
 
1004
    if (result > 0)
 
1005
    {
 
1006
        link[result] = 0;
 
1007
        if (!QDir::isRelativePath(QFile::decodeName(link)))
 
1008
        {
 
1009
            KDE_struct_stat stat_buf;
 
1010
            int res = KDE::lstat(QFile::decodeName(link), &stat_buf);
 
1011
            if ((res == -1) && (errno == ENOENT))
 
1012
            {
 
1013
                relink = true;
 
1014
            }
 
1015
            else if ((res == -1) || (!S_ISDIR(stat_buf.st_mode)))
 
1016
            {
 
1017
                fprintf(stderr, "Error: \"%s\" is not a directory.\n", link);
 
1018
                relink = true;
 
1019
            }
 
1020
            else if (stat_buf.st_uid != getuid())
 
1021
            {
 
1022
                fprintf(stderr, "Error: \"%s\" is owned by uid %d instead of uid %d.\n", link, stat_buf.st_uid, getuid());
 
1023
                relink = true;
 
1024
            }
 
1025
        }
 
1026
    }
 
1027
#ifdef Q_WS_WIN
 
1028
    if (relink)
 
1029
    {
 
1030
        if (!makeDir(dir, 0700))
 
1031
            fprintf(stderr, "failed to create \"%s\"", qPrintable(dir));
 
1032
        else
 
1033
            result = readlink(QFile::encodeName(dir).constData(), link, 1023);
 
1034
    }
 
1035
#else //UNIX
 
1036
    if (relink)
 
1037
    {
 
1038
        QString srv = findExe(QLatin1String("lnusertemp"), installPath("libexec"));
 
1039
        if (srv.isEmpty())
 
1040
            srv = findExe(QLatin1String("lnusertemp"));
 
1041
        if (!srv.isEmpty())
 
1042
        {
 
1043
            if (system(QFile::encodeName(srv) + ' ' + type) == -1) {
 
1044
                fprintf(stderr, "Error: unable to launch lnusertemp command" );
 
1045
            }
 
1046
            result = readlink(QFile::encodeName(dir).constData(), link, 1023);
 
1047
        }
 
1048
    }
 
1049
    if (result > 0)
 
1050
    {
 
1051
        link[result] = 0;
 
1052
        if (link[0] == '/')
 
1053
            dir = QFile::decodeName(link);
 
1054
        else
 
1055
            dir = QDir::cleanPath(dir + QFile::decodeName(link));
 
1056
    }
 
1057
#endif
 
1058
    q->addResourceDir(type, dir + QLatin1Char('/'), false);
 
1059
}
 
1060
 
 
1061
QStringList KStandardDirs::resourceDirs(const char *type) const
 
1062
{
 
1063
    return d->resourceDirs(type, QString());
 
1064
}
 
1065
 
 
1066
QStringList KStandardDirs::KStandardDirsPrivate::resourceDirs(const char* type, const QString& subdirForRestrictions)
 
1067
{
 
1068
    QMutexLocker lock(&m_cacheMutex);
 
1069
    const bool dataRestrictionActive = m_restrictionsActive
 
1070
                                       && (strcmp(type, "data") == 0)
 
1071
                                       && hasDataRestrictions(subdirForRestrictions);
 
1072
 
 
1073
    QMap<QByteArray, QStringList>::const_iterator dirCacheIt = m_dircache.constFind(type);
 
1074
 
 
1075
    QStringList candidates;
 
1076
 
 
1077
    if (dirCacheIt != m_dircache.constEnd() && !dataRestrictionActive) {
 
1078
        //qDebug() << this << "resourceDirs(" << type << "), in cache already";
 
1079
        candidates = *dirCacheIt;
 
1080
    }
 
1081
    else // filling cache
 
1082
    {
 
1083
        //qDebug() << this << "resourceDirs(" << type << "), not in cache";
 
1084
        if (strcmp(type, "socket") == 0)
 
1085
            createSpecialResource(type);
 
1086
        else if (strcmp(type, "tmp") == 0)
 
1087
            createSpecialResource(type);
 
1088
        else if (strcmp(type, "cache") == 0)
 
1089
            createSpecialResource(type);
 
1090
 
 
1091
        QDir testdir;
 
1092
 
 
1093
        bool restrictionActive = false;
 
1094
        if (m_restrictionsActive) {
 
1095
            if (dataRestrictionActive)
 
1096
                restrictionActive = true;
 
1097
            if (m_restrictions.value("all", false))
 
1098
                restrictionActive = true;
 
1099
            else if (m_restrictions.value(type, false))
 
1100
                restrictionActive = true;
 
1101
        }
 
1102
 
 
1103
        QStringList dirs;
 
1104
        dirs = m_relatives.value(type);
 
1105
        const QString typeInstallPath = installPath(type); // could be empty
 
1106
// better #ifdef incasesensitive_filesystem
 
1107
#ifdef Q_WS_WIN
 
1108
        const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath).toLower();
 
1109
        const QString installprefix = installPath("kdedir").toLower();
 
1110
#else
 
1111
        const QString installdir = typeInstallPath.isEmpty() ? QString() : realPath(typeInstallPath);
 
1112
        const QString installprefix = installPath("kdedir");
 
1113
#endif
 
1114
        if (!dirs.isEmpty())
 
1115
        {
 
1116
            bool local = true;
 
1117
 
 
1118
            for (QStringList::ConstIterator it = dirs.constBegin();
 
1119
                 it != dirs.constEnd(); ++it)
 
1120
            {
 
1121
                if ((*it).startsWith(QLatin1Char('%'))) {
 
1122
                    // grab the "data" from "%data/apps"
 
1123
                    const int pos = (*it).indexOf(QLatin1Char('/'));
 
1124
                    QString rel = (*it).mid(1, pos - 1);
 
1125
                    QString rest = (*it).mid(pos + 1);
 
1126
                    const QStringList basedirs = resourceDirs(rel.toUtf8().constData(), subdirForRestrictions);
 
1127
                    for (QStringList::ConstIterator it2 = basedirs.begin();
 
1128
                         it2 != basedirs.end(); ++it2)
 
1129
                    {
 
1130
#ifdef Q_WS_WIN
 
1131
                        const QString path = realPath( *it2 + rest ).toLower();
 
1132
#else
 
1133
                        const QString path = realPath( *it2 + rest );
 
1134
#endif
 
1135
                        testdir.setPath(path);
 
1136
                        if ((local || testdir.exists()) && !candidates.contains(path))
 
1137
                            candidates.append(path);
 
1138
                        local = false;
 
1139
                    }
 
1140
                }
 
1141
            }
 
1142
 
 
1143
            const QStringList *prefixList = 0;
 
1144
            if (strncmp(type, "xdgdata-", 8) == 0)
 
1145
                prefixList = &(xdgdata_prefixes);
 
1146
            else if (strncmp(type, "xdgconf-", 8) == 0)
 
1147
                prefixList = &(xdgconf_prefixes);
 
1148
            else
 
1149
                prefixList = &m_prefixes;
 
1150
 
 
1151
            for (QStringList::ConstIterator pit = prefixList->begin();
 
1152
                 pit != prefixList->end();
 
1153
                 ++pit)
 
1154
            {
 
1155
                if((*pit)!=installprefix||installdir.isEmpty())
 
1156
                {
 
1157
                    for (QStringList::ConstIterator it = dirs.constBegin();
 
1158
                         it != dirs.constEnd(); ++it)
 
1159
                    {
 
1160
                        if ((*it).startsWith(QLatin1Char('%')))
 
1161
                            continue;
 
1162
#ifdef Q_WS_WIN
 
1163
                        const QString path = realPath( *pit + *it ).toLower();
 
1164
#else
 
1165
                        const QString path = realPath( *pit + *it );
 
1166
#endif
 
1167
                        testdir.setPath(path);
 
1168
                        if (local && restrictionActive)
 
1169
                            continue;
 
1170
                        if ((local || testdir.exists()) && !candidates.contains(path))
 
1171
                            candidates.append(path);
 
1172
                    }
 
1173
                    local = false;
 
1174
                }
 
1175
                else
 
1176
                {
 
1177
                    // we have a custom install path, so use this instead of <installprefix>/<relative dir>
 
1178
                    testdir.setPath(installdir);
 
1179
                    if(testdir.exists() && ! candidates.contains(installdir))
 
1180
                        candidates.append(installdir);
 
1181
                }
 
1182
            }
 
1183
        }
 
1184
 
 
1185
        // make sure we find the path where it's installed
 
1186
        if (!installdir.isEmpty()) {
 
1187
            bool ok = true;
 
1188
            foreach (const QString &s, candidates) {
 
1189
                if (installdir.startsWith(s)) {
 
1190
                    ok = false;
 
1191
                    break;
 
1192
                }
 
1193
            }
 
1194
            if (ok)
 
1195
                candidates.append(installdir);
 
1196
        }
 
1197
 
 
1198
        dirs = m_absolutes.value(type);
 
1199
        if (!dirs.isEmpty())
 
1200
            for (QStringList::ConstIterator it = dirs.constBegin();
 
1201
                 it != dirs.constEnd(); ++it)
 
1202
            {
 
1203
                testdir.setPath(*it);
 
1204
                if (testdir.exists()) {
 
1205
#ifdef Q_WS_WIN
 
1206
                    const QString filename = realPath( *it ).toLower();
 
1207
#else
 
1208
                    const QString filename = realPath( *it );
 
1209
#endif
 
1210
                    if (!candidates.contains(filename)) {
 
1211
                        candidates.append(filename);
 
1212
                    }
 
1213
                }
 
1214
            }
 
1215
 
 
1216
        // Insert result into the cache for next time.
 
1217
        // Exception: data_subdir restrictions are per-subdir, so we can't store such results
 
1218
        if (!dataRestrictionActive) {
 
1219
            //kDebug() << this << "Inserting" << type << candidates << "into dircache";
 
1220
            m_dircache.insert(type, candidates);
 
1221
        }
 
1222
    }
 
1223
 
 
1224
#if 0
 
1225
    kDebug(180) << "found dirs for resource" << type << ":" << candidates;
 
1226
#endif
 
1227
 
 
1228
    return candidates;
 
1229
}
 
1230
 
 
1231
#ifdef Q_OS_WIN
 
1232
static QStringList executableExtensions()
 
1233
{
 
1234
    QStringList ret = QString::fromLocal8Bit(qgetenv("PATHEXT")).split(QLatin1Char(';'));
 
1235
    if (!ret.contains(QLatin1String(".exe"), Qt::CaseInsensitive)) {
 
1236
        // If %PATHEXT% does not contain .exe, it is either empty, malformed, or distorted in ways that we cannot support, anyway.
 
1237
        ret.clear();
 
1238
        ret << QLatin1String(".exe")
 
1239
            << QLatin1String(".com")
 
1240
            << QLatin1String(".bat")
 
1241
            << QLatin1String(".cmd");
 
1242
    }
 
1243
    return ret;
 
1244
}
 
1245
#endif
 
1246
 
 
1247
QStringList KStandardDirs::systemPaths( const QString& pstr )
 
1248
{
 
1249
    QStringList tokens;
 
1250
    QString p = pstr;
 
1251
 
 
1252
    if( p.isEmpty() )
 
1253
    {
 
1254
        p = QString::fromLocal8Bit( qgetenv( "PATH" ) );
 
1255
    }
 
1256
 
 
1257
    QString delimiters(QLatin1Char(KPATH_SEPARATOR));
 
1258
    delimiters += QLatin1Char('\b');
 
1259
    tokenize( tokens, p, delimiters );
 
1260
 
 
1261
    QStringList exePaths;
 
1262
 
 
1263
    // split path using : or \b as delimiters
 
1264
    for( int i = 0; i < tokens.count(); i++ )
 
1265
    {
 
1266
        exePaths << KShell::tildeExpand( tokens[ i ] );
 
1267
    }
 
1268
 
 
1269
    return exePaths;
 
1270
}
 
1271
 
 
1272
#ifdef Q_WS_MAC
 
1273
static QString getBundle( const QString& path, bool ignore )
 
1274
{
 
1275
    kDebug(180) << "getBundle(" << path << ", " << ignore << ") called";
 
1276
    QFileInfo info;
 
1277
    QString bundle = path;
 
1278
    bundle += QLatin1String(".app/Contents/MacOS/") + bundle.section(QLatin1Char('/'), -1);
 
1279
    info.setFile( bundle );
 
1280
    FILE *file;
 
1281
    if (file = fopen(info.absoluteFilePath().toUtf8().constData(), "r")) {
 
1282
        fclose(file);
 
1283
        struct stat _stat;
 
1284
        if ((stat(info.absoluteFilePath().toUtf8().constData(), &_stat)) < 0) {
 
1285
            return QString();
 
1286
        }
 
1287
        if ( ignore || (_stat.st_mode & S_IXUSR) ) {
 
1288
            if ( ((_stat.st_mode & S_IFMT) == S_IFREG) || ((_stat.st_mode & S_IFMT) == S_IFLNK) ) {
 
1289
                kDebug(180) << "getBundle(): returning " << bundle;
 
1290
                return bundle;
 
1291
            }
 
1292
        }
 
1293
    }
 
1294
    return QString();
 
1295
}
 
1296
#endif
 
1297
 
 
1298
static QString checkExecutable( const QString& path, bool ignoreExecBit )
 
1299
{
 
1300
#ifdef Q_WS_MAC
 
1301
    QString bundle = getBundle( path, ignoreExecBit );
 
1302
    if ( !bundle.isEmpty() ) {
 
1303
        //kDebug(180) << "findExe(): returning " << bundle;
 
1304
        return bundle;
 
1305
    }
 
1306
#endif
 
1307
    QFileInfo info( path );
 
1308
    QFileInfo orig = info;
 
1309
#if defined(Q_OS_DARWIN) || defined(Q_OS_MAC)
 
1310
    FILE *file;
 
1311
    if (file = fopen(orig.absoluteFilePath().toUtf8().constData(), "r")) {
 
1312
        fclose(file);
 
1313
        struct stat _stat;
 
1314
        if ((stat(orig.absoluteFilePath().toUtf8().constData(), &_stat)) < 0) {
 
1315
            return QString();
 
1316
        }
 
1317
        if ( ignoreExecBit || (_stat.st_mode & S_IXUSR) ) {
 
1318
            if ( ((_stat.st_mode & S_IFMT) == S_IFREG) || ((_stat.st_mode & S_IFMT) == S_IFLNK) ) {
 
1319
                orig.makeAbsolute();
 
1320
                return orig.filePath();
 
1321
            }
 
1322
        }
 
1323
    }
 
1324
    return QString();
 
1325
#else
 
1326
    if( info.exists() && info.isSymLink() )
 
1327
        info = QFileInfo( info.canonicalFilePath() );
 
1328
    if( info.exists() && ( ignoreExecBit || info.isExecutable() ) && info.isFile() ) {
 
1329
        // return absolute path, but without symlinks resolved in order to prevent
 
1330
        // problems with executables that work differently depending on name they are
 
1331
        // run as (for example gunzip)
 
1332
        orig.makeAbsolute();
 
1333
        return orig.filePath();
 
1334
    }
 
1335
    //kDebug(180) << "checkExecutable(): failed, returning empty string";
 
1336
    return QString();
 
1337
#endif
 
1338
}
 
1339
 
 
1340
QString KStandardDirs::findExe( const QString& appname,
 
1341
                                const QString& pstr,
 
1342
                                SearchOptions options )
 
1343
{
 
1344
    //kDebug(180) << "findExe(" << appname << ", pstr, " << ignoreExecBit << ") called";
 
1345
 
 
1346
#ifdef Q_OS_WIN
 
1347
    QStringList executable_extensions = executableExtensions();
 
1348
    if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) {
 
1349
        QString found_exe;
 
1350
        foreach (const QString& extension, executable_extensions) {
 
1351
            found_exe = findExe(appname + extension, pstr, options);
 
1352
            if (!found_exe.isEmpty()) {
 
1353
                return found_exe;
 
1354
            }
 
1355
        }
 
1356
        return QString();
 
1357
    }
 
1358
#endif
 
1359
    QFileInfo info;
 
1360
 
 
1361
    // absolute or relative path?
 
1362
    if (appname.contains(QDir::separator()))
 
1363
    {
 
1364
        //kDebug(180) << "findExe(): absolute path given";
 
1365
        QString path = checkExecutable(appname, options & IgnoreExecBit);
 
1366
        return path;
 
1367
    }
 
1368
 
 
1369
    //kDebug(180) << "findExe(): relative path given";
 
1370
 
 
1371
    QString p = installPath("libexec") + appname;
 
1372
    QString result = checkExecutable(p, options & IgnoreExecBit);
 
1373
    if (!result.isEmpty()) {
 
1374
        //kDebug(180) << "findExe(): returning " << result;
 
1375
        return result;
 
1376
    }
 
1377
 
 
1378
    // Look into the KDE-specific bin dir ("exe" resource) in case KDE was installed into a custom
 
1379
    // prefix, to make things easier ($PATH not required). But not if KDE is in /usr (#241763).
 
1380
    p = installPath("exe");
 
1381
    if (p != QLatin1String("/usr/")) {
 
1382
        p += appname;
 
1383
        result = checkExecutable(p, options & IgnoreExecBit);
 
1384
        if (!result.isEmpty()) {
 
1385
            kDebug(180) << "findExe(): returning " << result;
 
1386
            return result;
 
1387
        }
 
1388
    }
 
1389
 
 
1390
    //kDebug(180) << "findExe(): checking system paths";
 
1391
    const QStringList exePaths = systemPaths( pstr );
 
1392
    for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
 
1393
    {
 
1394
        p = (*it) + QLatin1Char('/');
 
1395
        p += appname;
 
1396
 
 
1397
        // Check for executable in this tokenized path
 
1398
        result = checkExecutable(p, options & IgnoreExecBit);
 
1399
        if (!result.isEmpty()) {
 
1400
            //kDebug(180) << "findExe(): returning " << result;
 
1401
            return result;
 
1402
        }
 
1403
    }
 
1404
 
 
1405
    // If we reach here, the executable wasn't found.
 
1406
    // So return empty string.
 
1407
 
 
1408
    //kDebug(180) << "findExe(): failed, nothing matched";
 
1409
    return QString();
 
1410
}
 
1411
 
 
1412
int KStandardDirs::findAllExe( QStringList& list, const QString& appname,
 
1413
                               const QString& pstr, SearchOptions options )
 
1414
{
 
1415
#ifdef Q_OS_WIN
 
1416
    QStringList executable_extensions = executableExtensions();
 
1417
    if (!executable_extensions.contains(appname.section(QLatin1Char('.'), -1, -1, QString::SectionIncludeLeadingSep), Qt::CaseInsensitive)) {
 
1418
        int total = 0;
 
1419
        foreach (const QString& extension, executable_extensions) {
 
1420
            total += findAllExe (list, appname + extension, pstr, options);
 
1421
        }
 
1422
        return total;
 
1423
    }
 
1424
#endif
 
1425
    QFileInfo info;
 
1426
    QString p;
 
1427
    list.clear();
 
1428
 
 
1429
    const QStringList exePaths = systemPaths( pstr );
 
1430
    for (QStringList::ConstIterator it = exePaths.begin(); it != exePaths.end(); ++it)
 
1431
    {
 
1432
        p = (*it) + QLatin1Char('/');
 
1433
        p += appname;
 
1434
 
 
1435
#ifdef Q_WS_MAC
 
1436
        QString bundle = getBundle( p, (options & IgnoreExecBit) );
 
1437
        if ( !bundle.isEmpty() ) {
 
1438
            //kDebug(180) << "findExe(): returning " << bundle;
 
1439
            list.append( bundle );
 
1440
        }
 
1441
#endif
 
1442
 
 
1443
        info.setFile( p );
 
1444
 
 
1445
        if( info.exists() && ( ( options & IgnoreExecBit ) || info.isExecutable())
 
1446
            && info.isFile() ) {
 
1447
            list.append( p );
 
1448
        }
 
1449
    }
 
1450
 
 
1451
    return list.count();
 
1452
}
 
1453
 
 
1454
static inline QString equalizePath(QString &str)
 
1455
{
 
1456
#ifdef Q_WS_WIN
 
1457
    // filter pathes through QFileInfo to have always
 
1458
    // the same case for drive letters
 
1459
    QFileInfo f(str);
 
1460
    if (f.isAbsolute())
 
1461
        return f.absoluteFilePath();
 
1462
    else
 
1463
#endif
 
1464
        return str;
 
1465
}
 
1466
 
 
1467
static void tokenize(QStringList& tokens, const QString& str,
 
1468
                    const QString& delim)
 
1469
{
 
1470
    const int len = str.length();
 
1471
    QString token;
 
1472
 
 
1473
    for(int index = 0; index < len; index++) {
 
1474
        if (delim.contains(str[index])) {
 
1475
            tokens.append(equalizePath(token));
 
1476
            token.clear();
 
1477
        } else {
 
1478
            token += str[index];
 
1479
        }
 
1480
    }
 
1481
    if (!token.isEmpty()) {
 
1482
        tokens.append(equalizePath(token));
 
1483
    }
 
1484
}
 
1485
 
 
1486
#ifndef KDE_NO_DEPRECATED
 
1487
QString KStandardDirs::kde_default(const char *type)
 
1488
{
 
1489
    return QString(QLatin1Char('%')) + QString::fromLatin1(type) + QLatin1Char('/');
 
1490
}
 
1491
#endif
 
1492
 
 
1493
QString KStandardDirs::saveLocation(const char *type,
 
1494
                                    const QString& suffix,
 
1495
                                    bool create) const
 
1496
{
 
1497
    QMutexLocker lock(&d->m_cacheMutex);
 
1498
    QString path = d->m_savelocations.value(type);
 
1499
    if (path.isEmpty())
 
1500
    {
 
1501
        QStringList dirs = d->m_relatives.value(type);
 
1502
        if (dirs.isEmpty() && (
 
1503
                (strcmp(type, "socket") == 0) ||
 
1504
                (strcmp(type, "tmp") == 0) ||
 
1505
                (strcmp(type, "cache") == 0) ))
 
1506
        {
 
1507
            (void) resourceDirs(type); // Generate socket|tmp|cache resource.
 
1508
            dirs = d->m_relatives.value(type); // Search again.
 
1509
        }
 
1510
        if (!dirs.isEmpty())
 
1511
        {
 
1512
            path = dirs.first();
 
1513
 
 
1514
            if (path.startsWith(QLatin1Char('%'))) {
 
1515
                // grab the "data" from "%data/apps"
 
1516
                const int pos = path.indexOf(QLatin1Char('/'));
 
1517
                QString rel = path.mid(1, pos - 1);
 
1518
                QString rest = path.mid(pos + 1);
 
1519
                QString basepath = saveLocation(rel.toUtf8().constData());
 
1520
                path = basepath + rest;
 
1521
            } else
 
1522
 
 
1523
                // Check for existence of typed directory + suffix
 
1524
                if (strncmp(type, "xdgdata-", 8) == 0) {
 
1525
                    path = realPath( localxdgdatadir() + path ) ;
 
1526
                } else if (strncmp(type, "xdgconf-", 8) == 0) {
 
1527
                    path = realPath( localxdgconfdir() + path );
 
1528
                } else {
 
1529
                    path = realPath( localkdedir() + path );
 
1530
                }
 
1531
        }
 
1532
        else {
 
1533
            dirs = d->m_absolutes.value(type);
 
1534
            if (dirs.isEmpty()) {
 
1535
                qFatal("KStandardDirs: The resource type %s is not registered", type);
 
1536
            } else {
 
1537
                path = realPath(dirs.first());
 
1538
            }
 
1539
        }
 
1540
 
 
1541
        d->m_savelocations.insert(type, path.endsWith(QLatin1Char('/')) ? path : path + QLatin1Char('/'));
 
1542
    }
 
1543
    QString fullPath = path + suffix;
 
1544
 
 
1545
    KDE_struct_stat st;
 
1546
    if (KDE::stat(fullPath, &st) != 0 || !(S_ISDIR(st.st_mode))) {
 
1547
        if(!create) {
 
1548
#ifndef NDEBUG
 
1549
            // Too much noise from kbuildsycoca4 -- it's fine if this happens from KConfig
 
1550
            // when parsing global files without a local equivalent.
 
1551
            //kDebug(180) << QString("save location %1 doesn't exist").arg(fullPath);
 
1552
#endif
 
1553
            return fullPath;
 
1554
        }
 
1555
        if(!makeDir(fullPath, 0700)) {
 
1556
            return fullPath;
 
1557
        }
 
1558
        d->m_dircache.remove(type);
 
1559
    }
 
1560
    if (!fullPath.endsWith(QLatin1Char('/')))
 
1561
        fullPath += QLatin1Char('/');
 
1562
    return fullPath;
 
1563
}
 
1564
 
 
1565
// KDE5: make the method const
 
1566
QString KStandardDirs::relativeLocation(const char *type, const QString &absPath)
 
1567
{
 
1568
    QString fullPath = absPath;
 
1569
    int i = absPath.lastIndexOf(QLatin1Char('/'));
 
1570
    if (i != -1) {
 
1571
        fullPath = realFilePath(absPath); // Normalize
 
1572
    }
 
1573
 
 
1574
    const QStringList candidates = resourceDirs(type);
 
1575
 
 
1576
    for (QStringList::ConstIterator it = candidates.begin();
 
1577
         it != candidates.end(); ++it) {
 
1578
        if (fullPath.startsWith(*it)) {
 
1579
            return fullPath.mid((*it).length());
 
1580
        }
 
1581
    }
 
1582
    return absPath;
 
1583
}
 
1584
 
 
1585
 
 
1586
bool KStandardDirs::makeDir(const QString& dir, int mode)
 
1587
{
 
1588
    // we want an absolute path
 
1589
    if (QDir::isRelativePath(dir))
 
1590
        return false;
 
1591
 
 
1592
#ifdef Q_WS_WIN
 
1593
    return QDir().mkpath(dir);
 
1594
#else
 
1595
    QString target = dir;
 
1596
    uint len = target.length();
 
1597
 
 
1598
    // append trailing slash if missing
 
1599
    if (dir.at(len - 1) != QLatin1Char('/'))
 
1600
        target += QLatin1Char('/');
 
1601
 
 
1602
    QString base;
 
1603
    uint i = 1;
 
1604
 
 
1605
    while( i < len )
 
1606
    {
 
1607
        KDE_struct_stat st;
 
1608
        int pos = target.indexOf(QLatin1Char('/'), i);
 
1609
        base += target.mid(i - 1, pos - i + 1);
 
1610
        QByteArray baseEncoded = QFile::encodeName(base);
 
1611
        // bail out if we encountered a problem
 
1612
        if (KDE_stat(baseEncoded, &st) != 0)
 
1613
        {
 
1614
            // Directory does not exist....
 
1615
            // Or maybe a dangling symlink ?
 
1616
            if (KDE_lstat(baseEncoded, &st) == 0)
 
1617
                (void)unlink(baseEncoded); // try removing
 
1618
 
 
1619
            if (KDE_mkdir(baseEncoded, static_cast<mode_t>(mode)) != 0) {
 
1620
                baseEncoded.prepend( "trying to create local folder " );
 
1621
                perror(baseEncoded.constData());
 
1622
                return false; // Couldn't create it :-(
 
1623
            }
 
1624
        }
 
1625
        i = pos + 1;
 
1626
    }
 
1627
    return true;
 
1628
#endif
 
1629
}
 
1630
 
 
1631
static QString readEnvPath(const char *env)
 
1632
{
 
1633
    QByteArray c_path;
 
1634
#ifndef _WIN32_WCE
 
1635
    c_path = qgetenv(env);
 
1636
    if (c_path.isEmpty())
 
1637
        return QString();
 
1638
#else
 
1639
    bool ok;
 
1640
    QString retval = getWin32RegistryValue(HKEY_LOCAL_MACHINE, "Software\\kde", "KDEDIRS", &ok);
 
1641
    if (!ok){
 
1642
        return QString();
 
1643
    } else {
 
1644
        c_path = retval.toAscii();
 
1645
    }
 
1646
#endif
 
1647
    return QDir::fromNativeSeparators(QFile::decodeName(c_path));
 
1648
}
 
1649
 
 
1650
#ifdef __linux__
 
1651
static QString executablePrefix()
 
1652
{
 
1653
    char path_buffer[MAXPATHLEN + 1];
 
1654
    path_buffer[MAXPATHLEN] = 0;
 
1655
    int length = readlink ("/proc/self/exe", path_buffer, MAXPATHLEN);
 
1656
    if (length == -1)
 
1657
        return QString();
 
1658
 
 
1659
    path_buffer[length] = '\0';
 
1660
 
 
1661
    QString path = QFile::decodeName(path_buffer);
 
1662
 
 
1663
    if(path.isEmpty())
 
1664
        return QString();
 
1665
 
 
1666
    int pos = path.lastIndexOf(QLatin1Char('/')); // Skip filename
 
1667
    if(pos <= 0)
 
1668
        return QString();
 
1669
    pos = path.lastIndexOf(QLatin1Char('/'), pos - 1); // Skip last directory
 
1670
    if(pos <= 0)
 
1671
        return QString();
 
1672
 
 
1673
    return path.left(pos);
 
1674
}
 
1675
#endif
 
1676
 
 
1677
void KStandardDirs::addResourcesFrom_krcdirs()
 
1678
{
 
1679
    QString localFile = QDir::currentPath() + QLatin1String("/.krcdirs");
 
1680
    if (!QFile::exists(localFile))
 
1681
        return;
 
1682
 
 
1683
    QSettings iniFile(localFile, QSettings::IniFormat);
 
1684
    iniFile.beginGroup(QString::fromLatin1("KStandardDirs"));
 
1685
    const QStringList resources = iniFile.allKeys();
 
1686
    foreach(const QString &key, resources)
 
1687
    {
 
1688
        QDir path(iniFile.value(key).toString());
 
1689
        if (!path.exists())
 
1690
            continue;
 
1691
 
 
1692
        if(path.makeAbsolute())
 
1693
            addResourceDir(key.toAscii(), path.path(), false);
 
1694
    }
 
1695
}
 
1696
 
 
1697
void KStandardDirs::addKDEDefaults()
 
1698
{
 
1699
    addResourcesFrom_krcdirs();
 
1700
 
 
1701
    QStringList kdedirList;
 
1702
    // begin KDEDIRS
 
1703
    QString kdedirs = readEnvPath("KDEDIRS");
 
1704
 
 
1705
    if (!kdedirs.isEmpty())
 
1706
    {
 
1707
        tokenize(kdedirList, kdedirs, QString(QLatin1Char(KPATH_SEPARATOR)));
 
1708
    }
 
1709
    kdedirList.append(installPath("kdedir"));
 
1710
 
 
1711
    QString execPrefix(QFile::decodeName(EXEC_INSTALL_PREFIX));
 
1712
    if (!execPrefix.isEmpty() && !kdedirList.contains(execPrefix))
 
1713
        kdedirList.append(execPrefix);
 
1714
#ifdef __linux__
 
1715
    const QString linuxExecPrefix = executablePrefix();
 
1716
    if ( !linuxExecPrefix.isEmpty() )
 
1717
        kdedirList.append( linuxExecPrefix );
 
1718
#endif
 
1719
 
 
1720
    // We treat root differently to prevent a "su" shell messing up the
 
1721
    // file permissions in the user's home directory.
 
1722
    QString localKdeDir = readEnvPath(getuid() ? "KDEHOME" : "KDEROOTHOME");
 
1723
    if (!localKdeDir.isEmpty()) {
 
1724
        if (!localKdeDir.endsWith(QLatin1Char('/')))
 
1725
            localKdeDir += QLatin1Char('/');
 
1726
    } else {
 
1727
        // TODO KDE5: make localKdeDir equal to localXdgDir (which is determined further below and
 
1728
        // defaults to ~/.config) + '/' + $KDECONFIG (which would default to e.g. "KDE")
 
1729
        // This would mean ~/.config/KDE/ by default, more xdg-compliant.
 
1730
 
 
1731
#if defined(Q_WS_MACX)
 
1732
        localKdeDir =  QDir::homePath() + QLatin1String("/Library/Preferences/KDE/");
 
1733
#elif defined(Q_WS_WIN)
 
1734
#ifndef _WIN32_WCE
 
1735
        WCHAR wPath[MAX_PATH+1];
 
1736
        if ( SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK) {
 
1737
          localKdeDir = QDir::fromNativeSeparators(QString::fromUtf16((const ushort *) wPath)) + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
 
1738
        } else {
 
1739
#endif
 
1740
          localKdeDir =  QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
 
1741
#ifndef _WIN32_WCE
 
1742
        }
 
1743
#endif
 
1744
#else
 
1745
        localKdeDir =  QDir::homePath() + QLatin1Char('/') + QString::fromLatin1(KDE_DEFAULT_HOME) + QLatin1Char('/');
 
1746
#endif
 
1747
    }
 
1748
 
 
1749
    if (localKdeDir != QLatin1String("-/"))
 
1750
    {
 
1751
        localKdeDir = KShell::tildeExpand(localKdeDir);
 
1752
        addPrefix(localKdeDir);
 
1753
    }
 
1754
 
 
1755
#ifdef Q_WS_MACX
 
1756
    // Adds the "Contents" directory of the current application bundle to
 
1757
    // the search path. This way bundled resources can be found.
 
1758
    QDir bundleDir(mac_app_filename());
 
1759
    if (bundleDir.dirName() == QLatin1String("MacOS")) { // just to be sure we're in a bundle
 
1760
        bundleDir.cdUp();
 
1761
        // now dirName should be "Contents". In there we can find our normal
 
1762
        // dir-structure, beginning with "share"
 
1763
        addPrefix(bundleDir.absolutePath());
 
1764
    }
 
1765
#endif
 
1766
 
 
1767
    QStringList::ConstIterator end(kdedirList.end());
 
1768
    for (QStringList::ConstIterator it = kdedirList.constBegin();
 
1769
         it != kdedirList.constEnd(); ++it)
 
1770
    {
 
1771
        const QString dir = KShell::tildeExpand(*it);
 
1772
        addPrefix(dir);
 
1773
    }
 
1774
    // end KDEDIRS
 
1775
 
 
1776
    // begin XDG_CONFIG_XXX
 
1777
    QStringList xdgdirList;
 
1778
    QString xdgdirs = readEnvPath("XDG_CONFIG_DIRS");
 
1779
    if (!xdgdirs.isEmpty())
 
1780
    {
 
1781
        tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR)));
 
1782
    }
 
1783
    else
 
1784
    {
 
1785
        xdgdirList.clear();
 
1786
        xdgdirList.append(QString::fromLatin1("/etc/xdg"));
 
1787
#ifdef Q_WS_WIN
 
1788
        xdgdirList.append(installPath("kdedir") + QString::fromLatin1("etc/xdg"));
 
1789
#else
 
1790
        xdgdirList.append(QFile::decodeName(KDESYSCONFDIR "/xdg"));
 
1791
#endif
 
1792
    }
 
1793
 
 
1794
    QString localXdgDir = readEnvPath("XDG_CONFIG_HOME");
 
1795
    if (!localXdgDir.isEmpty()) {
 
1796
        if (!localXdgDir.endsWith(QLatin1Char('/')))
 
1797
            localXdgDir += QLatin1Char('/');
 
1798
    } else {
 
1799
#ifdef Q_WS_MACX
 
1800
        localXdgDir = QDir::homePath() + QString::fromLatin1("/Library/Preferences/XDG/");
 
1801
#else
 
1802
        localXdgDir = QDir::homePath() + QString::fromLatin1("/.config/");
 
1803
#endif
 
1804
    }
 
1805
 
 
1806
    localXdgDir = KShell::tildeExpand(localXdgDir);
 
1807
    addXdgConfigPrefix(localXdgDir);
 
1808
 
 
1809
    for (QStringList::ConstIterator it = xdgdirList.constBegin();
 
1810
         it != xdgdirList.constEnd(); ++it)
 
1811
    {
 
1812
        QString dir = KShell::tildeExpand(*it);
 
1813
        addXdgConfigPrefix(dir);
 
1814
    }
 
1815
    // end XDG_CONFIG_XXX
 
1816
 
 
1817
    // begin XDG_DATA_XXX
 
1818
    QStringList kdedirDataDirs;
 
1819
    for (QStringList::ConstIterator it = kdedirList.constBegin();
 
1820
         it != kdedirList.constEnd(); ++it) {
 
1821
        QString dir = *it;
 
1822
        if (!dir.endsWith(QLatin1Char('/')))
 
1823
            dir += QLatin1Char('/');
 
1824
        kdedirDataDirs.append(dir + QLatin1String("share/"));
 
1825
    }
 
1826
 
 
1827
    xdgdirs = readEnvPath("XDG_DATA_DIRS");
 
1828
    if (!xdgdirs.isEmpty()) {
 
1829
        tokenize(xdgdirList, xdgdirs, QString(QLatin1Char(KPATH_SEPARATOR)));
 
1830
        // Ensure the kdedirDataDirs are in there too,
 
1831
        // otherwise resourceDirs() will add kdedir/share/applications/kde4
 
1832
        // as returned by installPath(), and that's incorrect.
 
1833
        Q_FOREACH(const QString& dir, kdedirDataDirs) {
 
1834
            if (!xdgdirList.contains(dir))
 
1835
                xdgdirList.append(dir);
 
1836
        }
 
1837
    } else {
 
1838
        xdgdirList = kdedirDataDirs;
 
1839
#ifndef Q_WS_WIN
 
1840
        xdgdirList.append(QString::fromLatin1("/usr/local/share/"));
 
1841
        xdgdirList.append(QString::fromLatin1("/usr/share/"));
 
1842
#endif
 
1843
    }
 
1844
 
 
1845
    localXdgDir = readEnvPath("XDG_DATA_HOME");
 
1846
    if (!localXdgDir.isEmpty())
 
1847
    {
 
1848
        if (localXdgDir[localXdgDir.length()-1] != QLatin1Char('/'))
 
1849
            localXdgDir += QLatin1Char('/');
 
1850
    }
 
1851
    else
 
1852
    {
 
1853
        localXdgDir = QDir::homePath() + QLatin1String("/.local/share/");
 
1854
    }
 
1855
 
 
1856
    localXdgDir = KShell::tildeExpand(localXdgDir);
 
1857
    addXdgDataPrefix(localXdgDir);
 
1858
 
 
1859
    for (QStringList::ConstIterator it = xdgdirList.constBegin();
 
1860
         it != xdgdirList.constEnd(); ++it)
 
1861
    {
 
1862
        QString dir = KShell::tildeExpand(*it);
 
1863
        addXdgDataPrefix(dir);
 
1864
    }
 
1865
    // end XDG_DATA_XXX
 
1866
 
 
1867
 
 
1868
    addResourceType("lib", 0, "lib" KDELIBSUFF "/");
 
1869
 
 
1870
    uint index = 0;
 
1871
    while (types_indices[index] != -1) {
 
1872
        addResourceType(types_string + types_indices[index], 0, types_string + types_indices[index+1], true);
 
1873
        index+=2;
 
1874
    }
 
1875
    addResourceType("exe", "lib", "kde4/libexec", true );
 
1876
 
 
1877
    addResourceDir("home", QDir::homePath(), false);
 
1878
 
 
1879
    addResourceType("autostart", "xdgconf-autostart", "/"); // merge them, start with xdg autostart
 
1880
    addResourceType("autostart", NULL, "share/autostart"); // KDE ones are higher priority
 
1881
}
 
1882
 
 
1883
static QStringList lookupProfiles(const QString &mapFile)
 
1884
{
 
1885
    QStringList profiles;
 
1886
 
 
1887
    if (mapFile.isEmpty() || !QFile::exists(mapFile))
 
1888
    {
 
1889
        profiles << QString::fromLatin1("default");
 
1890
        return profiles;
 
1891
    }
 
1892
 
 
1893
    struct passwd *pw = getpwuid(geteuid());
 
1894
    if (!pw)
 
1895
    {
 
1896
        profiles << QString::fromLatin1("default");
 
1897
        return profiles; // Not good
 
1898
    }
 
1899
 
 
1900
    QByteArray user = pw->pw_name;
 
1901
 
 
1902
    gid_t sup_gids[512];
 
1903
    int sup_gids_nr = getgroups(512, sup_gids);
 
1904
 
 
1905
    KConfig mapCfgFile(mapFile);
 
1906
    KConfigGroup mapCfg(&mapCfgFile, "Users");
 
1907
    if (mapCfg.hasKey(user.constData()))
 
1908
    {
 
1909
        profiles = mapCfg.readEntry(user.constData(), QStringList());
 
1910
        return profiles;
 
1911
    }
 
1912
 
 
1913
    const KConfigGroup generalGrp(&mapCfgFile, "General");
 
1914
    const QStringList groups = generalGrp.readEntry("groups", QStringList());
 
1915
 
 
1916
    const KConfigGroup groupsGrp(&mapCfgFile, "Groups");
 
1917
 
 
1918
    for( QStringList::ConstIterator it = groups.begin();
 
1919
         it != groups.end(); ++it )
 
1920
    {
 
1921
        QByteArray grp = (*it).toUtf8();
 
1922
        // Check if user is in this group
 
1923
        struct group *grp_ent = getgrnam(grp);
 
1924
        if (!grp_ent) continue;
 
1925
        gid_t gid = grp_ent->gr_gid;
 
1926
        if (pw->pw_gid == gid)
 
1927
        {
 
1928
            // User is in this group --> add profiles
 
1929
            profiles += groupsGrp.readEntry(*it, QStringList());
 
1930
        }
 
1931
        else
 
1932
        {
 
1933
            for(int i = 0; i < sup_gids_nr; i++)
 
1934
            {
 
1935
                if (sup_gids[i] == gid)
 
1936
                {
 
1937
                    // User is in this group --> add profiles
 
1938
                    profiles += groupsGrp.readEntry(*it, QStringList());
 
1939
                    break;
 
1940
                }
 
1941
            }
 
1942
        }
 
1943
    }
 
1944
 
 
1945
    if (profiles.isEmpty())
 
1946
        profiles << QString::fromLatin1("default");
 
1947
    return profiles;
 
1948
}
 
1949
 
 
1950
extern bool kde_kiosk_admin;
 
1951
 
 
1952
bool KStandardDirs::addCustomized(KConfig *config)
 
1953
{
 
1954
    if (!d->m_checkRestrictions) // there are already customized entries
 
1955
        return false; // we just quit and hope they are the right ones
 
1956
 
 
1957
    // save the numbers of config directories. If this changes,
 
1958
    // we will return true to give KConfig a chance to reparse
 
1959
    int configdirs = resourceDirs("config").count();
 
1960
 
 
1961
    if (true)
 
1962
    {
 
1963
        // reading the prefixes in
 
1964
        QString group = QLatin1String("Directories");
 
1965
        KConfigGroup cg(config, group);
 
1966
 
 
1967
        QString kioskAdmin = cg.readEntry("kioskAdmin");
 
1968
        if (!kioskAdmin.isEmpty() && !kde_kiosk_admin)
 
1969
        {
 
1970
            int i = kioskAdmin.indexOf(QLatin1Char(':'));
 
1971
            QString user = kioskAdmin.left(i);
 
1972
            QString host = kioskAdmin.mid(i+1);
 
1973
 
 
1974
            KUser thisUser;
 
1975
            char hostname[ 256 ];
 
1976
            hostname[ 0 ] = '\0';
 
1977
            if (!gethostname( hostname, 255 ))
 
1978
                hostname[sizeof(hostname)-1] = '\0';
 
1979
 
 
1980
            if ((user == thisUser.loginName()) &&
 
1981
                (host.isEmpty() || (host == QLatin1String(hostname))))
 
1982
            {
 
1983
                kde_kiosk_admin = true;
 
1984
            }
 
1985
        }
 
1986
 
 
1987
        bool readProfiles = true;
 
1988
 
 
1989
        if (kde_kiosk_admin && !qgetenv("KDE_KIOSK_NO_PROFILES").isEmpty())
 
1990
            readProfiles = false;
 
1991
 
 
1992
        QString userMapFile = cg.readEntry("userProfileMapFile");
 
1993
        QString profileDirsPrefix = cg.readEntry("profileDirsPrefix");
 
1994
        if (!profileDirsPrefix.isEmpty() && !profileDirsPrefix.endsWith(QLatin1Char('/')))
 
1995
            profileDirsPrefix.append(QLatin1Char('/'));
 
1996
 
 
1997
        QStringList profiles;
 
1998
        if (readProfiles)
 
1999
            profiles = lookupProfiles(userMapFile);
 
2000
        QString profile;
 
2001
 
 
2002
        bool priority = false;
 
2003
        while(true)
 
2004
        {
 
2005
            KConfigGroup cg(config, group);
 
2006
            const QStringList list = cg.readEntry("prefixes", QStringList());
 
2007
            for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
 
2008
            {
 
2009
                addPrefix(*it, priority);
 
2010
                addXdgConfigPrefix(*it + QLatin1String("/etc/xdg"), priority);
 
2011
                addXdgDataPrefix(*it + QLatin1String("/share"), priority);
 
2012
            }
 
2013
            // If there are no prefixes defined, check if there is a directory
 
2014
            // for this profile under <profileDirsPrefix>
 
2015
            if (list.isEmpty() && !profile.isEmpty() && !profileDirsPrefix.isEmpty())
 
2016
            {
 
2017
                QString dir = profileDirsPrefix + profile;
 
2018
                addPrefix(dir, priority);
 
2019
                addXdgConfigPrefix(dir + QLatin1String("/etc/xdg"), priority);
 
2020
                addXdgDataPrefix(dir + QLatin1String("/share"), priority);
 
2021
            }
 
2022
 
 
2023
            // iterating over all entries in the group Directories
 
2024
            // to find entries that start with dir_$type
 
2025
            const QMap<QString, QString> entries = config->entryMap(group);
 
2026
            for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
 
2027
                 it2 != entries.end(); ++it2)
 
2028
            {
 
2029
                const QString key = it2.key();
 
2030
                if (key.startsWith(QLatin1String("dir_"))) {
 
2031
                    // generate directory list, there may be more than 1.
 
2032
                    QStringList dirs = (*it2).split(QString(QLatin1Char(',')));
 
2033
                    QStringList::Iterator sIt(dirs.begin());
 
2034
                    QString resType = key.mid(4);
 
2035
                    for (; sIt != dirs.end(); ++sIt)
 
2036
                    {
 
2037
                        addResourceDir(resType.toLatin1(), *sIt, priority);
 
2038
                    }
 
2039
                }
 
2040
            }
 
2041
            if (profiles.isEmpty())
 
2042
                break;
 
2043
            profile = profiles.back();
 
2044
            group = QString::fromLatin1("Directories-%1").arg(profile);
 
2045
            profiles.pop_back();
 
2046
            priority = true;
 
2047
        }
 
2048
    }
 
2049
 
 
2050
    // Process KIOSK restrictions.
 
2051
    if (!kde_kiosk_admin || qgetenv("KDE_KIOSK_NO_RESTRICTIONS").isEmpty())
 
2052
    {
 
2053
        KConfigGroup cg(config, "KDE Resource Restrictions");
 
2054
        const QMap<QString, QString> entries = cg.entryMap();
 
2055
        for (QMap<QString, QString>::ConstIterator it2 = entries.begin();
 
2056
             it2 != entries.end(); ++it2)
 
2057
        {
 
2058
            const QString key = it2.key();
 
2059
            if (!cg.readEntry(key, true))
 
2060
            {
 
2061
                d->m_restrictionsActive = true;
 
2062
                const QByteArray cKey = key.toLatin1();
 
2063
                d->m_restrictions.insert(cKey, true);
 
2064
                d->m_dircache.remove(cKey);
 
2065
                d->m_savelocations.remove(cKey);
 
2066
            }
 
2067
        }
 
2068
    }
 
2069
 
 
2070
    // check if the number of config dirs changed
 
2071
    bool configDirsChanged = (resourceDirs("config").count() != configdirs);
 
2072
    // If the config dirs changed, we check kiosk restrictions again.
 
2073
    d->m_checkRestrictions = configDirsChanged;
 
2074
    // return true if the number of config dirs changed: reparse config file
 
2075
    return configDirsChanged;
 
2076
}
 
2077
 
 
2078
QString KStandardDirs::localkdedir() const
 
2079
{
 
2080
    // Return the prefix to use for saving
 
2081
    return d->m_prefixes.first();
 
2082
}
 
2083
 
 
2084
QString KStandardDirs::localxdgdatadir() const
 
2085
{
 
2086
    // Return the prefix to use for saving
 
2087
    return d->xdgdata_prefixes.first();
 
2088
}
 
2089
 
 
2090
QString KStandardDirs::localxdgconfdir() const
 
2091
{
 
2092
    // Return the prefix to use for saving
 
2093
    return d->xdgconf_prefixes.first();
 
2094
}
 
2095
 
 
2096
 
 
2097
// just to make code more readable without macros
 
2098
QString KStandardDirs::locate( const char *type,
 
2099
                               const QString& filename, const KComponentData &cData)
 
2100
{
 
2101
    return cData.dirs()->findResource(type, filename);
 
2102
}
 
2103
 
 
2104
QString KStandardDirs::locateLocal( const char *type,
 
2105
                                    const QString& filename, const KComponentData &cData)
 
2106
{
 
2107
    return locateLocal(type, filename, true, cData);
 
2108
}
 
2109
 
 
2110
QString KStandardDirs::locateLocal( const char *type,
 
2111
                                    const QString& filename, bool createDir,
 
2112
                                    const KComponentData &cData)
 
2113
{
 
2114
    // try to find slashes. If there are some, we have to
 
2115
    // create the subdir first
 
2116
    int slash = filename.lastIndexOf(QLatin1Char('/')) + 1;
 
2117
    if (!slash) { // only one filename
 
2118
        return cData.dirs()->saveLocation(type, QString(), createDir) + filename;
 
2119
    }
 
2120
 
 
2121
    // split path from filename
 
2122
    QString dir = filename.left(slash);
 
2123
    QString file = filename.mid(slash);
 
2124
    return cData.dirs()->saveLocation(type, dir, createDir) + file;
 
2125
}
 
2126
 
 
2127
bool KStandardDirs::checkAccess(const QString& pathname, int mode)
 
2128
{
 
2129
    int accessOK = KDE::access( pathname, mode );
 
2130
    if ( accessOK == 0 )
 
2131
        return true;  // OK, I can really access the file
 
2132
 
 
2133
    // else
 
2134
    // if we want to write the file would be created. Check, if the
 
2135
    // user may write to the directory to create the file.
 
2136
    if ( (mode & W_OK) == 0 )
 
2137
        return false;   // Check for write access is not part of mode => bail out
 
2138
 
 
2139
 
 
2140
    if (!KDE::access( pathname, F_OK)) // if it already exists
 
2141
        return false;
 
2142
 
 
2143
    //strip the filename (everything until '/' from the end
 
2144
    QString dirName(pathname);
 
2145
    int pos = dirName.lastIndexOf(QLatin1Char('/'));
 
2146
    if ( pos == -1 )
 
2147
        return false;   // No path in argument. This is evil, we won't allow this
 
2148
    else if ( pos == 0 ) // don't turn e.g. /root into an empty string
 
2149
        pos = 1;
 
2150
 
 
2151
    dirName.truncate(pos); // strip everything starting from the last '/'
 
2152
 
 
2153
    accessOK = KDE::access( dirName, W_OK );
 
2154
    // -?- Can I write to the accessed diretory
 
2155
    if ( accessOK == 0 )
 
2156
        return true;  // Yes
 
2157
    else
 
2158
        return false; // No
 
2159
}
 
2160