summaryrefslogblamecommitdiffstats
path: root/src/config.cpp
blob: 0d4a72d06a6e77307f78eb28687667eb04065bb5 (plain) (tree)
1
2
3
4
5
6
7
8
9






                             
                 
                


                                       
                                       
























                                                                                                                                                                     
                                


     
                                                                                                                                                                                                                   
























                                                                                                                                                                                                                                                           
                                                                                                                                                                                  



















                                                                                  









                                                                                                                                                      







                                                                                        
                                    
                                                            
                                        

                                                                                                    
                                                                     
                         
         

                                                               
                                                



                

















                                                                                                              
#include "config.h"
#include "globals.h"

#include <QFileInfo>
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QSettings>
#include <QDebug>
#include <QList>

static QCommandLineParser parser;
static QSettings* configFile = nullptr;
static QList<ConfigOption*> allOptions;

static inline QStringList combine(const QString &a, const QString &b)
{
    QStringList ret;
    if (!a.isEmpty()) {
        ret << a;
    }
    if (!b.isEmpty()) {
        ret << b;
    }
    return ret;
}

struct ConfigOption
{
    const QCommandLineOption cmdLine;
    const QString iniKey;
    const QString defaultValue;
    const bool withArgument;
    ConfigOption(const QString optShort, const QString optLong, const QString iniKey, const QString valueName, const QString defaultValue, const QString description)
        : cmdLine(combine(optLong, optShort), description, valueName, defaultValue), iniKey(iniKey), defaultValue(defaultValue), withArgument(!valueName.isEmpty())
    {
        if (!cmdLine.names().isEmpty()) {
            parser.addOption(cmdLine);
        }
        allOptions.append(this);
    }
};

const ConfigOption* const Config::ALLOW_SCREENSAVER_DISABLE = new ConfigOption("", "allow-screensaver-disable", "allow-screensaver-disable", "", "", "Show checkbox to disable the screen saver for this session");
const ConfigOption* const Config::ALLOW_VM_EDIT = new ConfigOption("", "allow-vm-edit", "allow-vm-edit", "", "", "Show edit checkbox for VMs/lectures where meta data allows editing");
const ConfigOption* const Config::AUTOQUIT = new ConfigOption("", "autoquit", "autoquit", "seconds", "120", "Time after which vmchooser will quit if no user interaction is detected");
const ConfigOption* const Config::BASEDIR = new ConfigOption("b", "base", "base", "path", "/mnt/vmstore", "Base directory where vm meta data is relative to");
const ConfigOption* const Config::CONFIG = new ConfigOption("c", "config", "", "path", CONFIG_FILE_GLOBAL, "Path to global config file");
const ConfigOption* const Config::DEBUG = new ConfigOption("D", "debug", "debug", "", "", "Enable debug mode");
const ConfigOption* const Config::DEFAULT_SESSION = new ConfigOption("d", "default", "", "uuid", "", "Preselect session with given uuid or name");
const ConfigOption* const Config::EXAM_MODE = new ConfigOption("", "exam-mode", "exam-mode", "", "", "Turn on exam mode: Limits options, forces PVS");
const ConfigOption* const Config::FULLSCREEN = new ConfigOption("F", "fullscreen", "fullscreen", "", "", "Show vmchooser in fullscreen mode");
const ConfigOption* const Config::INSECURE = new ConfigOption("k", "insecure", "insecure", "", "", "When using HTTPS, don't check server's certificate");
const ConfigOption* const Config::LOCATIONS = new ConfigOption("l", "locations", "locations", "ids..", "", "Space separated list of location ids, for list request and location-mode");
const ConfigOption* const Config::PVS = new ConfigOption("p", "pvs", "pvs", "", "", "Show 'join PVS' checkbox");
const ConfigOption* const Config::PVS_CHECKED = new ConfigOption("", "pvs-checked", "pvs-checked", "", "", "PVS checkbox is selected by default");
const ConfigOption* const Config::RUNSCRIPT = new ConfigOption("S", "runscript", "runscript", "path", RUN_VIRT_PATH, "Path to run-virt script");
const ConfigOption* const Config::WINDOW_SIZE = new ConfigOption("s", "size", "size", "WxH", "640x480", "Size of window if not using fullscreen");
const ConfigOption* const Config::DEFAULT_TAB = new ConfigOption("T", "tab", "tab", "tabno", "2", "Default tab to show, first tab being 0");
const ConfigOption* const Config::THEME = new ConfigOption("t", "theme", "theme", "name", "", "Name of theme to load");
const ConfigOption* const Config::URL_BASE = new ConfigOption("u", "url", "url", "url", "", "Base URL path to fetch resources from");
const ConfigOption* const Config::URL_LIST = new ConfigOption("", "url-list", "url-list", "url", "", "Use this URL for the VM list instead of <urlbase>/list");
const ConfigOption* const Config::URL_NEWS = new ConfigOption("", "url-news", "url-news", "url", "", "Use this URL for the news panel instead of <urlbase>/news");
const ConfigOption* const Config::URL_HELP = new ConfigOption("", "url-help", "url-help", "url", "", "Use this URL for the help panel instead of <urlbase>/help");
const ConfigOption* const Config::XSESSION_PATH = new ConfigOption("x", "xpath", "xpath", "path", VMCHOOSER_X_SESSIONS_PATH, "Path to xsession files");
const ConfigOption* const Config::LOCATION_MODE = new ConfigOption("", "location-mode", "location-mode", "mode", "BUMP", "Whether to IGNORE locations, BUMP matching entries, or EXCLUSIVE-ly show only those matching the currently configured location");
const ConfigOption* const Config::TEMPLATE_MODE = new ConfigOption("", "template-mode", "template-mode", "mode", "BUMP", "Whether to BUMP entries marked as template, or IGNORE the flag");
const ConfigOption* const Config::AUTOSTART_UUID = new ConfigOption("", "start-uuid", "start-uuid", "uuid", "", "Immediately launch session with given uuid/name");
const ConfigOption* const Config::NO_VTX = new ConfigOption("", "no-vtx", "no-vtx", "", "0", "Fade all VM sessions that would require VTX/SVM CPU capabilities");
const ConfigOption* const Config::DUMP_CONFIG = new ConfigOption("", "dump-config", "", "", "", "Dump effective configuration (config file plus command line options) to stdout");


QString Config::get(const ConfigOption* const option)
{
    if (option == nullptr)
        return QString();
    if (parser.isSet(option->cmdLine))
        return parser.value(option->cmdLine);
    if (configFile != nullptr && !option->iniKey.isEmpty())
        return configFile->value(option->iniKey, option->defaultValue).toString();
    // TODO: CONFIG_FILE_USER is currently not supported, but unused anyways
    return option->defaultValue;
}

bool Config::isSet(const ConfigOption* const option)
{
    if (option == nullptr)
        return false;
    if (parser.isSet(option->cmdLine))
        return true;
    if (configFile != nullptr && !option->iniKey.isEmpty() && configFile->contains(option->iniKey)) {
        // Option present in ini...
        if (option->withArgument) // ...and needs an argument -> set either way
            return true;
        // If it doesn't require an argument, special case
        QString val = configFile->value(option->iniKey).toString().toLower();
        if (!val.isEmpty() && val != QLatin1String("false") && val != QLatin1String("0") && val != QLatin1String("no") && val != QLatin1String("off"))
            return true; // Everything except empty string, "false", "0", "no" and "off" is considered as "is set"
        // Fall though otherwise
    }
    return false;
}

bool Config::init(const QCoreApplication& app, const ConfigOption* const configFileName)
{
    parser.addHelpOption();
    parser.addVersionOption();
    parser.process(app);
    if (configFileName != nullptr) {
        QString file(parser.value(configFileName->cmdLine));
        if (!QFileInfo(file).exists()) {
            if (!parser.isSet(configFileName->cmdLine))
                return true; // No explicit config file passed, ignore if default file doesn't exist
            qDebug() << "--config file" << file << "does not exist!";
            return false;
        }
        configFile = new QSettings(file, QSettings::IniFormat);
        configFile->setIniCodec("UTF-8");
        qDebug() << "Using config file" << file;
    }
    return true;
}

void Config::dump()
{
    QTextStream ts(stdout);
    for (ConfigOption *c : allOptions) {
        if (c->iniKey.isEmpty()) // Not configurable by config
            continue;
        QString val = get(c);
        if (c->withArgument) {
            if (c->defaultValue.isEmpty() && val.isEmpty()) // Defaults to empty, current value is empty, skip
                continue;
            ts << c->iniKey << "=" << val << "\n";
        } else {
            if (!isSet(c)) // Bool argument not set, default would be false anyways, skip
                continue;
            ts << c->iniKey << "=true\n";
        }
    }
}