/* * This file is part of smolbote. It's copyrighted by the contributors recorded * in the version control history of the file, available from its original * location: git://neueland.iserlohn-fortress.net/smolbote.git * * SPDX-License-Identifier: GPL-3.0 */ #include #include "version.h" #include "browser.h" #include #include #include #include #include #include "mainwindow.h" // startup time measuring #ifdef QT_DEBUG #include #endif // read config into std::string, supports qrc inline std::string readConfig(const QString &path) { QFile conf(path); std::string ret; if(conf.open(QIODevice::ReadOnly)) { ret = conf.readAll().toStdString(); conf.close(); } return ret; } void bootstrapUserConfig(const std::string &path, Configuration &config) { // set firstRun to false so we don't re-init on every run config.setValue("browser.firstRun", false); // The .path's need to be overriden because ~ doesn't translate to home const QString &home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); // filter.path std::string filterPath = config.value("filter.path").value(); config.setValue("filter.path", patchHome(filterPath, home.toStdString())); // profile.path std::string profilePath = config.value("profile.path").value(); config.setValue("profile.path", patchHome(profilePath, home.toStdString())); // bookmarks.path std::string bookmarksPath = config.value("bookmarks.path").value(); config.setValue("bookmarks.path", patchHome(bookmarksPath, home.toStdString())); // downloads.path std::string downloadsPath = config.value("downloads.path").value(); config.setValue("downloads.path", patchHome(downloadsPath, home.toStdString())); } int main(int argc, char *argv[]) { // Create application object Browser instance(argc, argv); #ifdef GIT_VERSION instance.setApplicationVersion(GIT_VERSION); #else instance.setApplicationVersion("1.0.0"); #endif #ifdef QT_DEBUG QElapsedTimer timer; timer.start(); #endif QCommandLineParser parser; parser.setApplicationDescription("yet another no-frills browser"); parser.addHelpOption(); parser.addVersionOption(); // user config, ~/.config/smolbote/smolbote.cfg or empty if there is none QCommandLineOption configOption({"c", "config"}, "Set configuration file.", "path"); configOption.setDefaultValue(QStandardPaths::locate(QStandardPaths::AppConfigLocation, "smolbote.cfg")); parser.addOption(configOption); // default config, :/poi.cfg QCommandLineOption defaultConfigOption("default-config", "Set the default configuration file.", "path"); defaultConfigOption.setDefaultValue(":/poi.cfg"); parser.addOption(defaultConfigOption); // print default config, so users can easily create their overrides QCommandLineOption printDefaultConfigOption("print-default-config", "Print default configuration."); parser.addOption(printDefaultConfigOption); // generate user config QCommandLineOption generateUserConfigOption("generate-user-config", "Generate user configuration and exit."); parser.addOption(generateUserConfigOption); QCommandLineOption profileOption({"p", "profile"}, "Use this profile.", "PROFILE"); profileOption.setDefaultValue(""); parser.addOption(profileOption); QCommandLineOption socketOption("socket", "Set socket to use for IPC, leave blank for default, 'none' to disable.", "name"); socketOption.setDefaultValue(""); parser.addOption(socketOption); QCommandLineOption newWindowOption("in-new-window", "Open URL in new window"); parser.addOption(newWindowOption); parser.addPositionalArgument("URL", "URL(s) to open"); parser.process(instance); #ifdef QT_DEBUG qDebug("config=%s", qUtf8Printable(parser.value(configOption))); qDebug("default-config=%s", qUtf8Printable(parser.value(defaultConfigOption))); qDebug("socket=%s", qUtf8Printable(parser.value(socketOption))); qDebug("profile=%s", qUtf8Printable(parser.value(profileOption))); #endif if(parser.isSet(printDefaultConfigOption)) { std::cout << readConfig(parser.value(defaultConfigOption)); std::cout.flush(); return 0; } std::shared_ptr config = std::make_shared(); config->readUserConfiguration(parser.value(configOption).toStdString()); config->parseDefaultConfiguration(readConfig(parser.value(defaultConfigOption))); // check if first run if(config->value("browser.firstRun").value_or(true) || parser.isSet(generateUserConfigOption)) { // create a user config file QString path = parser.value(configOption); // make sure we have a path if(path.isEmpty()) { path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/smolbote.cfg"; } // make sure the directory exists QDir configDir = QFileInfo(path).absoluteDir(); if(!configDir.exists()) { configDir.mkpath("."); } // remove any existing config if(QFile::exists(path)) { QFile::remove(path); } config->parse(readConfig(parser.value(defaultConfigOption))); // patch paths bootstrapUserConfig(path.toStdString(), *config); std::cout << "Generating config to: " << qUtf8Printable(path) << (config->writeUserConfiguration(path.toStdString()) ? " ok" : " failed") << std::endl; // exit if this is the only thing we needed to do if(parser.isSet(generateUserConfigOption)) { return 0; } } // check for other instances // if we socket hasn't been disabled (socket is not none) if(parser.value(socketOption) != "none") { bool bindOk = instance.bindLocalSocket(parser.value(socketOption)); if(bindOk) { qDebug("Connected to local socket: %s", qUtf8Printable(instance.serverName())); } else { // pass arguments to new instance return instance.sendMessage(parser.value(profileOption), parser.isSet(newWindowOption), parser.positionalArguments()); } } instance.setConfiguration(config); instance.createSession(parser.value(profileOption), parser.isSet(newWindowOption), parser.positionalArguments()); #ifdef QT_DEBUG qDebug("Startup complete in %lldms", timer.elapsed()); #endif return instance.exec(); }