/* * 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 "browser.h" #include "src/mainwindow/mainwindow.h" #include "version.h" #include #include #include #include // 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); config.resetValue("filter.path"); config.resetValue("profile.path"); config.resetValue("bookmarks.path"); config.resetValue("downloads.path"); config.resetValue("plugins.path"); } int main(int argc, char *argv[]) { // Create application object Browser instance(argc, argv); instance.setApplicationVersion(SMOLBOTE_VERSION); #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( parser.value(configOption).toStdString(), QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString()); config->read(); 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 << "Writing configuration: " << (config->writeIfNeeded(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(); }