/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_desktop.hxx" #include "dp_update.hxx" #include "dp_version.hxx" #include "dp_identifier.hxx" #include "dp_descriptioninfoset.hxx" #include "rtl/bootstrap.hxx" using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using ::rtl::OUString; using ::rtl::OString; namespace dp_misc { namespace { int determineHighestVersion( ::rtl::OUString const & userVersion, ::rtl::OUString const & sharedVersion, ::rtl::OUString const & bundledVersion, ::rtl::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 const & updateInformation, Sequence< OUString > const & urls, OUString const & identifier, uno::Any & out_error) { try { return updateInformation->getUpdateInformation(urls, identifier); } catch (uno::RuntimeException &) { throw; } catch (ucb::CommandFailedException & e) { out_error = e.Reason; } catch (ucb::CommandAbortedException &) { } catch (uno::Exception & e) { out_error = uno::makeAny(e); } return Sequence >(); } void getOwnUpdateInfos( Reference const & xContext, Reference const & updateInformation, UpdateInfoMap& inout_map, std::vector, uno::Any> > & out_errors, bool & out_allFound) { bool allHaveOwnUpdateInformation = true; for (UpdateInfoMap::iterator i = inout_map.begin(); i != inout_map.end(); i++) { OSL_ASSERT(i->second.extension.is()); Sequence urls(i->second.extension->getUpdateInformationURLs()); if (urls.getLength()) { const OUString id = dp_misc::getIdentifier(i->second.extension); 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 Sequence > infos(getUpdateInformation(updateInformation, urls, id, anyError)); if (anyError.hasValue()) out_errors.push_back(std::make_pair(i->second.extension, anyError)); for (sal_Int32 j = 0; j < infos.getLength(); ++j) { dp_misc::DescriptionInfoset infoset( xContext, Reference< xml::dom::XNode >(infos[j], UNO_QUERY_THROW)); if (!infoset.hasDescription()) continue; boost::optional< OUString > id2(infoset.getIdentifier()); if (!id2) continue; OSL_ASSERT(*id2 == id); if (*id2 == id) { i->second.version = infoset.getVersion(); i->second.info = Reference< xml::dom::XNode >( infos[j], UNO_QUERY_THROW); } break; } } else { allHaveOwnUpdateInformation &= false; } } out_allFound = allHaveOwnUpdateInformation; } void getDefaultUpdateInfos( Reference const & xContext, Reference const & updateInformation, UpdateInfoMap& inout_map, std::vector, uno::Any> > & out_errors) { const rtl::OUString sDefaultURL(dp_misc::getExtensionDefaultUpdateURL()); OSL_ASSERT(sDefaultURL.getLength()); Any anyError; Sequence< Reference< xml::dom::XElement > > infos( getUpdateInformation( updateInformation, Sequence< OUString >(&sDefaultURL, 1), OUString(), anyError)); if (anyError.hasValue()) out_errors.push_back(std::make_pair(Reference(), anyError)); for (sal_Int32 i = 0; i < infos.getLength(); ++i) { Reference< xml::dom::XNode > node(infos[i], UNO_QUERY_THROW); dp_misc::DescriptionInfoset infoset(xContext, node); boost::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 > const & sameIdExtensions) { OSL_ASSERT(sameIdExtensions.getLength() == 3); if (!sameIdExtensions[0].is() && !sameIdExtensions[1].is() && sameIdExtensions[2].is()) return true; else return false; } /** 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 const & xExtMgr, std::vector< Reference > const * extensionList) { OSL_ASSERT(xExtMgr.is()); bool onlyBundled = true; if (extensionList) { typedef std::vector >::const_iterator CIT; for (CIT i = extensionList->begin(); i != extensionList->end(); i++) { Sequence > seqExt = xExtMgr->getExtensionsWithSameIdentifier( dp_misc::getIdentifier(*i), (*i)->getName(), Reference()); if (!containsBundledOnly(seqExt)) { onlyBundled = false; break; } } } else { const uno::Sequence< uno::Sequence< Reference > > seqAllExt = xExtMgr->getAllExtensions(Reference(), Reference()); for (int pos = seqAllExt.getLength(); pos --; ) { if (!containsBundledOnly(seqAllExt[pos])) { onlyBundled = false; break; } } } return onlyBundled; } } // anon namespace OUString getExtensionDefaultUpdateURL() { ::rtl::OUString sUrl( RTL_CONSTASCII_USTRINGPARAM( "${$BRAND_BASE_DIR/program/" 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, ::rtl::OUString const & userVersion, ::rtl::OUString const & sharedVersion, ::rtl::OUString const & bundledVersion, ::rtl::OUString const & onlineVersion) { UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE; if (bReadOnlyShared) { if (userVersion.getLength()) { 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.getLength()) { int index = determineHighestVersion( OUString(), sharedVersion, bundledVersion, onlineVersion); if (index == 2) retVal = UPDATE_SOURCE_BUNDLED; else if (index == 3) retVal = UPDATE_SOURCE_ONLINE; } //No update for bundled extensions, they are updated only by the setup //else if (bundledVersion.getLength()) //{ // int index = determineHighestVersion( // OUString(), OUString(), bundledVersion, onlineVersion); // if (index == 3) // retVal = UPDATE_SOURCE_ONLINE; //} } else { if (userVersion.getLength()) { 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, ::rtl::OUString const & sharedVersion, ::rtl::OUString const & bundledVersion, ::rtl::OUString const & onlineVersion) { if (bReadOnlyShared) return UPDATE_SOURCE_NONE; UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE; if (sharedVersion.getLength()) { int index = determineHighestVersion( OUString(), sharedVersion, bundledVersion, onlineVersion); if (index == 2) retVal = UPDATE_SOURCE_BUNDLED; else if (index == 3) retVal = UPDATE_SOURCE_ONLINE; } //No update for bundled extensions, they are updated only by the setup //else if (bundledVersion.getLength()) //{ // int index = determineHighestVersion( // OUString(), OUString(), bundledVersion, onlineVersion); // if (index == 3) // retVal = UPDATE_SOURCE_ONLINE; //} return retVal; } Reference getExtensionWithHighestVersion( Sequence > const & seqExt) { if (seqExt.getLength() == 0) return Reference(); Reference greatest; sal_Int32 len = seqExt.getLength(); for (sal_Int32 i = 0; i < len; i++) { if (!greatest.is()) { greatest = seqExt[i]; continue; } Reference 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 const &xContext, Reference const & xExtMgr, Reference const & updateInformation, std::vector > const * extensionList, std::vector, 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 > > seqAllExt = xExtMgr->getAllExtensions( Reference(), Reference()); //fill the UpdateInfoMap. key = extension identifier, value = UpdateInfo for (int pos = seqAllExt.getLength(); pos --; ) { uno::Sequence > const & seqExt = seqAllExt[pos]; Reference extension = getExtensionWithHighestVersion(seqExt); OSL_ASSERT(extension.is()); std::pair insertRet = infoMap.insert( UpdateInfoMap::value_type( dp_misc::getIdentifier(extension), UpdateInfo(extension))); OSL_ASSERT(insertRet.second == true); } } else { typedef std::vector >::const_iterator CIT; for (CIT i = extensionList->begin(); i != extensionList->end(); i++) { OSL_ASSERT(i->is()); std::pair insertRet = infoMap.insert( UpdateInfoMap::value_type( dp_misc::getIdentifier(*i), UpdateInfo(*i))); OSL_ASSERT(insertRet.second == true); } } //Now find the update information for the extensions which provide their own //URLs to update information. bool allInfosObtained = false; getOwnUpdateInfos(xContext, updateInformation, infoMap, out_errors, allInfosObtained); if (!allInfosObtained) getDefaultUpdateInfos(xContext, updateInformation, infoMap, out_errors); return infoMap; } OUString getHighestVersion( ::rtl::OUString const & userVersion, ::rtl::OUString const & sharedVersion, ::rtl::OUString const & bundledVersion, ::rtl::OUString const & onlineVersion) { int index = determineHighestVersion(userVersion, sharedVersion, bundledVersion, onlineVersion); switch (index) { case 0: return userVersion; case 1: return sharedVersion; case 2: return bundledVersion; case 3: return onlineVersion; default: OSL_ASSERT(0); } return OUString(); } } //namespace dp_misc