diff options
Diffstat (limited to 'desktop/source/deployment/misc/dp_update.cxx')
-rw-r--r-- | desktop/source/deployment/misc/dp_update.cxx | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/desktop/source/deployment/misc/dp_update.cxx b/desktop/source/deployment/misc/dp_update.cxx new file mode 100644 index 000000000..7116be42b --- /dev/null +++ b/desktop/source/deployment/misc/dp_update.cxx @@ -0,0 +1,408 @@ +/* -*- 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 <config_folders.h> + +#include <dp_update.hxx> +#include <dp_version.hxx> +#include <dp_identifier.hxx> +#include <dp_descriptioninfoset.hxx> + +#include <com/sun/star/ucb/CommandAbortedException.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <osl/diagnose.h> +#include <rtl/bootstrap.hxx> +#include <sal/log.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +namespace dp_misc { +namespace { + +int determineHighestVersion( + OUString const & userVersion, + OUString const & sharedVersion, + OUString const & bundledVersion, + OUString const & onlineVersion) +{ + int index = 0; + OUString greatest = userVersion; + if (dp_misc::compareVersions(sharedVersion, greatest) == dp_misc::GREATER) + { + index = 1; + greatest = sharedVersion; + } + if (dp_misc::compareVersions(bundledVersion, greatest) == dp_misc::GREATER) + { + index = 2; + greatest = bundledVersion; + } + if (dp_misc::compareVersions(onlineVersion, greatest) == dp_misc::GREATER) + { + index = 3; + } + return index; +} + +Sequence< Reference< xml::dom::XElement > > +getUpdateInformation( Reference<deployment::XUpdateInformationProvider > const & updateInformation, + Sequence< OUString > const & urls, + OUString const & identifier, + uno::Any & out_error) +{ + try { + return updateInformation->getUpdateInformation(urls, identifier); + } catch (const uno::RuntimeException &) { + throw; + } catch (const ucb::CommandFailedException & e) { + out_error = e.Reason; + } catch (const ucb::CommandAbortedException &) { + } catch (const uno::Exception & e) { + out_error <<= e; + } + return + Sequence<Reference< xml::dom::XElement > >(); +} + +void getOwnUpdateInfos( + Reference<uno::XComponentContext> const & xContext, + Reference<deployment::XUpdateInformationProvider > const & updateInformation, + UpdateInfoMap& inout_map, std::vector<std::pair<Reference<deployment::XPackage>, uno::Any> > & out_errors, + bool & out_allFound) +{ + bool bAllHaveOwnUpdateInformation = true; + for (auto & inout : inout_map) + { + OSL_ASSERT(inout.second.extension.is()); + Sequence<OUString> urls(inout.second.extension->getUpdateInformationURLs()); + if (urls.hasElements()) + { + const OUString search_id = dp_misc::getIdentifier(inout.second.extension); + SAL_INFO( "extensions.update", "Searching update for " << search_id ); + uno::Any anyError; + //It is unclear from the idl if there can be a null reference returned. + //However all valid information should be the same + const Sequence<Reference< xml::dom::XElement > > + infos(getUpdateInformation(updateInformation, urls, search_id, anyError)); + if (anyError.hasValue()) + out_errors.emplace_back(inout.second.extension, anyError); + + for (const Reference< xml::dom::XElement >& element : infos) + { + dp_misc::DescriptionInfoset infoset( + xContext, + Reference< xml::dom::XNode >(element, UNO_QUERY_THROW)); + if (!infoset.hasDescription()) + continue; + std::optional< OUString > result_id(infoset.getIdentifier()); + if (!result_id) + continue; + SAL_INFO( "extensions.update", " found version " + << infoset.getVersion() << " for " << *result_id ); + if (*result_id != search_id) + continue; + inout.second.version = infoset.getVersion(); + inout.second.info.set(element, UNO_QUERY_THROW); + break; + } + } + else + { + bAllHaveOwnUpdateInformation = false; + } + } + out_allFound = bAllHaveOwnUpdateInformation; +} + +void getDefaultUpdateInfos( + Reference<uno::XComponentContext> const & xContext, + Reference<deployment::XUpdateInformationProvider > const & updateInformation, + UpdateInfoMap& inout_map, + std::vector<std::pair<Reference<deployment::XPackage>, uno::Any> > & out_errors) +{ + const OUString sDefaultURL(dp_misc::getExtensionDefaultUpdateURL()); + OSL_ASSERT(!sDefaultURL.isEmpty()); + + Any anyError; + const Sequence< Reference< xml::dom::XElement > > + infos( + getUpdateInformation( + updateInformation, + Sequence< OUString >(&sDefaultURL, 1), OUString(), anyError)); + if (anyError.hasValue()) + out_errors.emplace_back(Reference<deployment::XPackage>(), anyError); + for (const Reference< xml::dom::XElement >& element : infos) + { + Reference< xml::dom::XNode > node(element, UNO_QUERY_THROW); + dp_misc::DescriptionInfoset infoset(xContext, node); + std::optional< OUString > id(infoset.getIdentifier()); + if (!id) { + continue; + } + UpdateInfoMap::iterator j = inout_map.find(*id); + if (j != inout_map.end()) + { + //skip those extension which provide its own update urls + if (j->second.extension->getUpdateInformationURLs().getLength()) + continue; + OUString v(infoset.getVersion()); + //look for the highest version in the online repository + if (dp_misc::compareVersions(v, j->second.version) == + dp_misc::GREATER) + { + j->second.version = v; + j->second.info = node; + } + } + } +} + +bool containsBundledOnly(Sequence<Reference<deployment::XPackage> > const & sameIdExtensions) +{ + OSL_ASSERT(sameIdExtensions.getLength() == 3); + return !sameIdExtensions[0].is() && !sameIdExtensions[1].is() && sameIdExtensions[2].is(); +} + +/** Returns true if the list of extensions are bundled extensions and there are no + other extensions with the same identifier in the shared or user repository. + If extensionList is NULL, then it is checked if there are only bundled extensions. +*/ +bool onlyBundledExtensions( + Reference<deployment::XExtensionManager> const & xExtMgr, + std::vector< Reference<deployment::XPackage > > const * extensionList) +{ + OSL_ASSERT(xExtMgr.is()); + bool bOnlyBundled = true; + if (extensionList) + { + for (auto const& elem : *extensionList) + { + Sequence<Reference<deployment::XPackage> > seqExt = xExtMgr->getExtensionsWithSameIdentifier( + dp_misc::getIdentifier(elem), elem->getName(), Reference<ucb::XCommandEnvironment>()); + + bOnlyBundled = containsBundledOnly(seqExt); + if (!bOnlyBundled) + break; + } + } + else + { + const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = + xExtMgr->getAllExtensions(Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>()); + + for (int pos(0), nLen(seqAllExt.getLength()); bOnlyBundled && pos != nLen; ++pos) + { + bOnlyBundled = containsBundledOnly(seqAllExt[pos]); + } + } + return bOnlyBundled; +} + +} // anon namespace + + +OUString getExtensionDefaultUpdateURL() +{ + OUString sUrl( + "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") + ":Version:ExtensionUpdateURL}"); + ::rtl::Bootstrap::expandMacros(sUrl); + return sUrl; +} + +/* returns the index of the greatest version, starting with 0 + + */ +UPDATE_SOURCE isUpdateUserExtension( + bool bReadOnlyShared, + OUString const & userVersion, + OUString const & sharedVersion, + OUString const & bundledVersion, + OUString const & onlineVersion) +{ + UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE; + if (bReadOnlyShared) + { + if (!userVersion.isEmpty()) + { + int index = determineHighestVersion( + userVersion, sharedVersion, bundledVersion, onlineVersion); + if (index == 1) + retVal = UPDATE_SOURCE_SHARED; + else if (index == 2) + retVal = UPDATE_SOURCE_BUNDLED; + else if (index == 3) + retVal = UPDATE_SOURCE_ONLINE; + } + else if (!sharedVersion.isEmpty()) + { + int index = determineHighestVersion( + OUString(), sharedVersion, bundledVersion, onlineVersion); + if (index == 2) + retVal = UPDATE_SOURCE_BUNDLED; + else if (index == 3) + retVal = UPDATE_SOURCE_ONLINE; + + } + } + else + { + if (!userVersion.isEmpty()) + { + int index = determineHighestVersion( + userVersion, sharedVersion, bundledVersion, onlineVersion); + if (index == 1) + retVal = UPDATE_SOURCE_SHARED; + else if (index == 2) + retVal = UPDATE_SOURCE_BUNDLED; + else if (index == 3) + retVal = UPDATE_SOURCE_ONLINE; + } + } + + return retVal; +} + +UPDATE_SOURCE isUpdateSharedExtension( + bool bReadOnlyShared, + OUString const & sharedVersion, + OUString const & bundledVersion, + OUString const & onlineVersion) +{ + if (bReadOnlyShared) + return UPDATE_SOURCE_NONE; + UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE; + + if (!sharedVersion.isEmpty()) + { + int index = determineHighestVersion( + OUString(), sharedVersion, bundledVersion, onlineVersion); + if (index == 2) + retVal = UPDATE_SOURCE_BUNDLED; + else if (index == 3) + retVal = UPDATE_SOURCE_ONLINE; + } + return retVal; +} + +Reference<deployment::XPackage> +getExtensionWithHighestVersion( + Sequence<Reference<deployment::XPackage> > const & seqExt) +{ + if (!seqExt.hasElements()) + return Reference<deployment::XPackage>(); + + Reference<deployment::XPackage> greatest; + sal_Int32 len = seqExt.getLength(); + + for (sal_Int32 i = 0; i < len; i++) + { + if (!greatest.is()) + { + greatest = seqExt[i]; + continue; + } + Reference<deployment::XPackage> const & current = seqExt[i]; + //greatest has a value + if (! current.is()) + continue; + + if (dp_misc::compareVersions(current->getVersion(), greatest->getVersion()) == dp_misc::GREATER) + greatest = current; + } + return greatest; +} + +UpdateInfo::UpdateInfo( Reference< deployment::XPackage> const & ext): +extension(ext) +{ +} + + +UpdateInfoMap getOnlineUpdateInfos( + Reference<uno::XComponentContext> const &xContext, + Reference<deployment::XExtensionManager> const & xExtMgr, + Reference<deployment::XUpdateInformationProvider > const & updateInformation, + std::vector<Reference<deployment::XPackage > > const * extensionList, + std::vector<std::pair< Reference<deployment::XPackage>, uno::Any> > & out_errors) +{ + OSL_ASSERT(xExtMgr.is()); + UpdateInfoMap infoMap; + if (!xExtMgr.is() || onlyBundledExtensions(xExtMgr, extensionList)) + return infoMap; + + if (!extensionList) + { + const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = xExtMgr->getAllExtensions( + Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>()); + + //fill the UpdateInfoMap. key = extension identifier, value = UpdateInfo + for (int pos = seqAllExt.getLength(); pos --; ) + { + uno::Sequence<Reference<deployment::XPackage> > const & seqExt = seqAllExt[pos]; + + Reference<deployment::XPackage> extension = getExtensionWithHighestVersion(seqExt); + OSL_ASSERT(extension.is()); + + std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.emplace( + dp_misc::getIdentifier(extension), UpdateInfo(extension)); + OSL_ASSERT(insertRet.second); + } + } + else + { + for (auto const& elem : *extensionList) + { + OSL_ASSERT(elem.is()); + std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.emplace( + dp_misc::getIdentifier(elem), UpdateInfo(elem)); + OSL_ASSERT(insertRet.second); + } + } + + //Now find the update information for the extensions which provide their own + //URLs to update information. + bool bAllInfosObtained = false; + getOwnUpdateInfos(xContext, updateInformation, infoMap, out_errors, bAllInfosObtained); + + if (!bAllInfosObtained) + getDefaultUpdateInfos(xContext, updateInformation, infoMap, out_errors); + return infoMap; +} +OUString getHighestVersion( + OUString const & sharedVersion, + OUString const & bundledVersion, + OUString const & onlineVersion) +{ + int index = determineHighestVersion(OUString(), sharedVersion, bundledVersion, onlineVersion); + switch (index) + { + case 1: return sharedVersion; + case 2: return bundledVersion; + case 3: return onlineVersion; + default: OSL_ASSERT(false); + } + + return OUString(); +} +} //namespace dp_misc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |