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.
This commit is contained in:
Christian Hohnstädt 2021-04-27 14:11:31 +02:00
parent 7d564132ba
commit 8daf06dcac
7 changed files with 129 additions and 142 deletions

View File

@ -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@

View File

@ -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 <name>.xca found avoids other <name>.xca to be loaded
*/
QSet<QString> 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<pki_temp*>(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<pki_temp*>(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)));
}
}
}

View File

@ -22,8 +22,8 @@
#if defined(Q_OS_MAC)
#include <IOKit/IOKitLib.h>
#include <QStandardPaths>
#endif
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QFileInfo>
@ -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.

View File

@ -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();

View File

@ -29,6 +29,8 @@
#include <windows.h>
#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();

View File

@ -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<first_additional_oid;i++)
addToLowerMap(i);
ign_openssl_error();
readOIDs(dir + oids);
#if !defined(Q_OS_WIN32)
#if !defined(Q_OS_MAC)
readOIDs(QString(ETC) + oids);
#endif
#endif
readOIDs(getUserSettingsDir() + oids);
foreach(QString d, QStandardPaths::standardLocations(
QStandardPaths::AppDataLocation))
readOIDs(d + "/oids.txt");
extkeyuse_nid = read_nidlist("eku.txt");
distname_nid = read_nidlist("dn.txt");

View File

@ -116,7 +116,8 @@ void MainWindow::about()
.arg(version)
.arg(Entropy::strength())
.arg(version_str(true))
.arg(nativeSeparator(getPrefix()))
.arg(nativeSeparator(QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation)))
.arg(nativeSeparator(getUserSettingsDir()))
.arg(nativeSeparator(QString(Settings["workingdir"])))
.arg(portable_app() ? " (Portable)" : "")