1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_desktop.hxx" 26 27 28 #include "dp_update.hxx" 29 #include "dp_version.hxx" 30 #include "dp_identifier.hxx" 31 #include "dp_descriptioninfoset.hxx" 32 33 #include "rtl/bootstrap.hxx" 34 35 using namespace ::com::sun::star; 36 using namespace ::com::sun::star::uno; 37 using ::rtl::OUString; 38 using ::rtl::OString; 39 40 41 namespace dp_misc { 42 namespace { 43 44 int determineHighestVersion( 45 ::rtl::OUString const & userVersion, 46 ::rtl::OUString const & sharedVersion, 47 ::rtl::OUString const & bundledVersion, 48 ::rtl::OUString const & onlineVersion) 49 { 50 int index = 0; 51 OUString greatest = userVersion; 52 if (dp_misc::compareVersions(sharedVersion, greatest) == dp_misc::GREATER) 53 { 54 index = 1; 55 greatest = sharedVersion; 56 } 57 if (dp_misc::compareVersions(bundledVersion, greatest) == dp_misc::GREATER) 58 { 59 index = 2; 60 greatest = bundledVersion; 61 } 62 if (dp_misc::compareVersions(onlineVersion, greatest) == dp_misc::GREATER) 63 { 64 index = 3; 65 } 66 return index; 67 } 68 69 Sequence< Reference< xml::dom::XElement > > 70 getUpdateInformation( Reference<deployment::XUpdateInformationProvider > const & updateInformation, 71 Sequence< OUString > const & urls, 72 OUString const & identifier, 73 uno::Any & out_error) 74 { 75 try { 76 return updateInformation->getUpdateInformation(urls, identifier); 77 } catch (uno::RuntimeException &) { 78 throw; 79 } catch (ucb::CommandFailedException & e) { 80 out_error = e.Reason; 81 } catch (ucb::CommandAbortedException &) { 82 } catch (uno::Exception & e) { 83 out_error = uno::makeAny(e); 84 } 85 return 86 Sequence<Reference< xml::dom::XElement > >(); 87 } 88 89 void getOwnUpdateInfos( 90 Reference<uno::XComponentContext> const & xContext, 91 Reference<deployment::XUpdateInformationProvider > const & updateInformation, 92 UpdateInfoMap& inout_map, std::vector<std::pair<Reference<deployment::XPackage>, uno::Any> > & out_errors, 93 bool & out_allFound) 94 { 95 bool allHaveOwnUpdateInformation = true; 96 for (UpdateInfoMap::iterator i = inout_map.begin(); i != inout_map.end(); i++) 97 { 98 OSL_ASSERT(i->second.extension.is()); 99 Sequence<OUString> urls(i->second.extension->getUpdateInformationURLs()); 100 if (urls.getLength()) 101 { 102 const OUString id = dp_misc::getIdentifier(i->second.extension); 103 uno::Any anyError; 104 //It is unclear from the idl if there can be a null reference returned. 105 //However all valid information should be the same 106 Sequence<Reference< xml::dom::XElement > > 107 infos(getUpdateInformation(updateInformation, urls, id, anyError)); 108 if (anyError.hasValue()) 109 out_errors.push_back(std::make_pair(i->second.extension, anyError)); 110 111 for (sal_Int32 j = 0; j < infos.getLength(); ++j) 112 { 113 dp_misc::DescriptionInfoset infoset( 114 xContext, 115 Reference< xml::dom::XNode >(infos[j], UNO_QUERY_THROW)); 116 if (!infoset.hasDescription()) 117 continue; 118 boost::optional< OUString > id2(infoset.getIdentifier()); 119 if (!id2) 120 continue; 121 OSL_ASSERT(*id2 == id); 122 if (*id2 == id) 123 { 124 i->second.version = infoset.getVersion(); 125 i->second.info = Reference< xml::dom::XNode >( 126 infos[j], UNO_QUERY_THROW); 127 } 128 break; 129 } 130 } 131 else 132 { 133 allHaveOwnUpdateInformation &= false; 134 } 135 } 136 out_allFound = allHaveOwnUpdateInformation; 137 } 138 139 void getDefaultUpdateInfos( 140 Reference<uno::XComponentContext> const & xContext, 141 Reference<deployment::XUpdateInformationProvider > const & updateInformation, 142 UpdateInfoMap& inout_map, 143 std::vector<std::pair<Reference<deployment::XPackage>, uno::Any> > & out_errors) 144 { 145 const rtl::OUString sDefaultURL(dp_misc::getExtensionDefaultUpdateURL()); 146 OSL_ASSERT(sDefaultURL.getLength()); 147 148 Any anyError; 149 Sequence< Reference< xml::dom::XElement > > 150 infos( 151 getUpdateInformation( 152 updateInformation, 153 Sequence< OUString >(&sDefaultURL, 1), OUString(), anyError)); 154 if (anyError.hasValue()) 155 out_errors.push_back(std::make_pair(Reference<deployment::XPackage>(), anyError)); 156 for (sal_Int32 i = 0; i < infos.getLength(); ++i) 157 { 158 Reference< xml::dom::XNode > node(infos[i], UNO_QUERY_THROW); 159 dp_misc::DescriptionInfoset infoset(xContext, node); 160 boost::optional< OUString > id(infoset.getIdentifier()); 161 if (!id) { 162 continue; 163 } 164 UpdateInfoMap::iterator j = inout_map.find(*id); 165 if (j != inout_map.end()) 166 { 167 //skip those extension which provide its own update urls 168 if (j->second.extension->getUpdateInformationURLs().getLength()) 169 continue; 170 OUString v(infoset.getVersion()); 171 //look for the highest version in the online repository 172 if (dp_misc::compareVersions(v, j->second.version) == 173 dp_misc::GREATER) 174 { 175 j->second.version = v; 176 j->second.info = node; 177 } 178 } 179 } 180 } 181 182 bool containsBundledOnly(Sequence<Reference<deployment::XPackage> > const & sameIdExtensions) 183 { 184 OSL_ASSERT(sameIdExtensions.getLength() == 3); 185 if (!sameIdExtensions[0].is() && !sameIdExtensions[1].is() && sameIdExtensions[2].is()) 186 return true; 187 else 188 return false; 189 } 190 /** Returns true if the list of extensions are bundled extensions and there are no 191 other extensions with the same identifier in the shared or user repository. 192 If extensionList is NULL, then it is checked if there are only bundled extensions. 193 */ 194 bool onlyBundledExtensions( 195 Reference<deployment::XExtensionManager> const & xExtMgr, 196 std::vector< Reference<deployment::XPackage > > const * extensionList) 197 { 198 OSL_ASSERT(xExtMgr.is()); 199 bool onlyBundled = true; 200 if (extensionList) 201 { 202 typedef std::vector<Reference<deployment::XPackage > >::const_iterator CIT; 203 for (CIT i = extensionList->begin(); i != extensionList->end(); i++) 204 { 205 Sequence<Reference<deployment::XPackage> > seqExt = xExtMgr->getExtensionsWithSameIdentifier( 206 dp_misc::getIdentifier(*i), (*i)->getName(), Reference<ucb::XCommandEnvironment>()); 207 208 if (!containsBundledOnly(seqExt)) 209 { 210 onlyBundled = false; 211 break; 212 } 213 214 } 215 } 216 else 217 { 218 const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = 219 xExtMgr->getAllExtensions(Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>()); 220 221 for (int pos = seqAllExt.getLength(); pos --; ) 222 { 223 if (!containsBundledOnly(seqAllExt[pos])) 224 { 225 onlyBundled = false; 226 break; 227 } 228 } 229 } 230 return onlyBundled; 231 } 232 233 } // anon namespace 234 235 236 OUString getExtensionDefaultUpdateURL() 237 { 238 ::rtl::OUString sUrl( 239 RTL_CONSTASCII_USTRINGPARAM( 240 "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version") 241 ":Version:ExtensionUpdateURL}")); 242 ::rtl::Bootstrap::expandMacros(sUrl); 243 return sUrl; 244 } 245 246 /* returns the index of the greatest version, starting with 0 247 248 */ 249 UPDATE_SOURCE isUpdateUserExtension( 250 bool bReadOnlyShared, 251 ::rtl::OUString const & userVersion, 252 ::rtl::OUString const & sharedVersion, 253 ::rtl::OUString const & bundledVersion, 254 ::rtl::OUString const & onlineVersion) 255 { 256 UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE; 257 if (bReadOnlyShared) 258 { 259 if (userVersion.getLength()) 260 { 261 int index = determineHighestVersion( 262 userVersion, sharedVersion, bundledVersion, onlineVersion); 263 if (index == 1) 264 retVal = UPDATE_SOURCE_SHARED; 265 else if (index == 2) 266 retVal = UPDATE_SOURCE_BUNDLED; 267 else if (index == 3) 268 retVal = UPDATE_SOURCE_ONLINE; 269 } 270 else if (sharedVersion.getLength()) 271 { 272 int index = determineHighestVersion( 273 OUString(), sharedVersion, bundledVersion, onlineVersion); 274 if (index == 2) 275 retVal = UPDATE_SOURCE_BUNDLED; 276 else if (index == 3) 277 retVal = UPDATE_SOURCE_ONLINE; 278 279 } 280 //No update for bundled extensions, they are updated only by the setup 281 //else if (bundledVersion.getLength()) 282 //{ 283 // int index = determineHighestVersion( 284 // OUString(), OUString(), bundledVersion, onlineVersion); 285 // if (index == 3) 286 // retVal = UPDATE_SOURCE_ONLINE; 287 //} 288 } 289 else 290 { 291 if (userVersion.getLength()) 292 { 293 int index = determineHighestVersion( 294 userVersion, sharedVersion, bundledVersion, onlineVersion); 295 if (index == 1) 296 retVal = UPDATE_SOURCE_SHARED; 297 else if (index == 2) 298 retVal = UPDATE_SOURCE_BUNDLED; 299 else if (index == 3) 300 retVal = UPDATE_SOURCE_ONLINE; 301 } 302 } 303 304 return retVal; 305 } 306 307 UPDATE_SOURCE isUpdateSharedExtension( 308 bool bReadOnlyShared, 309 ::rtl::OUString const & sharedVersion, 310 ::rtl::OUString const & bundledVersion, 311 ::rtl::OUString const & onlineVersion) 312 { 313 if (bReadOnlyShared) 314 return UPDATE_SOURCE_NONE; 315 UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE; 316 317 if (sharedVersion.getLength()) 318 { 319 int index = determineHighestVersion( 320 OUString(), sharedVersion, bundledVersion, onlineVersion); 321 if (index == 2) 322 retVal = UPDATE_SOURCE_BUNDLED; 323 else if (index == 3) 324 retVal = UPDATE_SOURCE_ONLINE; 325 } 326 //No update for bundled extensions, they are updated only by the setup 327 //else if (bundledVersion.getLength()) 328 //{ 329 // int index = determineHighestVersion( 330 // OUString(), OUString(), bundledVersion, onlineVersion); 331 // if (index == 3) 332 // retVal = UPDATE_SOURCE_ONLINE; 333 //} 334 return retVal; 335 } 336 337 Reference<deployment::XPackage> 338 getExtensionWithHighestVersion( 339 Sequence<Reference<deployment::XPackage> > const & seqExt) 340 { 341 if (seqExt.getLength() == 0) 342 return Reference<deployment::XPackage>(); 343 344 Reference<deployment::XPackage> greatest; 345 sal_Int32 len = seqExt.getLength(); 346 347 for (sal_Int32 i = 0; i < len; i++) 348 { 349 if (!greatest.is()) 350 { 351 greatest = seqExt[i]; 352 continue; 353 } 354 Reference<deployment::XPackage> const & current = seqExt[i]; 355 //greatest has a value 356 if (! current.is()) 357 continue; 358 359 if (dp_misc::compareVersions(current->getVersion(), greatest->getVersion()) == dp_misc::GREATER) 360 greatest = current; 361 } 362 return greatest; 363 } 364 365 UpdateInfo::UpdateInfo( Reference< deployment::XPackage> const & ext): 366 extension(ext) 367 { 368 } 369 370 371 372 UpdateInfoMap getOnlineUpdateInfos( 373 Reference<uno::XComponentContext> const &xContext, 374 Reference<deployment::XExtensionManager> const & xExtMgr, 375 Reference<deployment::XUpdateInformationProvider > const & updateInformation, 376 std::vector<Reference<deployment::XPackage > > const * extensionList, 377 std::vector<std::pair< Reference<deployment::XPackage>, uno::Any> > & out_errors) 378 { 379 OSL_ASSERT(xExtMgr.is()); 380 UpdateInfoMap infoMap; 381 if (!xExtMgr.is() || onlyBundledExtensions(xExtMgr, extensionList)) 382 return infoMap; 383 384 if (!extensionList) 385 { 386 const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = xExtMgr->getAllExtensions( 387 Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>()); 388 389 //fill the UpdateInfoMap. key = extension identifier, value = UpdateInfo 390 for (int pos = seqAllExt.getLength(); pos --; ) 391 { 392 uno::Sequence<Reference<deployment::XPackage> > const & seqExt = seqAllExt[pos]; 393 394 Reference<deployment::XPackage> extension = getExtensionWithHighestVersion(seqExt); 395 OSL_ASSERT(extension.is()); 396 397 std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.insert( 398 UpdateInfoMap::value_type( 399 dp_misc::getIdentifier(extension), UpdateInfo(extension))); 400 OSL_ASSERT(insertRet.second == true); 401 } 402 } 403 else 404 { 405 typedef std::vector<Reference<deployment::XPackage > >::const_iterator CIT; 406 for (CIT i = extensionList->begin(); i != extensionList->end(); i++) 407 { 408 OSL_ASSERT(i->is()); 409 std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.insert( 410 UpdateInfoMap::value_type( 411 dp_misc::getIdentifier(*i), UpdateInfo(*i))); 412 OSL_ASSERT(insertRet.second == true); 413 } 414 } 415 416 //Now find the update information for the extensions which provide their own 417 //URLs to update information. 418 bool allInfosObtained = false; 419 getOwnUpdateInfos(xContext, updateInformation, infoMap, out_errors, allInfosObtained); 420 421 if (!allInfosObtained) 422 getDefaultUpdateInfos(xContext, updateInformation, infoMap, out_errors); 423 return infoMap; 424 } 425 OUString getHighestVersion( 426 ::rtl::OUString const & userVersion, 427 ::rtl::OUString const & sharedVersion, 428 ::rtl::OUString const & bundledVersion, 429 ::rtl::OUString const & onlineVersion) 430 { 431 int index = determineHighestVersion(userVersion, sharedVersion, bundledVersion, onlineVersion); 432 switch (index) 433 { 434 case 0: return userVersion; 435 case 1: return sharedVersion; 436 case 2: return bundledVersion; 437 case 3: return onlineVersion; 438 default: OSL_ASSERT(0); 439 } 440 441 return OUString(); 442 } 443 } //namespace dp_misc 444