File indexing completed on 2024-09-29 07:24:44
0001 // SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org> 0002 // SPDX-License-Identifier: GPL-3.0-only 0003 0004 #include <QCommandLineParser> 0005 #include <QIcon> 0006 #include <QNetworkDiskCache> 0007 #include <QNetworkProxyFactory> 0008 #include <QObject> 0009 #include <QQmlApplicationEngine> 0010 #include <QQmlContext> 0011 #include <QQmlNetworkAccessManagerFactory> 0012 #include <QQuickStyle> 0013 #include <QQuickWindow> 0014 0015 #ifdef Q_OS_ANDROID 0016 #include <QGuiApplication> 0017 #else 0018 #include <QApplication> 0019 #endif 0020 0021 #ifdef HAVE_WEBVIEW 0022 #include <QtWebView> 0023 #endif 0024 0025 #include <KAboutData> 0026 #ifdef HAVE_KDBUSADDONS 0027 #include <KDBusService> 0028 #endif 0029 #ifdef HAVE_WINDOWSYSTEM 0030 #include <KWindowSystem> 0031 #endif 0032 #include <KLocalizedContext> 0033 #include <KLocalizedString> 0034 0035 #include "neochat-version.h" 0036 0037 #include <Quotient/networkaccessmanager.h> 0038 0039 #include "blurhashimageprovider.h" 0040 #include "colorschemer.h" 0041 #include "controller.h" 0042 #include "logger.h" 0043 #include "matriximageprovider.h" 0044 #include "neochatconfig.h" 0045 #include "roommanager.h" 0046 #include "windowcontroller.h" 0047 0048 #ifdef HAVE_RUNNER 0049 #include "runner.h" 0050 #include <QDBusConnection> 0051 #endif 0052 0053 #ifdef Q_OS_WINDOWS 0054 #include <Windows.h> 0055 #endif 0056 0057 using namespace Quotient; 0058 0059 void qml_register_types_org_kde_neochat(); 0060 0061 class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory 0062 { 0063 QNetworkAccessManager *create(QObject *) override 0064 { 0065 auto nam = NetworkAccessManager::instance(); 0066 nam->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); 0067 0068 nam->enableStrictTransportSecurityStore(true, QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/hsts/")); 0069 nam->setStrictTransportSecurityEnabled(true); 0070 0071 auto namDiskCache = new QNetworkDiskCache(nam); 0072 namDiskCache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/nam/")); 0073 nam->setCache(namDiskCache); 0074 0075 return nam; 0076 } 0077 }; 0078 0079 static QWindow *windowFromEngine(QQmlApplicationEngine *engine) 0080 { 0081 const auto rootObjects = engine->rootObjects(); 0082 auto *window = qobject_cast<QQuickWindow *>(rootObjects.first()); 0083 Q_ASSERT(window); 0084 return window; 0085 } 0086 0087 #ifdef Q_OS_ANDROID 0088 Q_DECL_EXPORT 0089 #endif 0090 int main(int argc, char *argv[]) 0091 { 0092 QNetworkProxyFactory::setUseSystemConfiguration(true); 0093 0094 #ifdef HAVE_WEBVIEW 0095 QtWebView::initialize(); 0096 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); 0097 QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi); 0098 #endif 0099 0100 #ifdef Q_OS_ANDROID 0101 QGuiApplication app(argc, argv); 0102 QQuickStyle::setStyle(QStringLiteral("org.kde.breeze")); 0103 #else 0104 QIcon::setFallbackThemeName("breeze"_ls); 0105 QApplication app(argc, argv); 0106 // Default to org.kde.desktop style unless the user forces another style 0107 if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) { 0108 QQuickStyle::setStyle(QStringLiteral("org.kde.desktop")); 0109 } 0110 #endif 0111 0112 #ifdef Q_OS_WINDOWS 0113 if (AttachConsole(ATTACH_PARENT_PROCESS)) { 0114 freopen("CONOUT$", "w", stdout); 0115 freopen("CONOUT$", "w", stderr); 0116 } 0117 0118 QApplication::setStyle(QStringLiteral("breeze")); 0119 QFont font(QStringLiteral("Segoe UI Emoji")); 0120 font.setPointSize(10); 0121 font.setHintingPreference(QFont::PreferNoHinting); 0122 app.setFont(font); 0123 #endif 0124 KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat")); 0125 0126 QGuiApplication::setOrganizationName("KDE"_ls); 0127 0128 KAboutData about(QStringLiteral("neochat"), 0129 i18n("NeoChat"), 0130 QStringLiteral(NEOCHAT_VERSION_STRING), 0131 i18n("Matrix client"), 0132 KAboutLicense::GPL_V3, 0133 i18n("© 2018-2020 Black Hat, 2020-2024 KDE Community")); 0134 about.addAuthor(i18n("Carl Schwan"), 0135 i18n("Maintainer"), 0136 QStringLiteral("carl@carlschwan.eu"), 0137 QStringLiteral("https://carlschwan.eu"), 0138 QStringLiteral("https://carlschwan.eu/avatar.png")); 0139 about.addAuthor(i18n("Tobias Fella"), i18n("Maintainer"), QStringLiteral("tobias.fella@kde.org"), QStringLiteral("https://tobiasfella.de")); 0140 about.addAuthor(i18n("James Graham"), i18n("Maintainer"), QStringLiteral("james.h.graham@protonmail.com")); 0141 about.addCredit(i18n("Black Hat"), i18n("Original author of Spectral"), QStringLiteral("bhat@encom.eu.org")); 0142 about.addCredit(i18n("Alexey Rusakov"), i18n("Maintainer of Quotient"), QStringLiteral("Kitsune-Ral@users.sf.net")); 0143 about.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); 0144 about.setOrganizationDomain("kde.org"); 0145 0146 about.addComponent(QStringLiteral("libQuotient"), 0147 i18n("A Qt library to write cross-platform clients for Matrix"), 0148 i18nc("<version number> (built against <possibly different version number>)", 0149 "%1 (built against %2)", 0150 Quotient::versionString(), 0151 QStringLiteral(Quotient_VERSION_STRING)), 0152 QStringLiteral("https://github.com/quotient-im/libquotient"), 0153 KAboutLicense::LGPL_V2_1); 0154 0155 KAboutData::setApplicationData(about); 0156 QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.neochat"))); 0157 0158 initLogging(); 0159 0160 Connection::setEncryptionDefault(true); 0161 0162 #ifdef NEOCHAT_FLATPAK 0163 // Copy over the included FontConfig configuration to the 0164 // app's config dir: 0165 QFile::copy(QStringLiteral("/app/etc/fonts/conf.d/99-noto-mono-color-emoji.conf"), 0166 QStringLiteral("/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf")); 0167 #endif 0168 0169 ColorSchemer colorScheme; 0170 if (!NeoChatConfig::self()->colorScheme().isEmpty()) { 0171 colorScheme.apply(NeoChatConfig::self()->colorScheme()); 0172 } 0173 0174 QCommandLineParser parser; 0175 parser.setApplicationDescription(i18n("Client for the matrix communication protocol")); 0176 parser.addPositionalArgument(QStringLiteral("urls"), i18n("Supports matrix: url scheme")); 0177 parser.addOption(QCommandLineOption("ignore-ssl-errors"_ls, i18n("Ignore all SSL Errors, e.g., unsigned certificates."))); 0178 0179 QCommandLineOption testOption("test"_ls, i18n("Only used for autotests")); 0180 testOption.setFlags(QCommandLineOption::HiddenFromHelp); 0181 parser.addOption(testOption); 0182 0183 #ifdef HAVE_KUNIFIEDPUSH 0184 QCommandLineOption dbusActivatedOption(QStringLiteral("dbus-activated"), i18n("Internal usage only.")); 0185 dbusActivatedOption.setFlags(QCommandLineOption::Flag::HiddenFromHelp); 0186 parser.addOption(dbusActivatedOption); 0187 #endif 0188 0189 about.setupCommandLine(&parser); 0190 parser.process(app); 0191 about.processCommandLine(&parser); 0192 Controller::setTestMode(parser.isSet("test"_ls)); 0193 0194 #ifdef HAVE_KUNIFIEDPUSH 0195 if (parser.isSet(dbusActivatedOption)) { 0196 // We want to be replaceable by the main client 0197 KDBusService service(KDBusService::Replace); 0198 0199 Controller::listenForNotifications(); 0200 return QCoreApplication::exec(); 0201 } 0202 #endif 0203 0204 #ifdef HAVE_KDBUSADDONS 0205 KDBusService service(KDBusService::Unique); 0206 #endif 0207 0208 qml_register_types_org_kde_neochat(); 0209 qmlRegisterSingletonInstance("org.kde.neochat.config", 1, 0, "Config", NeoChatConfig::self()); 0210 qmlRegisterSingletonInstance("org.kde.neochat.accounts", 1, 0, "AccountRegistry", &Controller::instance().accounts()); 0211 0212 qmlRegisterUncreatableType<KeyVerificationSession>("com.github.quotient_im.libquotient", 1, 0, "KeyVerificationSession", {}); 0213 0214 QQmlApplicationEngine engine; 0215 0216 #ifdef HAVE_KDBUSADDONS 0217 service.connect(&service, 0218 &KDBusService::activateRequested, 0219 &RoomManager::instance(), 0220 [&engine](const QStringList &arguments, const QString &workingDirectory) { 0221 Q_UNUSED(workingDirectory); 0222 0223 QWindow *window = windowFromEngine(&engine); 0224 KWindowSystem::updateStartupId(window); 0225 0226 WindowController::instance().showAndRaiseWindow(QString()); 0227 0228 // Open matrix uri 0229 if (arguments.isEmpty()) { 0230 return; 0231 } 0232 auto args = arguments; 0233 args.removeFirst(); 0234 for (const auto &arg : args) { 0235 RoomManager::instance().resolveResource(arg); 0236 } 0237 }); 0238 #endif 0239 0240 engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); 0241 QObject::connect(&engine, &QQmlApplicationEngine::quit, &app, &QCoreApplication::quit); 0242 engine.setNetworkAccessManagerFactory(new NetworkAccessManagerFactory()); 0243 0244 if (parser.isSet("ignore-ssl-errors"_ls)) { 0245 QObject::connect(NetworkAccessManager::instance(), &QNetworkAccessManager::sslErrors, NetworkAccessManager::instance(), [](QNetworkReply *reply) { 0246 reply->ignoreSslErrors(); 0247 }); 0248 } 0249 0250 engine.addImageProvider(QLatin1String("mxc"), MatrixImageProvider::create(&engine, &engine)); 0251 engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider); 0252 0253 engine.load(QUrl(QStringLiteral("qrc:/org/kde/neochat/qml/main.qml"))); 0254 if (engine.rootObjects().isEmpty()) { 0255 return -1; 0256 } 0257 0258 if (!parser.positionalArguments().isEmpty()) { 0259 RoomManager::instance().setUrlArgument(parser.positionalArguments()[0]); 0260 } 0261 0262 #ifdef HAVE_RUNNER 0263 auto runner = Runner::create(&engine, &engine); 0264 QDBusConnection::sessionBus().registerObject("/RoomRunner"_ls, runner, QDBusConnection::ExportScriptableContents); 0265 #endif 0266 0267 QWindow *window = windowFromEngine(&engine); 0268 0269 WindowController::instance().setWindow(window); 0270 WindowController::instance().restoreGeometry(); 0271 0272 return app.exec(); 0273 }