From 8daf06dcacd9b2b31a1987d47d23943db948e1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Hohnst=C3=A4dt?= Date: Tue, 27 Apr 2021 14:11:31 +0200 Subject: [PATCH] Close #259: Follow the XDG base directory specification After dropping Qt4 support, the Qt5 QStandardPaths class can be used to replace my implementation of directory discovery. QStandardPaths follows the XDG specification. --- Local.mak.in | 2 +- lib/db_temp.cpp | 52 +++++++++------ lib/func.cpp | 152 +++++++++++++++++++------------------------- lib/func.h | 1 - lib/main.cpp | 20 ++++-- lib/oid.cpp | 41 ++++-------- widgets/MW_help.cpp | 3 +- 7 files changed, 129 insertions(+), 142 deletions(-) diff --git a/Local.mak.in b/Local.mak.in index d0900321..4d61750b 100644 --- a/Local.mak.in +++ b/Local.mak.in @@ -6,7 +6,7 @@ export TOPDIR=@abs_srcdir@ export VERSION=@XCA_VERSION@ export HOST=@HOST@ -CPPFLAGS+=-Wall -Wextra -DXCA_PREFIX=\"${xca_prefix}\" -DETC=\"@sysconfdir@\" -DDOCDIR=\"@docdir@\" +CPPFLAGS+=-Wall -Wextra -DETC=\"@sysconfdir@\" -DDOCDIR=\"@docdir@\" CFLAGS+=-O2 -ggdb -std=c++11 @CXXFLAGS@ LIBS=@LIBS@ EXTRA_VERSION=@EXTRA_VERSION@ diff --git a/lib/db_temp.cpp b/lib/db_temp.cpp index 14a84270..c5fa3fe7 100644 --- a/lib/db_temp.cpp +++ b/lib/db_temp.cpp @@ -19,36 +19,50 @@ db_temp::db_temp() : db_x509name("templates") { + /* XCA loads templates from private space ($HOME/.local/) + * Host specific (/usr/local) and distribution (/usr) + * The first .xca found avoids other .xca to be loaded + */ + QSet template_files; + load_temp l; + sqlHashTable = "templates"; pkitype << tmpl; updateHeaders(); loadContainer(); - QDir dir; - if (!dir.cd(getPrefix())) - return; - dir.setFilter(QDir::Files | QDir::NoSymLinks); - QFileInfoList list = dir.entryInfoList(); - load_temp l; pki_temp *tmpl = new pki_temp(tr("Empty template")); tmpl->setAsPreDefined(); predefs << tmpl; - for (int i = 0; i < list.size(); ++i) { - QFileInfo fileInfo = list.at(i); - QString name = getPrefix() + "/" + fileInfo.fileName(); - if (!name.endsWith(".xca", Qt::CaseInsensitive)) - continue; - try { - tmpl = dynamic_cast(l.loadItem(name)); - if (tmpl) { - tmpl->setAsPreDefined(); - predefs << tmpl; + foreach(QString d, QStandardPaths::standardLocations( + QStandardPaths::AppDataLocation)) + { + QFileInfoList list = QDir(d).entryInfoList( + QStringList("*.xca"), + QDir::Files | QDir::NoSymLinks | + QDir::NoDot | QDir::Readable); + + foreach(QFileInfo fileInfo, list) { + if (template_files.contains(fileInfo.fileName())) + continue; + + qWarning() << "LOAD TMP" << fileInfo.absoluteFilePath() + << fileInfo.fileName(); + try { + tmpl = dynamic_cast(l.loadItem( + fileInfo.absoluteFilePath())); + if (tmpl) { + tmpl->setAsPreDefined(); + predefs << tmpl; + template_files << fileInfo.fileName(); + } + } catch(errorEx &err) { + XCA_WARN(tr("Bad template: %1") + .arg(nativeSeparator( + fileInfo.absoluteFilePath()))); } - } catch(errorEx &err) { - XCA_WARN(tr("Bad template: %1") - .arg(nativeSeparator(name))); } } } diff --git a/lib/func.cpp b/lib/func.cpp index ccb7b07f..d7c070dd 100644 --- a/lib/func.cpp +++ b/lib/func.cpp @@ -22,8 +22,8 @@ #if defined(Q_OS_MAC) #include -#include #endif +#include #include #include #include @@ -118,20 +118,6 @@ const QStringList getLibExtensions() } #if defined(Q_OS_WIN32) -static QString xcaExeDir() -{ - QString dir; - wchar_t inst_dir[2048]; - ULONG dwLength = ARRAY_SIZE(inst_dir); - - dwLength = GetModuleFileNameW(0, inst_dir, dwLength - 1); - dir = QString::fromWCharArray(inst_dir, dwLength); - int bslash = dir.lastIndexOf("\\"); - if (bslash > 0) - dir = dir.mid(0, bslash); - return QFileInfo(dir).canonicalFilePath(); -} - static QString registryInstallDir() { QString dir; @@ -158,7 +144,7 @@ int portable_app() if (portable == -1) { #if defined(Q_OS_WIN32) f1 = registryInstallDir(); - f2 = xcaExeDir(); + f2 = QCoreApplication::applicationDirPath(); /* f1 == f2 Registry entry of install dir exists and matches * path of this xca.exe -> Installed. Not the portable app */ @@ -172,48 +158,6 @@ int portable_app() return portable; } -/* returns e.g. /usr/local/share/xca for unix systems - * or HKEY_LOCAL_MACHINE->Software->xca for WIN32 - * (e.g. c:\Program Files\xca ) - */ - -const QString getPrefix() -{ -#if defined(Q_OS_WIN32) - static QString inst_dir; - QString reg_dir; - - if (!inst_dir.isEmpty()) { - /* if we already once discovered the directory just return it */ - return inst_dir; - } - inst_dir = xcaExeDir(); - - if (portable_app()) - return QString(inst_dir); - - reg_dir = registryInstallDir(); - if (reg_dir.isEmpty()) - XCA_WARN("Registry Key: 'HKEY_LOCAL_MACHINE->Software->xca->Install_Dir' not found"); - else - inst_dir = reg_dir; - return inst_dir; - -#elif defined(Q_OS_MAC) - // since this is platform-specific anyway, - // this is a more robust way to get the bundle directory - QDir bundleDir(qApp->applicationDirPath()); - bundleDir.cdUp(); - return bundleDir.canonicalPath() + "/Resources"; -#else -#ifndef XCA_PREFIX -#define XCA_PREFIX PREFIX "/share/xca" -#endif - return QString(XCA_PREFIX); -#endif - -} - #if defined(Q_OS_WIN32) static QString specialFolder(int csidl) { @@ -231,11 +175,9 @@ static QString specialFolder(int csidl) const QString getHomeDir() { -#if defined(Q_OS_WIN32) - return portable_app() ? getPrefix() : specialFolder(CSIDL_PERSONAL); -#else - return QDir::homePath(); -#endif + return portable_app() ? QCoreApplication::applicationDirPath() : + QStandardPaths::writableLocation( + QStandardPaths::DocumentsLocation); } /* For portable APP remove leading file name if it is @@ -294,43 +236,81 @@ const QString getLibDir() const QString getDocDir() { -#if defined(Q_OS_WIN32) - return getPrefix() + "\\html"; -#elif defined (Q_OS_MAC) - return getPrefix(); -#else - return QString(DOCDIR); + static QString docdir; + + if (!docdir.isEmpty()) + return docdir; + + QStringList docs; +#ifdef DOCDIR + docs << QString(DOCDIR); #endif + docs += QStandardPaths::standardLocations(QStandardPaths::DataLocation); + foreach (docdir, docs) { +#if defined(Q_OS_WIN32) + docdir += "/html"; +#endif + if (QFileInfo::exists(docdir + "/xca.qhc")) { + qWarning() << "Detected" << docdir + "/xca.qhc"; + return docdir; + } + } + docdir = QString(); + return docdir; } // The intent of this function is to return the proper location for // user-controlled settings on the current platform -// i.e. PROFILE\Application Data\xca on windows, HOME/.xca on UNIX, -// ~/Library/Preferences/xca on Mac OS X const QString getUserSettingsDir() { - QString rv; + static QString dir; + + if (!dir.isEmpty()) + return dir; + + dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + #if defined(Q_OS_WIN32) - rv = portable_app() ? getPrefix() + "/settings" : - specialFolder(CSIDL_APPDATA) + "/xca"; -#elif defined(Q_OS_MAC) - rv = QStandardPaths::writableLocation( - QStandardPaths::GenericDataLocation) + "/data/" + - QCoreApplication::organizationName() + "/" + - QCoreApplication::applicationName(); -#else - rv = QDir::homePath() + "/.xca"; + if (portable_app()) + dir = QCoreApplication::applicationDirPath() + "/settings"; + #endif - return rv; + if (!QDir().mkpath(dir)) + qCritical("Failed to create Path: '%s'", CCHAR(dir)); + + return dir; } const QString getI18nDir() { -#if defined(Q_OS_WIN32) - return getPrefix() + "\\i18n"; -#else - return getPrefix(); + return QStandardPaths::locate(QStandardPaths::DataLocation, + "translations"); +} + +void migrateOldPaths() +{ + QString old; +#if defined(Q_OS_UNIX) + old = QDir::homePath() + "/.xca"; + +#elif defined(Q_OS_MAC) + old = QStandardPaths::writableLocation( + QStandardPaths::GenericDataLocation) + "/data/" + + QCoreApplication::applicationName(); #endif + QDir old_dir(old); + qWarning() << "OLD" << old; + if (old.isEmpty() || !old_dir.exists()) + return; + qWarning() << "OLDexists" << old; + QString new_dir = getUserSettingsDir() + "/"; + foreach(QString n, QStringList({"dbhistory", "defaultdb", + "defaultlang", ".rnd"})) + { + old_dir.rename(n, new_dir + n); + qWarning() << "Move" << old + "/" + n << new_dir + n; + } + old_dir.rmdir(old); } // Qt's open and save dialogs result in some undesirable quirks. diff --git a/lib/func.h b/lib/func.h index 4ff76c95..37bde0a8 100644 --- a/lib/func.h +++ b/lib/func.h @@ -44,7 +44,6 @@ int console_write(FILE *fp, const QByteArray &ba); Passwd readPass(); QPixmap *loadImg(const char *name); int portable_app(); -const QString getPrefix(); const QString getHomeDir(); const QString getLibDir(); const QString getDocDir(); diff --git a/lib/main.cpp b/lib/main.cpp index 0bb16a45..e3fd394c 100644 --- a/lib/main.cpp +++ b/lib/main.cpp @@ -29,6 +29,8 @@ #include #endif +void migrateOldPaths(); + char segv_data[1024]; MainWindow *mainwin = NULL; @@ -328,22 +330,28 @@ int main(int argc, char *argv[]) xca_name = argv[0]; bool console_only = arguments::is_console(argc, argv); - XcaApplication *gui; + XcaApplication *gui = nullptr; + QCoreApplication *coreApp = nullptr; #if !defined(Q_OS_WIN32) if (console_only) { - new QCoreApplication(argc, argv); - gui = NULL; + coreApp = new QCoreApplication(argc, argv); } else #endif { /* On windows, always instantiate a GUI app */ - gui = new XcaApplication(argc, argv); + coreApp = gui = new XcaApplication(argc, argv); } - if (!QDir().mkpath(getUserSettingsDir())) - qCritical("Failed to create Path: '%s'", CCHAR(getUserSettingsDir())); + coreApp->setApplicationName(PACKAGE_TARNAME); + coreApp->setOrganizationDomain("de.hohnstaedt"); + coreApp->setApplicationVersion(XCA_VERSION); + migrateOldPaths(); + + qWarning() << "AppDataLocation" << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + + qWarning() << "AppConfigLocation" << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); Entropy entropy; Settings.clear(); initOIDs(); diff --git a/lib/oid.cpp b/lib/oid.cpp index 1513ed12..0ab0a9e0 100644 --- a/lib/oid.cpp +++ b/lib/oid.cpp @@ -120,12 +120,13 @@ static void insert_new_oid(const QStringList &sl, QString fname, int line) } } -static void readOIDs(QString fname) +static void readOIDs(const QString &fname) { int line = 0; QFile file(fname); if (!file.open(QIODevice::ReadOnly)) return; + qWarning() << "readOIDs" << fname; QTextStream in(&file); while (!in.atEnd()) { QString entry = in.readLine().trimmed(); @@ -174,44 +175,28 @@ static NIDlist read_nidlist(const QString &name) { NIDlist nl; - /* first try $HOME/xca/ */ - nl = readNIDlist(getUserSettingsDir() + "/" + name); -#if !defined(Q_OS_WIN32) -#if !defined(Q_OS_MAC) - if (nl.count() == 0){ - /* next is /etx/xca/... */ - nl = readNIDlist(QString(ETC) + "/" + name); - } -#endif -#endif - if (nl.count() == 0) { - /* look at /usr/(local/)share/xca/ */ - nl = readNIDlist(getPrefix() + "/" + name); + foreach(QString d, QStandardPaths::standardLocations( + QStandardPaths::AppDataLocation)) + { + nl = readNIDlist(d + "/" + name); + qWarning() << "read_nidlist" << d + "/" + name << nl.count(); + if (nl.count() > 0) + break; } return nl; } void initOIDs() { - QString oids("/oids.txt"); - QString dir = getPrefix(); - first_additional_oid = OBJ_new_nid(0); -#ifndef NID_tlsfeature - NID_tlsfeature = OBJ_create("1.3.6.1.5.5.7.1.24", "tlsfeature", - "TLS Feature"); -#endif openssl_error(); for (int i=0; i