diff options
Diffstat (limited to 'desktop/source/pkgchk/unopkg')
-rw-r--r-- | desktop/source/pkgchk/unopkg/unopkg_app.cxx | 636 | ||||
-rw-r--r-- | desktop/source/pkgchk/unopkg/unopkg_cmdenv.cxx | 390 | ||||
-rw-r--r-- | desktop/source/pkgchk/unopkg/unopkg_main.c | 26 | ||||
-rw-r--r-- | desktop/source/pkgchk/unopkg/unopkg_main.h | 34 | ||||
-rw-r--r-- | desktop/source/pkgchk/unopkg/unopkg_misc.cxx | 458 | ||||
-rw-r--r-- | desktop/source/pkgchk/unopkg/unopkg_shared.h | 119 |
6 files changed, 1663 insertions, 0 deletions
diff --git a/desktop/source/pkgchk/unopkg/unopkg_app.cxx b/desktop/source/pkgchk/unopkg/unopkg_app.cxx new file mode 100644 index 000000000..a12ee6ae4 --- /dev/null +++ b/desktop/source/pkgchk/unopkg/unopkg_app.cxx @@ -0,0 +1,636 @@ +/* -*- 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 <dp_misc.h> +#include "unopkg_main.h" +#include "unopkg_shared.h" +#include <dp_identifier.hxx> +#include <tools/extendapplicationenvironment.hxx> +#include <rtl/bootstrap.hxx> +#include <osl/process.h> +#include <osl/conditn.hxx> +#include <unotools/tempfile.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <comphelper/anytostring.hxx> +#include <comphelper/logging.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/deployment/DeploymentException.hpp> +#include <com/sun/star/deployment/ExtensionManager.hpp> + +#include <com/sun/star/deployment/ui/PackageManagerDialog.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/logging/ConsoleHandler.hpp> +#include <com/sun/star/logging/FileHandler.hpp> +#include <com/sun/star/logging/LogLevel.hpp> +#include <com/sun/star/logging/SimpleTextFormatter.hpp> +#include <com/sun/star/logging/XLogger.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <com/sun/star/ui/dialogs/XDialogClosedListener.hpp> +#if defined(UNX) + #include <unistd.h> +#endif +#include <utility> +#include <vector> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::logging; +using namespace ::com::sun::star::uno; +using namespace ::unopkg; + +namespace { + +struct ExtensionName +{ + OUString m_str; + explicit ExtensionName( OUString str ) : m_str(std::move( str )) {} + bool operator () ( Reference<deployment::XPackage> const & e ) const + { + return m_str == dp_misc::getIdentifier(e) + || m_str == e->getName(); + } +}; + + +const char16_t s_usingText [] = +u"\n" +"using: " APP_NAME " add <options> extension-path...\n" +" " APP_NAME " validate <options> extension-identifier...\n" +" " APP_NAME " remove <options> extension-identifier...\n" +" " APP_NAME " list <options> extension-identifier...\n" +" " APP_NAME " reinstall <options>\n" +" " APP_NAME " gui\n" +" " APP_NAME " -V\n" +" " APP_NAME " -h\n" +"\n" +"sub-commands:\n" +" add add extension\n" +" validate checks the prerequisites of an installed extension and\n" +" registers it if possible\n" +" remove remove extensions by identifier\n" +" reinstall expert feature: reinstall all deployed extensions\n" +" list list information about deployed extensions\n" +" gui raise Extension Manager Graphical User Interface (GUI)\n" +"\n" +"options:\n" +" -h, --help this help\n" +" -V, --version version information\n" +" -v, --verbose verbose output\n" +" -f, --force force overwriting existing extensions\n" +" -s, --suppress-license prevents showing the license\n" +" --log-file <file> custom log file; default: <cache-dir>/log.txt\n" +" --shared expert feature: operate on shared installation\n" +" deployment context;\n" +" run only when no concurrent Office\n" +" process(es) are running!\n" +" --bundled expert feature: operate on bundled extensions. Only\n" +" works with list, validate, reinstall;\n" +" --deployment-context expert feature: explicit deployment context\n" +" <context>\n" +"\n" +"To learn more about the Extension Manager and extensions, see:\n" +"https://wiki.documentfoundation.org/Documentation/DevGuide/Extensions\n\n"; + + +const OptionInfo s_option_infos [] = { + { RTL_CONSTASCII_STRINGPARAM("help"), 'h', false }, + { RTL_CONSTASCII_STRINGPARAM("version"), 'V', false }, + { RTL_CONSTASCII_STRINGPARAM("verbose"), 'v', false }, + { RTL_CONSTASCII_STRINGPARAM("force"), 'f', false }, + { RTL_CONSTASCII_STRINGPARAM("log-file"), '\0', true }, + { RTL_CONSTASCII_STRINGPARAM("shared"), '\0', false }, + { RTL_CONSTASCII_STRINGPARAM("deployment-context"), '\0', true }, + { RTL_CONSTASCII_STRINGPARAM("bundled"), '\0', false}, + { RTL_CONSTASCII_STRINGPARAM("suppress-license"), 's', false}, + + { nullptr, 0, '\0', false } +}; + +class DialogClosedListenerImpl : + public ::cppu::WeakImplHelper< ui::dialogs::XDialogClosedListener > +{ + osl::Condition & m_rDialogClosedCondition; + +public: + explicit DialogClosedListenerImpl( osl::Condition & rDialogClosedCondition ) + : m_rDialogClosedCondition( rDialogClosedCondition ) {} + + // XEventListener (base of XDialogClosedListener) + virtual void SAL_CALL disposing( lang::EventObject const & Source ) override; + + // XDialogClosedListener + virtual void SAL_CALL dialogClosed( + ui::dialogs::DialogClosedEvent const & aEvent ) override; +}; + +// XEventListener (base of XDialogClosedListener) +void DialogClosedListenerImpl::disposing( lang::EventObject const & ) +{ + // nothing to do +} + +// XDialogClosedListener +void DialogClosedListenerImpl::dialogClosed( + ui::dialogs::DialogClosedEvent const & ) +{ + m_rDialogClosedCondition.set(); +} + +// If a package had been installed with a pre OOo 2.2, it could not normally be +// found via its identifier; similarly (and for ease of use), a package +// installed with OOo 2.2 or later could not normally be found via its file +// name. +Reference<deployment::XPackage> findPackage( + OUString const & repository, + Reference<deployment::XExtensionManager> const & manager, + Reference<ucb::XCommandEnvironment > const & environment, + std::u16string_view idOrFileName ) +{ + const Sequence< Reference<deployment::XPackage> > ps( + manager->getDeployedExtensions(repository, + Reference<task::XAbortChannel>(), environment ) ); + for ( auto const & package : ps ) + if ( dp_misc::getIdentifier( package ) == idOrFileName ) + return package; + for ( auto const & package : ps ) + if ( package->getName() == idOrFileName ) + return package; + return Reference<deployment::XPackage>(); +} + +} // anon namespace + +extern "C" int unopkg_main() +{ + tools::extendApplicationEnvironment(); + bool bShowFailedMsg = true; + OUString subCommand; + bool option_shared = false; + bool option_force = false; + bool option_verbose = false; + bool option_bundled = false; + bool option_suppressLicense = false; + bool option_help = false; + bool subcmd_gui = false; + OUString logFile; + OUString repository; + OUString cmdArg; + std::vector<OUString> cmdPackages; + Reference<XLogHandler> xFileHandler; + Reference<XLogHandler> xConsoleHandler; + std::unique_ptr<comphelper::EventLogger> logger; + std::unique_ptr<utl::TempFile> pUserProfileTempDir; + + OptionInfo const * info_shared = getOptionInfo( + s_option_infos, "shared" ); + OptionInfo const * info_force = getOptionInfo( + s_option_infos, "force" ); + OptionInfo const * info_verbose = getOptionInfo( + s_option_infos, "verbose" ); + OptionInfo const * info_log = getOptionInfo( + s_option_infos, "log-file" ); + OptionInfo const * info_context = getOptionInfo( + s_option_infos, "deployment-context" ); + OptionInfo const * info_help = getOptionInfo( + s_option_infos, "help" ); + OptionInfo const * info_version = getOptionInfo( + s_option_infos, "version" ); + OptionInfo const * info_bundled = getOptionInfo( + s_option_infos, "bundled" ); + OptionInfo const * info_suppressLicense = getOptionInfo( + s_option_infos, "suppress-license" ); + + + Reference<XComponentContext> xComponentContext; + Reference<XComponentContext> xLocalComponentContext; + + try { + sal_uInt32 nPos = 0; + sal_uInt32 nCount = osl_getCommandArgCount(); + if (nCount == 0 || isOption( info_help, &nPos )) + { + dp_misc::writeConsole(s_usingText); + return 0; + } + else if (isOption( info_version, &nPos )) { + dp_misc::writeConsole(u"\n" APP_NAME " Version 3.3\n"); + return 0; + } + //consume all bootstrap variables which may occur before the sub-command + while(isBootstrapVariable(&nPos)) + ; + + if(nPos >= nCount) + return 0; + //get the sub-command + osl_getCommandArg( nPos, &subCommand.pData ); + ++nPos; + subCommand = subCommand.trim(); + bool subcmd_add = subCommand == "add"; + subcmd_gui = subCommand == "gui"; + + // sub-command options and packages: + while (nPos < nCount) + { + if (readArgument( &cmdArg, info_log, &nPos )) { + logFile = makeAbsoluteFileUrl( + cmdArg.trim(), getProcessWorkingDir() ); + } + else if (!readOption( &option_verbose, info_verbose, &nPos ) && + !readOption( &option_shared, info_shared, &nPos ) && + !readOption( &option_force, info_force, &nPos ) && + !readOption( &option_bundled, info_bundled, &nPos ) && + !readOption( &option_suppressLicense, info_suppressLicense, &nPos ) && + !readOption( &option_help, info_help, &nPos ) && + !readArgument( &repository, info_context, &nPos ) && + !isBootstrapVariable(&nPos)) + { + osl_getCommandArg( nPos, &cmdArg.pData ); + ++nPos; + cmdArg = cmdArg.trim(); + if (!cmdArg.isEmpty()) + { + if (cmdArg[ 0 ] == '-') + { + // is option: + dp_misc::writeConsoleError(OUStringConcatenation( + "\nERROR: unexpected option " + + cmdArg + + "!\n Use " APP_NAME " " + + toString(info_help) + + " to print all options.\n")); + return 1; + } + else + { + // is package: + cmdPackages.push_back( + subcmd_add || subcmd_gui + ? makeAbsoluteFileUrl( + cmdArg, getProcessWorkingDir() ) + : cmdArg ); + } + } + } + } + + // tdf#129917 Use temp user profile when installing shared extensions + if (option_shared) + { + pUserProfileTempDir.reset(new utl::TempFile(nullptr, true)); + pUserProfileTempDir->EnableKillingFile(); + } + + xComponentContext = getUNO(option_verbose, subcmd_gui, + pUserProfileTempDir ? pUserProfileTempDir->GetURL() : "", + xLocalComponentContext); + + // Initialize logging. This will log errors to the console and + // also to file if the --log-file parameter was provided. + logger.reset(new comphelper::EventLogger(xLocalComponentContext, "unopkg")); + const Reference<XLogger> xLogger(logger->getLogger()); + xLogger->setLevel(LogLevel::WARNING); + Reference<XLogFormatter> xLogFormatter(SimpleTextFormatter::create(xLocalComponentContext)); + Sequence < beans::NamedValue > aSeq { { "Formatter", Any(xLogFormatter) } }; + + xConsoleHandler.set(ConsoleHandler::createWithSettings(xLocalComponentContext, aSeq)); + xLogger->addLogHandler(xConsoleHandler); + xConsoleHandler->setLevel(LogLevel::WARNING); + xLogger->setLevel(LogLevel::WARNING); + + + if (!logFile.isEmpty()) + { + Sequence < beans::NamedValue > aSeq2 { { "Formatter", Any(xLogFormatter) }, {"FileURL", Any(logFile)} }; + xFileHandler.set(css::logging::FileHandler::createWithSettings(xLocalComponentContext, aSeq2)); + xFileHandler->setLevel(LogLevel::WARNING); + xLogger->addLogHandler(xFileHandler); + } + + if (option_verbose) + { + xLogger->setLevel(LogLevel::INFO); + xConsoleHandler->setLevel(LogLevel::INFO); + if (xFileHandler.is()) + xFileHandler->setLevel(LogLevel::INFO); + } + + if (repository.isEmpty()) + { + if (option_shared) + repository = "shared"; + else if (option_bundled) + repository = "bundled"; + else + repository = "user"; + } + else + { + if ( repository == "shared" ) { + option_shared = true; + } + else if (option_shared) + { + logger->log(LogLevel::WARNING, "Explicit context given! Ignoring option '$1$'", toString(info_shared)); + } + } +#if defined(UNX) + if ( geteuid() == 0 ) + { + if ( !(option_shared || option_bundled || option_help) ) + { + logger->log(LogLevel::SEVERE, "Cannot run $1$ as root without $2$ or $3$ option.", + APP_NAME, toString(info_shared), toString(info_bundled)); + return 1; + } + } +#endif + + if (subCommand == "reinstall") + { + //We must prevent that services and types are loaded by UNO, + //otherwise we cannot delete the registry data folder. + OUString extensionUnorc; + if (repository == "user") + extensionUnorc = "$UNO_USER_PACKAGES_CACHE/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc"; + else if (repository == "shared") + extensionUnorc = "$SHARED_EXTENSIONS_USER/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc"; + else if (repository == "bundled") + extensionUnorc = "$BUNDLED_EXTENSIONS_USER/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc"; + else + OSL_ASSERT(false); + + ::rtl::Bootstrap::expandMacros(extensionUnorc); + oslFileError e = osl_removeFile(extensionUnorc.pData); + if (e != osl_File_E_None && e != osl_File_E_NOENT) + throw Exception("Could not delete " + extensionUnorc, nullptr); + } + + Reference<deployment::XExtensionManager> xExtensionManager( + deployment::ExtensionManager::get( xComponentContext ) ); + + Reference<css::ucb::XCommandEnvironment> xCmdEnv( + createCmdEnv(xComponentContext, option_force, option_verbose, option_suppressLicense)); + + //synchronize bundled/shared extensions + //Do not synchronize when command is "reinstall". This could add types and services to UNO and + //prevent the deletion of the registry data folder + //syncing is done in XExtensionManager.reinstall + if (!subcmd_gui && subCommand != "reinstall" + && ! dp_misc::office_is_running()) + dp_misc::syncRepositories(false, xCmdEnv); + + if ( subcmd_add || subCommand == "remove" ) + { + for (const OUString & cmdPackage : cmdPackages) + { + if (subcmd_add) + { + beans::NamedValue nvSuppress( + "SUPPRESS_LICENSE", option_suppressLicense ? + Any(OUString("1")):Any(OUString("0"))); + xExtensionManager->addExtension( + cmdPackage, Sequence<beans::NamedValue>(&nvSuppress, 1), + repository, Reference<task::XAbortChannel>(), xCmdEnv); + } + else + { + try + { + xExtensionManager->removeExtension( + cmdPackage, cmdPackage, repository, + Reference<task::XAbortChannel>(), xCmdEnv ); + } + catch (const lang::IllegalArgumentException &) + { + Reference<deployment::XPackage> p( + findPackage(repository, + xExtensionManager, xCmdEnv, cmdPackage ) ); + if ( !p.is()) + throw; + else if (p.is()) + xExtensionManager->removeExtension( + ::dp_misc::getIdentifier(p), p->getName(), + repository, + Reference<task::XAbortChannel>(), xCmdEnv ); + } + } + } + } + else if ( subCommand == "reinstall" ) + { + xExtensionManager->reinstallDeployedExtensions( + false, repository, Reference<task::XAbortChannel>(), xCmdEnv); + } + else if ( subCommand == "list" ) + { + std::vector<Reference<deployment::XPackage> > vecExtUnaccepted; + ::comphelper::sequenceToContainer(vecExtUnaccepted, + xExtensionManager->getExtensionsWithUnacceptedLicenses( + repository, xCmdEnv)); + + //This vector tells what XPackage in allExtensions has an + //unaccepted license. + std::vector<bool> vecUnaccepted; + std::vector<Reference<deployment::XPackage> > allExtensions; + if (cmdPackages.empty()) + { + Sequence< Reference<deployment::XPackage> > + packages = xExtensionManager->getDeployedExtensions( + repository, Reference<task::XAbortChannel>(), xCmdEnv ); + + std::vector<Reference<deployment::XPackage> > vec_packages; + ::comphelper::sequenceToContainer(vec_packages, packages); + + //First copy the extensions with the unaccepted license + //to vector allExtensions. + allExtensions.resize(vecExtUnaccepted.size() + vec_packages.size()); + + std::vector<Reference<deployment::XPackage> >::iterator i_all_ext = + std::copy(vecExtUnaccepted.begin(), vecExtUnaccepted.end(), + allExtensions.begin()); + //Now copy those we got from getDeployedExtensions + std::copy(vec_packages.begin(), vec_packages.end(), i_all_ext); + + //Now prepare the vector which tells what extension has an + //unaccepted license + vecUnaccepted.resize(vecExtUnaccepted.size() + vec_packages.size()); + std::fill_n(vecUnaccepted.begin(), vecExtUnaccepted.size(), true); + std::fill_n(vecUnaccepted.begin() + vecExtUnaccepted.size(), + vec_packages.size(), false); + + dp_misc::writeConsole( + OUStringConcatenation("All deployed " + repository + " extensions:\n\n")); + } + else + { + //The user provided the names (ids or file names) of the extensions + //which shall be listed + for (const OUString & cmdPackage : cmdPackages) + { + Reference<deployment::XPackage> extension; + try + { + extension = xExtensionManager->getDeployedExtension( + repository, cmdPackage, cmdPackage, xCmdEnv ); + } + catch (const lang::IllegalArgumentException &) + { + extension = findPackage(repository, + xExtensionManager, xCmdEnv, cmdPackage ); + } + + //Now look if the requested extension has an unaccepted license + bool bUnacceptedLic = false; + if (!extension.is()) + { + std::vector<Reference<deployment::XPackage> >::const_iterator + i = std::find_if( + vecExtUnaccepted.begin(), + vecExtUnaccepted.end(), ExtensionName(cmdPackage)); + if (i != vecExtUnaccepted.end()) + { + extension = *i; + bUnacceptedLic = true; + } + } + + if (!extension.is()) + throw lang::IllegalArgumentException( + "There is no such extension deployed: " + + cmdPackage,nullptr,-1); + allExtensions.push_back(extension); + vecUnaccepted.push_back(bUnacceptedLic); + } + + } + + printf_packages(allExtensions, vecUnaccepted, xCmdEnv ); + } + else if ( subCommand == "validate" ) + { + std::vector<Reference<deployment::XPackage> > vecExtUnaccepted; + ::comphelper::sequenceToContainer( + vecExtUnaccepted, xExtensionManager->getExtensionsWithUnacceptedLicenses( + repository, xCmdEnv)); + + for (const OUString & cmdPackage : cmdPackages) + { + Reference<deployment::XPackage> extension; + try + { + extension = xExtensionManager->getDeployedExtension( + repository, cmdPackage, cmdPackage, xCmdEnv ); + } + catch (const lang::IllegalArgumentException &) + { + extension = findPackage( + repository, xExtensionManager, xCmdEnv, cmdPackage ); + } + + if (!extension.is()) + { + std::vector<Reference<deployment::XPackage> >::const_iterator + i = std::find_if( + vecExtUnaccepted.begin(), + vecExtUnaccepted.end(), ExtensionName(cmdPackage)); + if (i != vecExtUnaccepted.end()) + { + extension = *i; + } + } + + if (extension.is()) + xExtensionManager->checkPrerequisitesAndEnable( + extension, Reference<task::XAbortChannel>(), xCmdEnv); + } + } + else if ( subCommand == "gui" ) + { + Reference<ui::dialogs::XAsynchronousExecutableDialog> xDialog( + deployment::ui::PackageManagerDialog::createAndInstall( + xComponentContext, + !cmdPackages.empty() ? cmdPackages[0] : OUString() )); + + osl::Condition dialogEnded; + dialogEnded.reset(); + + Reference< ui::dialogs::XDialogClosedListener > xListener( + new DialogClosedListenerImpl( dialogEnded ) ); + + xDialog->startExecuteModal(xListener); + dialogEnded.wait(); + return 0; + } + else + { + logger->log(LogLevel::SEVERE, + "Unknown sub-command: '$1$'. Use $2$ $3$ to print all options.", + subCommand, APP_NAME, toString(info_help)); + return 1; + } + + logger->log(LogLevel::INFO, "$1$ done.", APP_NAME); + //Force to release all bridges which connect us to the child processes + dp_misc::disposeBridges(xLocalComponentContext); + css::uno::Reference<css::lang::XComponent>( + xLocalComponentContext, css::uno::UNO_QUERY_THROW)->dispose(); + return 0; + } + catch (const ucb::CommandFailedException &e) + { + logger->log(LogLevel::SEVERE, "Exception occurred: $1$", e.Message); + } + catch (const ucb::CommandAbortedException &) + { + logger->log(LogLevel::SEVERE, "$1$ aborted.", APP_NAME); + bShowFailedMsg = false; + } + catch (const deployment::DeploymentException & exc) + { + logger->log(LogLevel::SEVERE, "Exception occurred: $1$", exc.Message); + logger->log(LogLevel::INFO, " Cause: $1$", comphelper::anyToString(exc.Cause)); + } + catch (const LockFileException & e) + { + // No logger since it requires UNO which we don't have here + dp_misc::writeConsoleError(OUStringConcatenation(e.Message + "\n")); + bShowFailedMsg = false; + } + catch (const css::uno::Exception & e ) { + Any exc( ::cppu::getCaughtException() ); + + logger->log(LogLevel::SEVERE, "Exception occurred: $1$", e.Message); + logger->log(LogLevel::INFO, " Cause: $1$", comphelper::anyToString(exc)); + } + if (bShowFailedMsg) + logger->log(LogLevel::SEVERE, "$1$ failed.", APP_NAME); + dp_misc::disposeBridges(xLocalComponentContext); + if (xLocalComponentContext.is()) { + css::uno::Reference<css::lang::XComponent>( + xLocalComponentContext, css::uno::UNO_QUERY_THROW)->dispose(); + } + return 1; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/pkgchk/unopkg/unopkg_cmdenv.cxx b/desktop/source/pkgchk/unopkg/unopkg_cmdenv.cxx new file mode 100644 index 000000000..cca5b7ae3 --- /dev/null +++ b/desktop/source/pkgchk/unopkg/unopkg_cmdenv.cxx @@ -0,0 +1,390 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <strings.hrc> +#include <dp_misc.h> +#include <dp_shared.hxx> +#include "unopkg_shared.h" +#include <i18nlangtag/languagetag.hxx> +#include <rtl/ustrbuf.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/anytostring.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/configmgr.hxx> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/task/XInteractionApprove.hpp> +#include <com/sun/star/deployment/DeploymentException.hpp> +#include <com/sun/star/deployment/InstallException.hpp> +#include <com/sun/star/deployment/LicenseException.hpp> +#include <com/sun/star/deployment/VersionException.hpp> +#include <com/sun/star/deployment/PlatformException.hpp> +#include <com/sun/star/i18n/Collator.hpp> +#include <com/sun/star/i18n/CollatorOptions.hpp> + +#include <dp_version.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; +using namespace ::unopkg; + + +namespace { + + +class CommandEnvironmentImpl + : public ::cppu::WeakImplHelper< XCommandEnvironment, + task::XInteractionHandler, + XProgressHandler > +{ + sal_Int32 m_logLevel; + bool m_option_force_overwrite; + bool m_option_verbose; + bool m_option_suppress_license; + Reference< XComponentContext > m_xComponentContext; + Reference< XProgressHandler > m_xLogFile; + + /// @throws RuntimeException + void update_( Any const & Status ); + void printLicense(std::u16string_view sName,std::u16string_view sLicense, + bool & accept, bool & decline); + +public: + virtual ~CommandEnvironmentImpl() override; + CommandEnvironmentImpl( + Reference<XComponentContext> const & xComponentContext, + bool option_force_overwrite, + bool option_verbose, + bool option_suppress_license); + + // XCommandEnvironment + virtual Reference< task::XInteractionHandler > SAL_CALL + getInteractionHandler() override; + virtual Reference< XProgressHandler > SAL_CALL getProgressHandler() override; + + // XInteractionHandler + virtual void SAL_CALL handle( + Reference< task::XInteractionRequest > const & xRequest ) override; + + // XProgressHandler + virtual void SAL_CALL push( Any const & Status ) override; + virtual void SAL_CALL update( Any const & Status ) override; + virtual void SAL_CALL pop() override; +}; + + +CommandEnvironmentImpl::CommandEnvironmentImpl( + Reference<XComponentContext> const & xComponentContext, + bool option_force_overwrite, + bool option_verbose, + bool option_suppressLicense) + : m_logLevel(0), + m_option_force_overwrite( option_force_overwrite ), + m_option_verbose( option_verbose ), + m_option_suppress_license( option_suppressLicense ), + m_xComponentContext(xComponentContext) +{ + m_xLogFile.set( + xComponentContext->getServiceManager() + ->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.deployment.ProgressLog", + Sequence<Any>(), xComponentContext ), + UNO_QUERY_THROW ); +} + + +CommandEnvironmentImpl::~CommandEnvironmentImpl() +{ + try { + Reference< lang::XComponent > xComp( m_xLogFile, UNO_QUERY ); + if (xComp.is()) + xComp->dispose(); + } + catch (const RuntimeException &) { + TOOLS_WARN_EXCEPTION( "desktop", "" ); + } +} + +//May throw exceptions +void CommandEnvironmentImpl::printLicense( + std::u16string_view sName, std::u16string_view sLicense, bool & accept, bool &decline) +{ + OUString s1tmp(DpResId(RID_STR_UNOPKG_ACCEPT_LIC_1)); + OUString s1(s1tmp.replaceAll("$NAME", sName)); + OUString s2 = DpResId(RID_STR_UNOPKG_ACCEPT_LIC_2); + OUString s3 = DpResId(RID_STR_UNOPKG_ACCEPT_LIC_3); + OUString s4 = DpResId(RID_STR_UNOPKG_ACCEPT_LIC_4); + OUString sYES = DpResId(RID_STR_UNOPKG_ACCEPT_LIC_YES); + OUString sY = DpResId(RID_STR_UNOPKG_ACCEPT_LIC_Y); + OUString sNO = DpResId(RID_STR_UNOPKG_ACCEPT_LIC_NO); + OUString sN = DpResId(RID_STR_UNOPKG_ACCEPT_LIC_N); + + OUString sNewLine("\n"); + + dp_misc::writeConsole(OUStringConcatenation(sNewLine + sNewLine + s1 + sNewLine + sNewLine)); + dp_misc::writeConsole(OUStringConcatenation(sLicense + sNewLine + sNewLine)); + dp_misc::writeConsole(OUStringConcatenation(s2 + sNewLine)); + dp_misc::writeConsole(s3); + + //the user may enter "yes" or "no", we compare in a case insensitive way + Reference< css::i18n::XCollator > xCollator = + css::i18n::Collator::create( m_xComponentContext ); + xCollator->loadDefaultCollator( + LanguageTag(utl::ConfigManager::getUILocale()).getLocale(), + css::i18n::CollatorOptions::CollatorOptions_IGNORE_CASE); + + do + { + OUString sAnswer = dp_misc::readConsole(); + if (xCollator->compareString(sAnswer, sYES) == 0 + || xCollator->compareString(sAnswer, sY) == 0) + { + accept = true; + break; + } + else if(xCollator->compareString(sAnswer, sNO) == 0 + || xCollator->compareString(sAnswer, sN) == 0) + { + decline = true; + break; + } + else + { + dp_misc::writeConsole(OUStringConcatenation(sNewLine + sNewLine + s4 + sNewLine)); + } + } + while(true); +} + +// XCommandEnvironment + +Reference< task::XInteractionHandler > +CommandEnvironmentImpl::getInteractionHandler() +{ + return this; +} + + +Reference< XProgressHandler > CommandEnvironmentImpl::getProgressHandler() +{ + return this; +} + +// XInteractionHandler + +void CommandEnvironmentImpl::handle( + Reference<task::XInteractionRequest> const & xRequest ) +{ + Any request( xRequest->getRequest() ); + OSL_ASSERT( request.getValueTypeClass() == TypeClass_EXCEPTION ); + dp_misc::TRACE("[unopkg_cmdenv.cxx] incoming request:\n" + + ::comphelper::anyToString(request) + "\n\n"); + + // selections: + bool approve = false; + bool abort = false; + + lang::WrappedTargetException wtExc; + deployment::LicenseException licExc; + deployment::InstallException instExc; + deployment::PlatformException platExc; + + if (request >>= wtExc) { + // ignore intermediate errors of legacy packages, i.e. + // former pkgchk behaviour: + const Reference<deployment::XPackage> xPackage( + wtExc.Context, UNO_QUERY ); + OSL_ASSERT( xPackage.is() ); + if (xPackage.is()) { + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) { + approve = (xPackage->isBundle() && + xPackageType->getMediaType().match( + "application/vnd.sun.star.legacy-package-bundle") ); + } + } + abort = !approve; + if (abort) { + // notify cause as error: + request = wtExc.TargetException; + } + else { + // handable deployment error signalled, e.g. + // bundle item registration failed, notify as warning: + update_( wtExc.TargetException ); + } + } + else if (request >>= licExc) + { + if ( !m_option_suppress_license ) + printLicense(licExc.ExtensionName, licExc.Text, approve, abort); + else + { + approve = true; + abort = false; + } + } + else if (request >>= instExc) + { + //Only if the unopgk was started with gui + extension then the user is asked. + //In console mode there is no asking. + approve = true; + } + else if (request >>= platExc) + { + OUString sMsg(DpResId(RID_STR_UNSUPPORTED_PLATFORM)); + sMsg = sMsg.replaceAll("%Name", platExc.package->getDisplayName()); + dp_misc::writeConsole(OUStringConcatenation("\n" + sMsg + "\n\n")); + approve = true; + } + else { + deployment::VersionException nc_exc; + if (request >>= nc_exc) { + approve = m_option_force_overwrite || + (::dp_misc::compareVersions(nc_exc.NewVersion, nc_exc.Deployed->getVersion()) + == ::dp_misc::GREATER); + abort = !approve; + } + else + return; // unknown request => no selection at all + } + + if (abort && m_option_verbose) + { + OUString msg = ::comphelper::anyToString(request); + dp_misc::writeConsoleError(OUStringConcatenation("\nERROR: " + msg + "\n")); + } + + // select: + const css::uno::Sequence<css::uno::Reference<css::task::XInteractionContinuation>> xIC = xRequest->getContinuations(); + for ( auto const& rCont : xIC ) + { + if (approve) { + Reference<task::XInteractionApprove> xInteractionApprove( + rCont, UNO_QUERY ); + if (xInteractionApprove.is()) { + xInteractionApprove->select(); + break; + } + } + else if (abort) { + Reference<task::XInteractionAbort> xInteractionAbort( + rCont, UNO_QUERY ); + if (xInteractionAbort.is()) { + xInteractionAbort->select(); + break; + } + } + } +} + +// XProgressHandler + +void CommandEnvironmentImpl::push( Any const & Status ) +{ + update_( Status ); + OSL_ASSERT( m_logLevel >= 0 ); + ++m_logLevel; + if (m_xLogFile.is()) + m_xLogFile->push( Status ); +} + + +void CommandEnvironmentImpl::update_( Any const & Status ) +{ + if (! Status.hasValue()) + return; + bool bUseErr = false; + OUString msg; + if (Status >>= msg) { + if (! m_option_verbose) + return; + } + else { + OUStringBuffer buf; + buf.append( "WARNING: " ); + deployment::DeploymentException dp_exc; + if (Status >>= dp_exc) { + buf.append( dp_exc.Message ); + buf.append( ", Cause: " ); + buf.append( ::comphelper::anyToString(dp_exc.Cause) ); + } + else { + buf.append( ::comphelper::anyToString(Status) ); + } + msg = buf.makeStringAndClear(); + bUseErr = true; + } + OSL_ASSERT( m_logLevel >= 0 ); + for ( sal_Int32 n = 0; n < m_logLevel; ++n ) + { + if (bUseErr) + dp_misc::writeConsoleError(u" "); + else + dp_misc::writeConsole(u" "); + } + + if (bUseErr) + dp_misc::writeConsoleError(OUStringConcatenation(msg + "\n")); + else + dp_misc::writeConsole(OUStringConcatenation(msg + "\n")); +} + + +void CommandEnvironmentImpl::update( Any const & Status ) +{ + update_( Status ); + if (m_xLogFile.is()) + m_xLogFile->update( Status ); +} + + +void CommandEnvironmentImpl::pop() +{ + OSL_ASSERT( m_logLevel > 0 ); + --m_logLevel; + if (m_xLogFile.is()) + m_xLogFile->pop(); +} + + +} // anon namespace + +namespace unopkg { + + +Reference< XCommandEnvironment > createCmdEnv( + Reference< XComponentContext > const & xContext, + bool option_force_overwrite, + bool option_verbose, + bool option_suppress_license) +{ + return new CommandEnvironmentImpl( + xContext, option_force_overwrite, option_verbose, option_suppress_license); +} +} // unopkg + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/pkgchk/unopkg/unopkg_main.c b/desktop/source/pkgchk/unopkg/unopkg_main.c new file mode 100644 index 000000000..83b20b0b4 --- /dev/null +++ b/desktop/source/pkgchk/unopkg/unopkg_main.c @@ -0,0 +1,26 @@ +/* -*- 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 <sal/main.h> + +#include "unopkg_main.h" + +SAL_IMPLEMENT_MAIN() { return unopkg_main(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/pkgchk/unopkg/unopkg_main.h b/desktop/source/pkgchk/unopkg/unopkg_main.h new file mode 100644 index 000000000..0fcb1013d --- /dev/null +++ b/desktop/source/pkgchk/unopkg/unopkg_main.h @@ -0,0 +1,34 @@ +/* -*- 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 . + */ + +#pragma once + +#include <desktop/dllapi.h> + +#if defined __cplusplus +extern "C" { +#endif + +DESKTOP_DLLPUBLIC int unopkg_main(void); + +#if defined __cplusplus +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/pkgchk/unopkg/unopkg_misc.cxx b/desktop/source/pkgchk/unopkg/unopkg_misc.cxx new file mode 100644 index 000000000..402833aa5 --- /dev/null +++ b/desktop/source/pkgchk/unopkg/unopkg_misc.cxx @@ -0,0 +1,458 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <config_folders.h> + +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <rtl/bootstrap.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <osl/process.h> +#include <osl/file.hxx> +#include <unotools/configmgr.hxx> +#include <unotools/bootstrap.hxx> +#include <cppuhelper/bootstrap.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/processfactory.hxx> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ucb/UniversalContentBroker.hpp> + +#include <strings.hrc> +#include "unopkg_shared.h" +#include <dp_identifier.hxx> +#include <dp_misc.h> +#include <dp_shared.hxx> +#include <lockfile.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; + +namespace unopkg { + +OUString toString( OptionInfo const * info ) +{ + assert(info != nullptr); + OUStringBuffer buf; + buf.append("--"); + buf.appendAscii(info->m_name); + if (info->m_short_option != '\0') + { + buf.append(" (short -" ); + buf.append(info->m_short_option ); + buf.append(")"); + } + if (info->m_has_argument) + buf.append(" <argument>" ); + return buf.makeStringAndClear(); +} + + +OptionInfo const * getOptionInfo( + OptionInfo const * list, + OUString const & opt ) +{ + for ( ; list->m_name != nullptr; ++list ) + { + OptionInfo const & option_info = *list; + if (!opt.isEmpty()) + { + if (opt.equalsAsciiL( + option_info.m_name, option_info.m_name_length )) + { + return &option_info; + } + } + } + SAL_WARN( "desktop", opt ); + return nullptr; +} + + +bool isOption( OptionInfo const * option_info, sal_uInt32 * pIndex ) +{ + assert(option_info != nullptr); + if (osl_getCommandArgCount() <= *pIndex) + return false; + + OUString arg; + osl_getCommandArg( *pIndex, &arg.pData ); + sal_Int32 len = arg.getLength(); + + if (len < 2 || arg[ 0 ] != '-') + return false; + + if (len == 2 && arg[ 1 ] == option_info->m_short_option) + { + ++(*pIndex); + dp_misc::TRACE(__FILE__ ": identified option \'\'" + + OUStringChar( option_info->m_short_option ) + "\n"); + return true; + } + if (arg[ 1 ] == '-' && rtl_ustr_ascii_compare( + arg.pData->buffer + 2, option_info->m_name ) == 0) + { + ++(*pIndex); + dp_misc::TRACE(__FILE__ ": identified option \'" + + OUString::createFromAscii(option_info->m_name) + "\'\n"); + return true; + } + return false; +} + + +bool isBootstrapVariable(sal_uInt32 * pIndex) +{ + OSL_ASSERT(osl_getCommandArgCount() >= *pIndex); + + OUString arg; + osl_getCommandArg(*pIndex, &arg.pData); + if (arg.match("-env:")) + { + ++(*pIndex); + return true; + } + return false; +} + + +bool readArgument( + OUString * pValue, OptionInfo const * option_info, sal_uInt32 * pIndex ) +{ + if (isOption( option_info, pIndex )) + { + if (*pIndex < osl_getCommandArgCount()) + { + OSL_ASSERT( pValue != nullptr ); + osl_getCommandArg( *pIndex, &pValue->pData ); + dp_misc::TRACE(__FILE__ ": argument value: " + + *pValue + "\n"); + ++(*pIndex); + return true; + } + --(*pIndex); + } + return false; +} + + +OUString const & getExecutableDir() +{ + static const OUString EXEC = + []() + { + OUString path; + if (osl_getExecutableFile( &path.pData ) != osl_Process_E_None) { + throw RuntimeException("cannot locate executable directory!",nullptr); + } + return path.copy( 0, path.lastIndexOf( '/' ) ); + }(); + return EXEC; +} + + +OUString const & getProcessWorkingDir() +{ + static const OUString WORKING = + []() + { + OUString workingDir; + utl::Bootstrap::getProcessWorkingDir(workingDir); + return workingDir; + }(); + return WORKING; +} + + +OUString makeAbsoluteFileUrl( + OUString const & sys_path, OUString const & base_url ) +{ + // system path to file url + OUString file_url; + oslFileError rc = osl_getFileURLFromSystemPath( sys_path.pData, &file_url.pData ); + if ( rc != osl_File_E_None) { + OUString tempPath; + if ( osl_getSystemPathFromFileURL( sys_path.pData, &tempPath.pData) != osl_File_E_None ) + { + throw RuntimeException("cannot get file url from system path: " + + sys_path ); + } + file_url = sys_path; + } + + OUString abs; + if (osl_getAbsoluteFileURL( + base_url.pData, file_url.pData, &abs.pData ) != osl_File_E_None) + { + throw RuntimeException( + "making absolute file url failed: \"" + base_url + + "\" (base-url) and \"" + file_url + "\" (file-url)!" ); + } + return abs[ abs.getLength() -1 ] == '/' + ? abs.copy( 0, abs.getLength() -1 ) : abs; +} + + +namespace { + + +void printf_space( sal_Int32 space ) +{ + while (space--) + dp_misc::writeConsole(u" "); +} + + +void printf_line( + std::u16string_view name, std::u16string_view value, sal_Int32 level ) +{ + printf_space( level ); + dp_misc::writeConsole(OUStringConcatenation(OUString::Concat(name) + ": " + value + "\n")); +} + + +void printf_package( + Reference<deployment::XPackage> const & xPackage, + Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level ) +{ + beans::Optional< OUString > id( + level == 0 + ? beans::Optional< OUString >( + true, dp_misc::getIdentifier( xPackage ) ) + : xPackage->getIdentifier() ); + if (id.IsPresent) + printf_line( u"Identifier", id.Value, level ); + OUString version(xPackage->getVersion()); + if (!version.isEmpty()) + printf_line( u"Version", version, level + 1 ); + printf_line( u"URL", xPackage->getURL(), level + 1 ); + + beans::Optional< beans::Ambiguous<sal_Bool> > option( + xPackage->isRegistered( Reference<task::XAbortChannel>(), xCmdEnv ) ); + OUString value; + if (option.IsPresent) { + beans::Ambiguous<sal_Bool> const & reg = option.Value; + if (reg.IsAmbiguous) + value = "unknown"; + else + value = reg.Value ? std::u16string_view(u"yes") : std::u16string_view(u"no"); + } + else + value = "n/a"; + printf_line( u"is registered", value, level + 1 ); + + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) { + printf_line( u"Media-Type", xPackageType->getMediaType(), level + 1 ); + } + printf_line( u"Description", xPackage->getDescription(), level + 1 ); + if (!xPackage->isBundle()) + return; + + Sequence< Reference<deployment::XPackage> > seq( + xPackage->getBundle( Reference<task::XAbortChannel>(), xCmdEnv ) ); + printf_space( level + 1 ); + dp_misc::writeConsole(u"bundled Packages: {\n"); + std::vector<Reference<deployment::XPackage> >vec_bundle; + ::comphelper::sequenceToContainer(vec_bundle, seq); + printf_packages( vec_bundle, std::vector<bool>(vec_bundle.size()), + xCmdEnv, level + 2 ); + printf_space( level + 1 ); + dp_misc::writeConsole(u"}\n"); +} + +} // anon namespace + +static void printf_unaccepted_licenses( + Reference<deployment::XPackage> const & ext) +{ + OUString id( + dp_misc::getIdentifier(ext) ); + printf_line( u"Identifier", id, 0 ); + printf_space(1); + dp_misc::writeConsole(u"License not accepted\n\n"); +} + + +void printf_packages( + std::vector< Reference<deployment::XPackage> > const & allExtensions, + std::vector<bool> const & vecUnaccepted, + Reference<XCommandEnvironment> const & xCmdEnv, sal_Int32 level ) +{ + OSL_ASSERT(allExtensions.size() == vecUnaccepted.size()); + + if (allExtensions.empty()) + { + printf_space( level ); + dp_misc::writeConsole(u"<none>\n"); + } + else + { + int index = 0; + for (auto const& extension : allExtensions) + { + if (vecUnaccepted[index]) + printf_unaccepted_licenses(extension); + else + printf_package( extension, xCmdEnv, level ); + dp_misc::writeConsole(u"\n"); + ++index; + } + } +} + + +namespace { + + +Reference<XComponentContext> bootstrapStandAlone() +{ + Reference<XComponentContext> xContext = + ::cppu::defaultBootstrap_InitialComponentContext(); + + Reference<lang::XMultiServiceFactory> xServiceManager( + xContext->getServiceManager(), UNO_QUERY_THROW ); + // set global process service factory used by unotools config helpers + ::comphelper::setProcessServiceFactory( xServiceManager ); + + // Initialize the UCB (for backwards compatibility, in case some code still + // uses plain createInstance w/o args directly to obtain an instance): + UniversalContentBroker::create( xContext ); + + return xContext; +} + + +Reference<XComponentContext> connectToOffice( + Reference<XComponentContext> const & xLocalComponentContext, + bool verbose ) +{ + OUString pipeId( ::dp_misc::generateRandomPipeId() ); + OUString acceptArg = "--accept=pipe,name=" + pipeId + ";urp;"; + + Sequence<OUString> args { "--nologo", "--nodefault", acceptArg }; + OUString appURL( getExecutableDir() + "/soffice" ); + + if (verbose) + { + dp_misc::writeConsole(OUStringConcatenation( + "Raising process: " + appURL + + "\nArguments: --nologo --nodefault " + args[2] + + "\n")); + } + + ::dp_misc::raiseProcess( appURL, args ); + + if (verbose) + dp_misc::writeConsole(u"OK. Connecting..."); + + OUString sUnoUrl = "uno:pipe,name=" + pipeId + ";urp;StarOffice.ComponentContext"; + Reference<XComponentContext> xRet( + ::dp_misc::resolveUnoURL( + sUnoUrl, xLocalComponentContext ), + UNO_QUERY_THROW ); + if (verbose) + dp_misc::writeConsole(u"OK.\n"); + + return xRet; +} + +} // anon namespace + +/** returns the path to the lock file used by unopkg. + @return the path. An empty string signifies an error. +*/ +static OUString getLockFilePath() +{ + OUString ret; + OUString sBootstrap("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}"); + rtl::Bootstrap::expandMacros(sBootstrap); + OUString sAbs; + if (::osl::File::E_None == ::osl::File::getAbsoluteFileURL( + sBootstrap, ".lock", sAbs)) + { + if (::osl::File::E_None == + ::osl::File::getSystemPathFromFileURL(sAbs, sBootstrap)) + { + ret = sBootstrap; + } + } + + return ret; +} + +Reference<XComponentContext> getUNO( + bool verbose, bool bGui, const OUString& sTempDir, + Reference<XComponentContext> & out_localContext) +{ + // do not create any user data (for the root user) in --shared mode: + if (!sTempDir.isEmpty()) + rtl::Bootstrap::set("UserInstallation", sTempDir); + + // hold lock during process runtime: + static ::desktop::Lockfile s_lockfile( false /* no IPC server */ ); + Reference<XComponentContext> xComponentContext( bootstrapStandAlone() ); + out_localContext = xComponentContext; + if (::dp_misc::office_is_running()) { + xComponentContext.set( + connectToOffice( xComponentContext, verbose ) ); + } + else + { + if (! s_lockfile.check( nullptr )) + { + OUString sMsg(DpResId(RID_STR_CONCURRENTINSTANCE)); + OUString sError(DpResId(RID_STR_UNOPKG_ERROR)); + + sMsg += "\n" + getLockFilePath(); + + if (bGui) + { + //We show a message box or print to the console that there + //is another instance already running + if ( ! InitVCL() ) + throw RuntimeException( "Cannot initialize VCL!" ); + { + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(nullptr, + VclMessageType::Warning, VclButtonsType::Ok, + sMsg)); + xWarn->set_title(utl::ConfigManager::getProductName()); + xWarn->run(); + } + DeInitVCL(); + } + + throw LockFileException(sError + sMsg); + } + } + + return xComponentContext; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/pkgchk/unopkg/unopkg_shared.h b/desktop/source/pkgchk/unopkg/unopkg_shared.h new file mode 100644 index 000000000..21d0f6a92 --- /dev/null +++ b/desktop/source/pkgchk/unopkg/unopkg_shared.h @@ -0,0 +1,119 @@ +/* -*- 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 <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/deployment/XPackage.hpp> +#include <osl/diagnose.h> +#include <rtl/ustring.hxx> + +#include <utility> +#include <vector> + +#define APP_NAME "unopkg" + +namespace unopkg { + +struct OptionInfo +{ + char const * m_name; + sal_uInt32 m_name_length; + sal_Unicode m_short_option; + bool m_has_argument; +}; + +struct LockFileException +{ + explicit LockFileException(OUString sMessage) : + Message(std::move(sMessage)) {} + + OUString Message; +}; + + +OUString toString( OptionInfo const * info ); + + +OptionInfo const * getOptionInfo( + OptionInfo const * list, + OUString const & opt ); + + +bool isOption( OptionInfo const * option_info, sal_uInt32 * pIndex ); + + +bool readArgument( + OUString * pValue, OptionInfo const * option_info, + sal_uInt32 * pIndex ); + + +inline bool readOption( + bool * flag, OptionInfo const * option_info, sal_uInt32 * pIndex ) +{ + if (isOption( option_info, pIndex )) { + OSL_ASSERT( flag != nullptr ); + *flag = true; + return true; + } + return false; +} + + +/** checks if an argument is a bootstrap variable. These start with -env:. For example + -env:UNO_JAVA_JFW_USER_DATA=file:///d:/user +*/ +bool isBootstrapVariable(sal_uInt32 * pIndex); + +OUString const & getExecutableDir(); + + +OUString const & getProcessWorkingDir(); + + +OUString makeAbsoluteFileUrl( + OUString const & sys_path, OUString const & base_url ); + + + + +css::uno::Reference<css::ucb::XCommandEnvironment> createCmdEnv( + css::uno::Reference<css::uno::XComponentContext> const & xContext, + bool option_force_overwrite, + bool option_verbose, + bool option_suppressLicense); + +void printf_packages( + std::vector< + css::uno::Reference<css::deployment::XPackage> > const & allExtensions, + std::vector<bool> const & vecUnaccepted, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + sal_Int32 level = 0 ); + + + + +css::uno::Reference<css::uno::XComponentContext> getUNO( + bool verbose, bool bGui, const OUString& sTempDir, + css::uno::Reference<css::uno::XComponentContext> & out_LocalComponentContext); + +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |