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