/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kde5access.hxx" namespace { OUString getServiceImplementationName() { return OUString("com.sun.star.comp.configuration.backend.KDE5Backend"); } css::uno::Sequence getServiceSupportedServiceNames() { OUString name("com.sun.star.configuration.backend.KDE5Backend"); return css::uno::Sequence(&name, 1); } class Service : public cppu::WeakImplHelper, private boost::noncopyable { public: Service(); private: virtual ~Service() override {} virtual OUString SAL_CALL getImplementationName() override { return getServiceImplementationName(); } virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override { return ServiceName == getSupportedServiceNames()[0]; } virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override { return getServiceSupportedServiceNames(); } virtual css::uno::Reference SAL_CALL getPropertySetInfo() override { return css::uno::Reference(); } virtual void SAL_CALL setPropertyValue(OUString const&, css::uno::Any const&) override; virtual css::uno::Any SAL_CALL getPropertyValue(OUString const& PropertyName) override; virtual void SAL_CALL addPropertyChangeListener( OUString const&, css::uno::Reference const&) override { } virtual void SAL_CALL removePropertyChangeListener( OUString const&, css::uno::Reference const&) override { } virtual void SAL_CALL addVetoableChangeListener( OUString const&, css::uno::Reference const&) override { } virtual void SAL_CALL removeVetoableChangeListener( OUString const&, css::uno::Reference const&) override { } std::map> m_KDESettings; }; OString getDisplayArg() { OUString aParam; const sal_uInt32 nParams = osl_getCommandArgCount(); for (sal_uInt32 nIdx = 0; nIdx < nParams; ++nIdx) { osl_getCommandArg(nIdx, &aParam.pData); if (aParam != "-display") continue; ++nIdx; osl_getCommandArg(nIdx, &aParam.pData); return OUStringToOString(aParam, osl_getThreadTextEncoding()); } return {}; } OString getExecutable() { OUString aParam, aBin; osl_getExecutableFile(&aParam.pData); osl_getSystemPathFromFileURL(aParam.pData, &aBin.pData); return OUStringToOString(aBin, osl_getThreadTextEncoding()); } void readKDESettings(std::map>& rSettings) { const std::vector aKeys = { "EnableATToolSupport", "ExternalMailer", "SourceViewFontHeight", "SourceViewFontName", "WorkPathVariable", "ooInetFTPProxyName", "ooInetFTPProxyPort", "ooInetHTTPProxyName", "ooInetHTTPProxyPort", "ooInetHTTPSProxyName", "ooInetHTTPSProxyPort", "ooInetNoProxy", "ooInetProxyType" }; for (const OUString& aKey : aKeys) { css::beans::Optional aValue = kde5access::getValue(aKey); std::pair> elem = std::make_pair(aKey, aValue); rSettings.insert(elem); } } // init the QApplication when we load the kde5backend into a non-Qt vclplug (e.g. Gtk3KDE5) // TODO: use a helper process to read these values without linking to Qt directly? // TODO: share this code somehow with Qt5Instance.cxx? void initQApp(std::map>& rSettings) { const auto aDisplay = getDisplayArg(); int nFakeArgc = aDisplay.isEmpty() ? 2 : 3; char** pFakeArgv = new char*[nFakeArgc]; pFakeArgv[0] = strdup(getExecutable().getStr()); pFakeArgv[1] = strdup("--nocrashhandler"); if (!aDisplay.isEmpty()) pFakeArgv[2] = strdup(aDisplay.getStr()); char* session_manager = nullptr; if (auto* session_manager_env = getenv("SESSION_MANAGER")) { session_manager = strdup(session_manager_env); unsetenv("SESSION_MANAGER"); } std::unique_ptr app(new QApplication(nFakeArgc, pFakeArgv)); QObject::connect(app.get(), &QObject::destroyed, app.get(), [nFakeArgc, pFakeArgv]() { for (int i = 0; i < nFakeArgc; ++i) delete pFakeArgv[i]; delete[] pFakeArgv; }); readKDESettings(rSettings); if (session_manager != nullptr) { // coverity[tainted_string] - trusted source for setenv setenv("SESSION_MANAGER", session_manager, 1); free(session_manager); } } Service::Service() { css::uno::Reference context(css::uno::getCurrentContext()); if (context.is()) { OUString desktop; context->getValueByName("system.desktop-environment") >>= desktop; if (desktop == "KDE5") { if (!qApp) // no qt event loop yet { // so we start one and read KDE settings initQApp(m_KDESettings); } else // someone else (most likely kde/qt vclplug) has started qt event loop // all that is left to do is to read KDE settings readKDESettings(m_KDESettings); } } } void Service::setPropertyValue(OUString const&, css::uno::Any const&) { throw css::lang::IllegalArgumentException("setPropertyValue not supported", static_cast(this), -1); } css::uno::Any Service::getPropertyValue(OUString const& PropertyName) { if (PropertyName == "EnableATToolSupport" || PropertyName == "ExternalMailer" || PropertyName == "SourceViewFontHeight" || PropertyName == "SourceViewFontName" || PropertyName == "WorkPathVariable" || PropertyName == "ooInetFTPProxyName" || PropertyName == "ooInetFTPProxyPort" || PropertyName == "ooInetHTTPProxyName" || PropertyName == "ooInetHTTPProxyPort" || PropertyName == "ooInetHTTPSProxyName" || PropertyName == "ooInetHTTPSProxyPort" || PropertyName == "ooInetNoProxy" || PropertyName == "ooInetProxyType") { std::map>::iterator it = m_KDESettings.find(PropertyName); if (it != m_KDESettings.end()) return css::uno::makeAny(it->second); else return css::uno::makeAny(css::beans::Optional()); } else if (PropertyName == "givenname" || PropertyName == "sn" || PropertyName == "TemplatePathVariable") { return css::uno::makeAny(css::beans::Optional()); //TODO: obtain values from KDE? } throw css::beans::UnknownPropertyException(PropertyName, static_cast(this)); } css::uno::Reference createInstance(css::uno::Reference const&) { return static_cast(new Service); } static cppu::ImplementationEntry const services[] = { { &createInstance, &getServiceImplementationName, &getServiceSupportedServiceNames, &cppu::createSingleComponentFactory, nullptr, 0 }, { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } }; } extern "C" SAL_DLLPUBLIC_EXPORT void* kde5be1_component_getFactory(char const* pImplName, void* pServiceManager, void* pRegistryKey) { return cppu::component_getFactoryHelper(pImplName, pServiceManager, pRegistryKey, services); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */