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 #include "dp_ucb.h" 32 #include "dp_resource.h" 33 #include "dp_platform.hxx" 34 #include "dp_manager.h" 35 #include "dp_identifier.hxx" 36 #include "rtl/ustrbuf.hxx" 37 #include "rtl/string.hxx" 38 #include "rtl/uri.hxx" 39 #include "rtl/bootstrap.hxx" 40 #include "osl/diagnose.h" 41 #include "osl/file.hxx" 42 #include "osl/security.hxx" 43 #include "cppuhelper/weakref.hxx" 44 #include "cppuhelper/exc_hlp.hxx" 45 #include "cppuhelper/implbase1.hxx" 46 #include "cppuhelper/interfacecontainer.hxx" 47 #include "comphelper/servicedecl.hxx" 48 #include "comphelper/sequence.hxx" 49 #include "xmlscript/xml_helper.hxx" 50 #include "svl/inettype.hxx" 51 #include "com/sun/star/lang/DisposedException.hpp" 52 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" 53 #include "com/sun/star/beans/UnknownPropertyException.hpp" 54 #include "com/sun/star/util/XUpdatable.hpp" 55 #include "com/sun/star/sdbc/XResultSet.hpp" 56 #include "com/sun/star/sdbc/XRow.hpp" 57 #include "com/sun/star/ucb/XContentAccess.hpp" 58 #include "com/sun/star/ucb/NameClash.hpp" 59 #include "com/sun/star/deployment/VersionException.hpp" 60 #include "com/sun/star/deployment/InstallException.hpp" 61 #include "com/sun/star/deployment/Prerequisites.hpp" 62 #include "com/sun/star/task/XInteractionApprove.hpp" 63 #include "com/sun/star/ucb/UnsupportedCommandException.hpp" 64 #include "boost/bind.hpp" 65 #include "tools/urlobj.hxx" 66 #include "unotools/tempfile.hxx" 67 68 #include "osl/file.hxx" 69 #include <vector> 70 #include <list> 71 #include "dp_descriptioninfoset.hxx" 72 #include "dp_commandenvironments.hxx" 73 #include "dp_properties.hxx" 74 75 using namespace ::dp_misc; 76 using namespace ::com::sun::star; 77 using namespace ::com::sun::star::uno; 78 using namespace ::com::sun::star::ucb; 79 using ::rtl::OUString; 80 81 namespace dp_log { 82 extern comphelper::service_decl::ServiceDecl const serviceDecl; 83 } 84 85 namespace dp_registry { 86 Reference<deployment::XPackageRegistry> create( 87 OUString const & context, 88 OUString const & cachePath, bool readOnly, 89 Reference<XComponentContext> const & xComponentContext ); 90 } 91 92 namespace dp_manager { 93 94 struct MatchTempDir 95 { 96 OUString m_str; 97 MatchTempDir( OUString const & str ) : m_str( str ) {} 98 bool operator () ( ActivePackages::Entries::value_type const & v ) const { 99 return v.second.temporaryName.equalsIgnoreAsciiCase( m_str ); 100 } 101 }; 102 103 104 namespace { 105 OUString getExtensionFolder(OUString const & parentFolder, 106 Reference<ucb::XCommandEnvironment> const & xCmdEnv) 107 { 108 ::ucbhelper::Content tempFolder( 109 parentFolder, xCmdEnv ); 110 Reference<sdbc::XResultSet> xResultSet( 111 tempFolder.createCursor( 112 Sequence<OUString>( &StrTitle::get(), 1 ), 113 ::ucbhelper::INCLUDE_FOLDERS_ONLY ) ); 114 115 OUString title; 116 while (xResultSet->next()) 117 { 118 title = Reference<sdbc::XRow>( 119 xResultSet, UNO_QUERY_THROW )->getString(1 /* Title */ ) ; 120 break; 121 } 122 return title; 123 } 124 } 125 //______________________________________________________________________________ 126 void PackageManagerImpl::initActivationLayer( 127 Reference<XCommandEnvironment> const & xCmdEnv ) 128 { 129 if (m_activePackages.getLength() == 0) 130 { 131 OSL_ASSERT( m_registryCache.getLength() == 0 ); 132 // documents temp activation: 133 m_activePackagesDB.reset( new ActivePackages ); 134 ::ucbhelper::Content ucbContent; 135 if (create_ucb_content( &ucbContent, m_context, xCmdEnv, 136 false /* no throw */ )) 137 { 138 // scan for all entries in m_packagesDir: 139 Reference<sdbc::XResultSet> xResultSet( 140 ucbContent.createCursor( 141 Sequence<OUString>( &StrTitle::get(), 1 ), 142 ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) ); 143 while (xResultSet->next()) 144 { 145 Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW ); 146 OUString title( xRow->getString( 1 /* Title */ ) ); 147 // xxx todo: remove workaround for tdoc 148 if (title.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( 149 "this_is_a_dummy_stream_just_there_" 150 "as_a_workaround_for_a_" 151 "temporary_limitation_of_the_" 152 "storage_api_implementation") )) 153 continue; 154 if (title.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( 155 "META-INF") ) ) 156 continue; 157 158 ::ucbhelper::Content sourceContent( 159 Reference<XContentAccess>( 160 xResultSet, UNO_QUERY_THROW )->queryContent(), 161 xCmdEnv ); 162 163 OUString mediaType( detectMediaType( sourceContent, 164 false /* no throw */) ); 165 if (mediaType.getLength() >0) 166 { 167 ActivePackages::Data dbData; 168 insertToActivationLayer( 169 Sequence<css::beans::NamedValue>(),mediaType, sourceContent, 170 title, &dbData ); 171 172 insertToActivationLayerDB( title, dbData ); 173 //TODO #i73136#: insertToActivationLayerDB needs id not 174 // title, but the whole m_activePackages.getLength()==0 175 // case (i.e., document-relative deployment) currently 176 // does not work, anyway. 177 } 178 } 179 } 180 } 181 else 182 { 183 // user|share: 184 OSL_ASSERT( m_activePackages.getLength() > 0 ); 185 m_activePackages_expanded = expandUnoRcUrl( m_activePackages ); 186 m_registrationData_expanded = expandUnoRcUrl(m_registrationData); 187 if (!m_readOnly) 188 create_folder( 0, m_activePackages_expanded, xCmdEnv, true); 189 190 OUString dbName; 191 if (m_context.equals(OUSTR("user"))) 192 dbName = m_activePackages_expanded + OUSTR(".db"); 193 else 194 { 195 //Create the extension data base in the user installation 196 create_folder( 0, m_registrationData_expanded, xCmdEnv, true); 197 dbName = m_registrationData_expanded + OUSTR("/extensions.db"); 198 } 199 //The data base can always be written because it it always in the user installation 200 m_activePackagesDB.reset( 201 new ActivePackages( dbName, false ) ); 202 203 if (! m_readOnly && ! m_context.equals(OUSTR("bundled"))) 204 { 205 // clean up activation layer, scan for zombie temp dirs: 206 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 207 208 ::ucbhelper::Content tempFolder( 209 m_activePackages_expanded, xCmdEnv ); 210 Reference<sdbc::XResultSet> xResultSet( 211 tempFolder.createCursor( 212 Sequence<OUString>( &StrTitle::get(), 1 ), 213 ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) ); 214 // get all temp directories: 215 ::std::vector<OUString> tempEntries; 216 ::std::vector<OUString> removedEntries; 217 while (xResultSet->next()) 218 { 219 OUString title( 220 Reference<sdbc::XRow>( 221 xResultSet, UNO_QUERY_THROW )->getString( 222 1 /* Title */ ) ); 223 224 const char extensionRemoved[] = "removed"; 225 if (title.endsWithAsciiL( 226 extensionRemoved, sizeof(extensionRemoved) - 1)) 227 { 228 //save the file name withouth the "removed" part 229 sal_Int32 index = title.lastIndexOfAsciiL( 230 extensionRemoved, sizeof(extensionRemoved) - 1); 231 OUString remFile = title.copy(0, index); 232 removedEntries.push_back(::rtl::Uri::encode( 233 remFile, rtl_UriCharClassPchar, 234 rtl_UriEncodeIgnoreEscapes, 235 RTL_TEXTENCODING_UTF8 ) ); 236 } 237 else 238 { 239 tempEntries.push_back( ::rtl::Uri::encode( 240 title, rtl_UriCharClassPchar, 241 rtl_UriEncodeIgnoreEscapes, 242 RTL_TEXTENCODING_UTF8 ) ); 243 } 244 } 245 246 bool bShared = m_context.equals(OUSTR("shared")) ? true : false; 247 for ( ::std::size_t pos = 0; pos < tempEntries.size(); ++pos ) 248 { 249 OUString const & tempEntry = tempEntries[ pos ]; 250 const MatchTempDir match( tempEntry ); 251 if (::std::find_if( id2temp.begin(), id2temp.end(), match ) == 252 id2temp.end()) 253 { 254 const OUString url( 255 makeURL(m_activePackages_expanded, tempEntry ) ); 256 257 //In case of shared extensions, new entries are regarded as 258 //added extensions if there is no xxx.tmpremoved file. 259 if (bShared) 260 { 261 if (::std::find(removedEntries.begin(), removedEntries.end(), tempEntry) == 262 removedEntries.end()) 263 { 264 continue; 265 } 266 else 267 { 268 //Make sure only the same user removes the extension, who 269 //previously unregistered it. This is avoid races if multiple instances 270 //of OOo are running which all have write access to the shared installation. 271 //For example, a user removes the extension, but keeps OOo 272 //running. Parts of the extension may still be loaded and used by OOo. 273 //Therefore the extension is only deleted the next time the extension manager is 274 //run after restarting OOo. While OOo is still running, another user starts OOo 275 //which would deleted the extension files. If the same user starts another 276 //instance of OOo then the lock file will prevent this. 277 OUString aUserName; 278 ::osl::Security aSecurity; 279 aSecurity.getUserName( aUserName ); 280 ucbhelper::Content remFileContent( 281 url + OUSTR("removed"), Reference<XCommandEnvironment>()); 282 ::rtl::ByteSequence data = dp_misc::readFile(remFileContent); 283 ::rtl::OString osData(reinterpret_cast<const sal_Char*>(data.getConstArray()), 284 data.getLength()); 285 OUString sData = ::rtl::OStringToOUString( 286 osData, RTL_TEXTENCODING_UTF8); 287 if (!sData.equals(aUserName)) 288 continue; 289 } 290 } 291 // temp entry not needed anymore: 292 erase_path( url + OUSTR("_"), 293 Reference<XCommandEnvironment>(), 294 false /* no throw: ignore errors */ ); 295 erase_path( url, Reference<XCommandEnvironment>(), 296 false /* no throw: ignore errors */ ); 297 //delete the xxx.tmpremoved file 298 erase_path(url + OUSTR("removed"), 299 Reference<XCommandEnvironment>(), false); 300 } 301 } 302 } 303 } 304 } 305 306 //______________________________________________________________________________ 307 void PackageManagerImpl::initRegistryBackends() 308 { 309 if (m_registryCache.getLength() > 0) 310 create_folder( 0, m_registryCache, 311 Reference<XCommandEnvironment>(), false); 312 m_xRegistry.set( ::dp_registry::create( 313 m_context, m_registryCache, false, 314 m_xComponentContext ) ); 315 } 316 317 //______________________________________________________________________________ 318 Reference<deployment::XPackageManager> PackageManagerImpl::create( 319 Reference<XComponentContext> const & xComponentContext, 320 OUString const & context ) 321 { 322 PackageManagerImpl * that = new PackageManagerImpl( 323 xComponentContext, context ); 324 Reference<deployment::XPackageManager> xPackageManager( that ); 325 326 OUString packages, logFile, stampURL; 327 if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("user") )) { 328 that->m_activePackages = OUSTR( 329 "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages"); 330 that->m_registrationData = OUSTR( 331 "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE"); 332 that->m_registryCache = OUSTR( 333 "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/registry"); 334 logFile = OUSTR( 335 "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/log.txt"); 336 //We use the extension .sys for the file because on Windows Vista a sys 337 //(as well as exe and dll) file 338 //will not be written in the VirtualStore. For example if the process has no 339 //admin right once cannot write to the %programfiles% folder. However, when 340 //virtualization is used, the file will be written into the VirtualStore and 341 //it appears as if one could write to %programfiles%. When we test for write 342 //access to the office/shared folder for shared extensions then this typically 343 //fails because a normal user typically cannot write to this folder. However, 344 //using virtualization it appears that he/she can. Then a shared extension can 345 //be installed but is only visible for the user (because the extension is in 346 //the virtual store). 347 stampURL = OUSTR( 348 "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/stamp.sys"); 349 } 350 else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("shared") )) { 351 that->m_activePackages = OUSTR( 352 "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages"); 353 that->m_registrationData = OUSTR( 354 "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER"); 355 that->m_registryCache = OUSTR( 356 "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/registry"); 357 logFile = OUSTR( 358 "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/log.txt"); 359 stampURL = OUSTR( 360 "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/stamp.sys"); 361 } 362 else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bundled") )) { 363 that->m_activePackages = OUSTR( 364 "vnd.sun.star.expand:$BUNDLED_EXTENSIONS"); 365 that->m_registrationData = OUSTR( 366 "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER"); 367 that->m_registryCache = OUSTR( 368 "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/registry"); 369 logFile = OUSTR( 370 "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/log.txt"); 371 //No stamp file. We assume that bundled is always readonly. It must not be 372 //modified from ExtensionManager but only by the installer 373 } 374 else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bundled_prereg") )) { 375 //This is a bundled repository but the registration data 376 //is in the brand layer: share/prereg 377 //It is special because the registration data are copied at the first startup 378 //into the user installation. The processed help and xcu files are not 379 //copied. Instead the backenddb.xml for the help backend references the help 380 //by using $BUNDLED_EXTENSION_PREREG instead $BUNDLED_EXTENSIONS_USER. The 381 //configmgr.ini also used $BUNDLED_EXTENSIONS_PREREG to refer to the xcu file 382 //which contain the replacement for %origin%. 383 that->m_activePackages = OUSTR( 384 "vnd.sun.star.expand:$BUNDLED_EXTENSIONS"); 385 that->m_registrationData = OUSTR( 386 "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_PREREG"); 387 that->m_registryCache = OUSTR( 388 "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_PREREG/registry"); 389 logFile = OUSTR( 390 "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_PREREG/log.txt"); 391 } 392 else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("tmp") )) { 393 that->m_activePackages = OUSTR( 394 "vnd.sun.star.expand:$TMP_EXTENSIONS/extensions"); 395 that->m_registrationData = OUSTR( 396 "vnd.sun.star.expand:$TMP_EXTENSIONS"); 397 that->m_registryCache = OUSTR( 398 "vnd.sun.star.expand:$TMP_EXTENSIONS/registry"); 399 stampURL = OUSTR( 400 "vnd.sun.star.expand:$TMP_EXTENSIONS/stamp.sys"); 401 } 402 else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bak") )) { 403 that->m_activePackages = OUSTR( 404 "vnd.sun.star.expand:$BAK_EXTENSIONS/extensions"); 405 that->m_registrationData = OUSTR( 406 "vnd.sun.star.expand:$BAK_EXTENSIONS"); 407 that->m_registryCache = OUSTR( 408 "vnd.sun.star.expand:$BAK_EXTENSIONS/registry"); 409 stampURL = OUSTR( 410 "vnd.sun.star.expand:$BAK_EXTENSIONS/stamp.sys"); 411 } 412 413 else if (! context.matchAsciiL( 414 RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:/") )) { 415 throw lang::IllegalArgumentException( 416 OUSTR("invalid context given: ") + context, 417 Reference<XInterface>(), static_cast<sal_Int16>(-1) ); 418 } 419 420 Reference<XCommandEnvironment> xCmdEnv; 421 422 try { 423 //There is no stampURL for the bundled folder 424 if (stampURL.getLength() > 0) 425 { 426 #define CURRENT_STAMP "1" 427 try { 428 //The osl file API does not allow to find out if one can write 429 //into a folder. Therefore we try to write a file. Then we delete 430 //it, so that it does not hinder uninstallation of OOo 431 // probe writing: 432 ::ucbhelper::Content ucbStamp( stampURL, xCmdEnv ); 433 ::rtl::OString stamp( 434 RTL_CONSTASCII_STRINGPARAM(CURRENT_STAMP) ); 435 Reference<io::XInputStream> xData( 436 ::xmlscript::createInputStream( 437 ::rtl::ByteSequence( 438 reinterpret_cast<sal_Int8 const *>(stamp.getStr()), 439 stamp.getLength() ) ) ); 440 ucbStamp.writeStream( xData, true /* replace existing */ ); 441 that->m_readOnly = false; 442 erase_path( stampURL, xCmdEnv ); 443 } 444 catch (RuntimeException &) { 445 try { 446 erase_path( stampURL, xCmdEnv ); 447 } catch (...) 448 { 449 } 450 throw; 451 } 452 catch (Exception &) { 453 that->m_readOnly = true; 454 } 455 } 456 457 if (!that->m_readOnly && logFile.getLength() > 0) 458 { 459 const Any any_logFile(logFile); 460 that->m_xLogFile.set( 461 that->m_xComponentContext->getServiceManager() 462 ->createInstanceWithArgumentsAndContext( 463 dp_log::serviceDecl.getSupportedServiceNames()[0], 464 Sequence<Any>( &any_logFile, 1 ), 465 that->m_xComponentContext ), 466 UNO_QUERY_THROW ); 467 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv, that->m_xLogFile ) ); 468 } 469 470 that->initRegistryBackends(); 471 that->initActivationLayer( xCmdEnv ); 472 473 return xPackageManager; 474 475 } 476 catch (RuntimeException &) { 477 throw; 478 } 479 catch (Exception &) { 480 Any exc( ::cppu::getCaughtException() ); 481 ::rtl::OUStringBuffer buf; 482 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[context=\"") ); 483 buf.append( context ); 484 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( 485 "\"] caught unexpected exception!") ); 486 throw lang::WrappedTargetRuntimeException( 487 buf.makeStringAndClear(), Reference<XInterface>(), exc ); 488 } 489 } 490 491 //______________________________________________________________________________ 492 PackageManagerImpl::~PackageManagerImpl() 493 { 494 } 495 496 //______________________________________________________________________________ 497 void PackageManagerImpl::fireModified() 498 { 499 ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer( 500 util::XModifyListener::static_type() ); 501 if (pContainer != 0) { 502 pContainer->forEach<util::XModifyListener>( 503 boost::bind(&util::XModifyListener::modified, _1, 504 lang::EventObject(static_cast<OWeakObject *>(this))) ); 505 } 506 } 507 508 //______________________________________________________________________________ 509 void PackageManagerImpl::disposing() 510 { 511 try { 512 // // xxx todo: guarding? 513 // ::osl::MutexGuard guard( getMutex() ); 514 try_dispose( m_xLogFile ); 515 m_xLogFile.clear(); 516 try_dispose( m_xRegistry ); 517 m_xRegistry.clear(); 518 m_activePackagesDB.reset(0); 519 m_xComponentContext.clear(); 520 521 t_pm_helper::disposing(); 522 523 } 524 catch (RuntimeException &) { 525 throw; 526 } 527 catch (Exception &) { 528 Any exc( ::cppu::getCaughtException() ); 529 throw lang::WrappedTargetRuntimeException( 530 OUSTR("caught unexpected exception while disposing..."), 531 static_cast<OWeakObject *>(this), exc ); 532 } 533 } 534 535 // XComponent 536 //______________________________________________________________________________ 537 void PackageManagerImpl::dispose() throw (RuntimeException) 538 { 539 check(); 540 WeakComponentImplHelperBase::dispose(); 541 } 542 543 //______________________________________________________________________________ 544 void PackageManagerImpl::addEventListener( 545 Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) 546 { 547 check(); 548 WeakComponentImplHelperBase::addEventListener( xListener ); 549 } 550 551 //______________________________________________________________________________ 552 void PackageManagerImpl::removeEventListener( 553 Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) 554 { 555 check(); 556 WeakComponentImplHelperBase::removeEventListener( xListener ); 557 } 558 559 // XPackageManager 560 //______________________________________________________________________________ 561 OUString PackageManagerImpl::getContext() throw (RuntimeException) 562 { 563 check(); 564 return m_context; 565 } 566 567 //______________________________________________________________________________ 568 Sequence< Reference<deployment::XPackageTypeInfo> > 569 PackageManagerImpl::getSupportedPackageTypes() throw (RuntimeException) 570 { 571 OSL_ASSERT( m_xRegistry.is() ); 572 return m_xRegistry->getSupportedPackageTypes(); 573 } 574 575 //______________________________________________________________________________ 576 Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel() 577 throw (RuntimeException) 578 { 579 check(); 580 return new AbortChannel; 581 } 582 583 // XModifyBroadcaster 584 //______________________________________________________________________________ 585 void PackageManagerImpl::addModifyListener( 586 Reference<util::XModifyListener> const & xListener ) 587 throw (RuntimeException) 588 { 589 check(); 590 rBHelper.addListener( ::getCppuType( &xListener ), xListener ); 591 } 592 593 //______________________________________________________________________________ 594 void PackageManagerImpl::removeModifyListener( 595 Reference<util::XModifyListener> const & xListener ) 596 throw (RuntimeException) 597 { 598 check(); 599 rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); 600 } 601 602 //______________________________________________________________________________ 603 OUString PackageManagerImpl::detectMediaType( 604 ::ucbhelper::Content const & ucbContent_, bool throw_exc ) 605 { 606 ::ucbhelper::Content ucbContent(ucbContent_); 607 OUString url( ucbContent.getURL() ); 608 OUString mediaType; 609 if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:") ) || 610 url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.pkg:") )) 611 { 612 try { 613 ucbContent.getPropertyValue( OUSTR("MediaType") ) >>= mediaType; 614 } 615 catch (beans::UnknownPropertyException &) { 616 } 617 OSL_ENSURE( mediaType.getLength() > 0, "### no media-type?!" ); 618 } 619 if (mediaType.getLength() == 0) 620 { 621 try { 622 Reference<deployment::XPackage> xPackage( 623 m_xRegistry->bindPackage( 624 url, OUString(), false, OUString(), ucbContent.getCommandEnvironment() ) ); 625 const Reference<deployment::XPackageTypeInfo> xPackageType( 626 xPackage->getPackageType() ); 627 OSL_ASSERT( xPackageType.is() ); 628 if (xPackageType.is()) 629 mediaType = xPackageType->getMediaType(); 630 } 631 catch (lang::IllegalArgumentException & exc) { 632 if (throw_exc) 633 throw; 634 (void) exc; 635 OSL_ENSURE( 0, ::rtl::OUStringToOString( 636 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 637 } 638 } 639 return mediaType; 640 } 641 642 //______________________________________________________________________________ 643 OUString PackageManagerImpl::insertToActivationLayer( 644 Sequence<beans::NamedValue> const & properties, 645 OUString const & mediaType, ::ucbhelper::Content const & sourceContent_, 646 OUString const & title, ActivePackages::Data * dbData ) 647 { 648 ::ucbhelper::Content sourceContent(sourceContent_); 649 Reference<XCommandEnvironment> xCmdEnv( 650 sourceContent.getCommandEnvironment() ); 651 652 String baseDir(m_activePackages_expanded); 653 ::utl::TempFile aTemp(&baseDir, sal_False); 654 OUString tempEntry = aTemp.GetURL(); 655 tempEntry = tempEntry.copy(tempEntry.lastIndexOf('/') + 1); 656 OUString destFolder = makeURL( m_activePackages, tempEntry); 657 destFolder += OUSTR("_"); 658 659 // prepare activation folder: 660 ::ucbhelper::Content destFolderContent; 661 create_folder( &destFolderContent, destFolder, xCmdEnv ); 662 663 // copy content into activation temp dir: 664 if (mediaType.matchIgnoreAsciiCaseAsciiL( 665 RTL_CONSTASCII_STRINGPARAM( 666 "application/vnd.sun.star.package-bundle") ) || 667 // xxx todo: more sophisticated parsing 668 mediaType.matchIgnoreAsciiCaseAsciiL( 669 RTL_CONSTASCII_STRINGPARAM( 670 "application/vnd.sun.star.legacy-package-bundle") )) 671 { 672 // inflate content: 673 ::rtl::OUStringBuffer buf; 674 if (!sourceContent.isFolder()) 675 { 676 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") ); 677 buf.append( ::rtl::Uri::encode( sourceContent.getURL(), 678 rtl_UriCharClassRegName, 679 rtl_UriEncodeIgnoreEscapes, 680 RTL_TEXTENCODING_UTF8 ) ); 681 } 682 else 683 { 684 //Folder. No need to unzip, just copy 685 buf.append(sourceContent.getURL()); 686 } 687 buf.append( static_cast<sal_Unicode>('/') ); 688 sourceContent = ::ucbhelper::Content( 689 buf.makeStringAndClear(), xCmdEnv ); 690 } 691 if (! destFolderContent.transferContent( 692 sourceContent, ::ucbhelper::InsertOperation_COPY, 693 title, NameClash::OVERWRITE )) 694 throw RuntimeException( OUSTR("UCB transferContent() failed!"), 0 ); 695 696 697 // write to DB: 698 //bundled extensions should only be added by the synchronizeAddedExtensions 699 //functions. Moreover, there is no "temporary folder" for bundled extensions. 700 OSL_ASSERT(!m_context.equals(OUSTR("bundled"))); 701 OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title); 702 DescriptionInfoset info = 703 dp_misc::getDescriptionInfoset(sFolderUrl); 704 dbData->temporaryName = tempEntry; 705 dbData->fileName = title; 706 dbData->mediaType = mediaType; 707 dbData->version = info.getVersion(); 708 709 //No write the properties file next to the extension 710 ExtensionProperties props(sFolderUrl, properties, xCmdEnv); 711 props.write(); 712 return destFolder; 713 } 714 715 //______________________________________________________________________________ 716 void PackageManagerImpl::insertToActivationLayerDB( 717 OUString const & id, ActivePackages::Data const & dbData ) 718 { 719 //access to the database must be guarded. See removePackage 720 const ::osl::MutexGuard guard( getMutex() ); 721 m_activePackagesDB->put( id, dbData ); 722 } 723 724 //______________________________________________________________________________ 725 /* The function returns true if there is an extension with the same id already 726 installed which needs to be uninstalled, before the new extension can be installed. 727 */ 728 bool PackageManagerImpl::isInstalled( 729 Reference<deployment::XPackage> const & package) 730 { 731 OUString id(dp_misc::getIdentifier(package)); 732 OUString fn(package->getName()); 733 bool bInstalled = false; 734 if (m_activePackagesDB->has( id, fn )) 735 { 736 bInstalled = true; 737 } 738 return bInstalled; 739 } 740 741 // XPackageManager 742 //______________________________________________________________________________ 743 Reference<deployment::XPackage> PackageManagerImpl::importExtension( 744 Reference<deployment::XPackage> const & extension, 745 Reference<task::XAbortChannel> const & xAbortChannel, 746 Reference<XCommandEnvironment> const & xCmdEnv_ ) 747 throw (deployment::DeploymentException, CommandFailedException, 748 CommandAbortedException, lang::IllegalArgumentException, 749 RuntimeException) 750 { 751 return addPackage(extension->getURL(), Sequence<beans::NamedValue>(), 752 OUString(), xAbortChannel, xCmdEnv_); 753 } 754 755 /* The function adds an extension but does not register it!!! 756 It may not do any user interaction. This is done in XExtensionManager::addExtension 757 */ 758 Reference<deployment::XPackage> PackageManagerImpl::addPackage( 759 OUString const & url, 760 css::uno::Sequence<css::beans::NamedValue> const & properties, 761 OUString const & mediaType_, 762 Reference<task::XAbortChannel> const & xAbortChannel, 763 Reference<XCommandEnvironment> const & xCmdEnv_ ) 764 throw (deployment::DeploymentException, CommandFailedException, 765 CommandAbortedException, lang::IllegalArgumentException, 766 RuntimeException) 767 { 768 check(); 769 if (m_readOnly) 770 { 771 OUString message; 772 if (m_context == OUSTR("shared")) 773 message = OUSTR("You need write permissions to install a shared extension!"); 774 else 775 message = OUSTR("You need write permissions to install this extension!"); 776 throw deployment::DeploymentException( 777 message, static_cast<OWeakObject *>(this), Any() ); 778 } 779 Reference<XCommandEnvironment> xCmdEnv; 780 if (m_xLogFile.is()) 781 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 782 else 783 xCmdEnv.set( xCmdEnv_ ); 784 785 try { 786 ::ucbhelper::Content sourceContent; 787 create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc 788 const OUString title(sourceContent.getPropertyValue( 789 StrTitle::get() ).get<OUString>() ); 790 const OUString title_enc( ::rtl::Uri::encode( 791 title, rtl_UriCharClassPchar, 792 rtl_UriEncodeIgnoreEscapes, 793 RTL_TEXTENCODING_UTF8 ) ); 794 OUString destFolder; 795 796 OUString mediaType(mediaType_); 797 if (mediaType.getLength() == 0) 798 mediaType = detectMediaType( sourceContent ); 799 800 Reference<deployment::XPackage> xPackage; 801 // copy file: 802 progressUpdate( 803 getResourceString(RID_STR_COPYING_PACKAGE) + title, xCmdEnv ); 804 if (m_activePackages.getLength() == 0) 805 { 806 ::ucbhelper::Content docFolderContent; 807 create_folder( &docFolderContent, m_context, xCmdEnv ); 808 // copy into document, first: 809 if (! docFolderContent.transferContent( 810 sourceContent, ::ucbhelper::InsertOperation_COPY, 811 OUString(), 812 NameClash::ASK /* xxx todo: ASK not needed? */)) 813 throw RuntimeException( 814 OUSTR("UCB transferContent() failed!"), 0 ); 815 // set media-type: 816 ::ucbhelper::Content docContent( 817 makeURL( m_context, title_enc ), xCmdEnv ); 818 //TODO #i73136#: using title instead of id can lead to 819 // clashes, but the whole m_activePackages.getLength()==0 820 // case (i.e., document-relative deployment) currently does 821 // not work, anyway. 822 docContent.setPropertyValue( 823 OUSTR("MediaType"), Any(mediaType) ); 824 825 // xxx todo: obsolete in the future 826 try { 827 docFolderContent.executeCommand( OUSTR("flush"), Any() ); 828 } 829 catch (UnsupportedCommandException &) { 830 } 831 } 832 ActivePackages::Data dbData; 833 destFolder = insertToActivationLayer( 834 properties, mediaType, sourceContent, title, &dbData ); 835 836 837 // bind activation package: 838 //Because every shared/user extension will be unpacked in a folder, 839 //which was created with a unique name we will always have two different 840 //XPackage objects, even if the second extension is the same. 841 //Therefore bindPackage does not need a guard here. 842 xPackage = m_xRegistry->bindPackage( 843 makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv ); 844 845 OSL_ASSERT( xPackage.is() ); 846 if (xPackage.is()) 847 { 848 bool install = false; 849 try 850 { 851 OUString const id = dp_misc::getIdentifier( xPackage ); 852 853 ::osl::MutexGuard g(m_addMutex); 854 if (isInstalled(xPackage)) 855 { 856 //Do not guard the complete function with the getMutex 857 removePackage(id, xPackage->getName(), xAbortChannel, 858 xCmdEnv); 859 } 860 install = true; 861 insertToActivationLayerDB(id, dbData); 862 } 863 catch (...) 864 { 865 deletePackageFromCache( xPackage, destFolder ); 866 throw; 867 } 868 if (!install) 869 { 870 deletePackageFromCache( xPackage, destFolder ); 871 } 872 //ToDo: We should notify only if the extension is registered 873 fireModified(); 874 } 875 return xPackage; 876 } 877 catch (RuntimeException &) { 878 throw; 879 } 880 catch (CommandFailedException & exc) { 881 logIntern( Any(exc) ); 882 throw; 883 } 884 catch (CommandAbortedException & exc) { 885 logIntern( Any(exc) ); 886 throw; 887 } 888 catch (deployment::DeploymentException & exc) { 889 logIntern( Any(exc) ); 890 throw; 891 } 892 catch (Exception &) { 893 Any exc( ::cppu::getCaughtException() ); 894 logIntern( exc ); 895 throw deployment::DeploymentException( 896 getResourceString(RID_STR_ERROR_WHILE_ADDING) + url, 897 static_cast<OWeakObject *>(this), exc ); 898 } 899 } 900 void PackageManagerImpl::deletePackageFromCache( 901 Reference<deployment::XPackage> const & xPackage, 902 OUString const & destFolder) 903 { 904 try_dispose( xPackage ); 905 906 //we remove the package from the uno cache 907 //no service from the package may be loaded at this time!!! 908 erase_path( destFolder, Reference<XCommandEnvironment>(), 909 false /* no throw: ignore errors */ ); 910 //rm last character '_' 911 OUString url = destFolder.copy(0, destFolder.getLength() - 1); 912 erase_path( url, Reference<XCommandEnvironment>(), 913 false /* no throw: ignore errors */ ); 914 915 } 916 //______________________________________________________________________________ 917 void PackageManagerImpl::removePackage( 918 OUString const & id, ::rtl::OUString const & fileName, 919 Reference<task::XAbortChannel> const & /*xAbortChannel*/, 920 Reference<XCommandEnvironment> const & xCmdEnv_ ) 921 throw (deployment::DeploymentException, CommandFailedException, 922 CommandAbortedException, lang::IllegalArgumentException, 923 RuntimeException) 924 { 925 check(); 926 927 Reference<XCommandEnvironment> xCmdEnv; 928 if (m_xLogFile.is()) 929 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 930 else 931 xCmdEnv.set( xCmdEnv_ ); 932 933 try { 934 Reference<deployment::XPackage> xPackage; 935 { 936 const ::osl::MutexGuard guard(getMutex()); 937 //Check if this extension exist and throw an IllegalArgumentException 938 //if it does not 939 //If the files of the extension are already removed, or there is a 940 //different extension at the same place, for example after updating the 941 //extension, then the returned object is that which uses the database data. 942 xPackage = getDeployedPackage_(id, fileName, xCmdEnv ); 943 944 945 //Because the extension is only removed the next time the extension 946 //manager runs after restarting OOo, we need to indicate that a 947 //shared extension was "deleted". When a user starts OOo, then it 948 //will check if something changed in the shared repository. Based on 949 //the flag file it will then recognize, that the extension was 950 //deleted and can then update the extnesion database of the shared 951 //extensions in the user installation. 952 if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && m_context.equals(OUSTR("shared"))) 953 { 954 ActivePackages::Data val; 955 m_activePackagesDB->get( & val, id, fileName); 956 OSL_ASSERT(val.temporaryName.getLength()); 957 OUString url(makeURL(m_activePackages_expanded, 958 val.temporaryName + OUSTR("removed"))); 959 ::ucbhelper::Content contentRemoved(url, xCmdEnv ); 960 OUString aUserName; 961 ::osl::Security aSecurity; 962 aSecurity.getUserName( aUserName ); 963 964 ::rtl::OString stamp = ::rtl::OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8); 965 Reference<css::io::XInputStream> xData( 966 ::xmlscript::createInputStream( 967 ::rtl::ByteSequence( 968 reinterpret_cast<sal_Int8 const *>(stamp.getStr()), 969 stamp.getLength() ) ) ); 970 contentRemoved.writeStream( xData, true /* replace existing */ ); 971 } 972 m_activePackagesDB->erase( id, fileName ); // to be removed upon next start 973 //remove any cached data hold by the backend 974 m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType()); 975 } 976 try_dispose( xPackage ); 977 978 fireModified(); 979 } 980 catch (RuntimeException &) { 981 throw; 982 } 983 catch (lang::IllegalArgumentException &) { 984 throw; 985 } 986 catch (CommandFailedException & exc) { 987 logIntern( Any(exc) ); 988 throw; 989 } 990 catch (CommandAbortedException & exc) { 991 logIntern( Any(exc) ); 992 throw; 993 } 994 catch (deployment::DeploymentException & exc) { 995 logIntern( Any(exc) ); 996 throw; 997 } 998 catch (Exception &) { 999 Any exc( ::cppu::getCaughtException() ); 1000 logIntern( exc ); 1001 throw deployment::DeploymentException( 1002 getResourceString(RID_STR_ERROR_WHILE_REMOVING) + id, 1003 static_cast<OWeakObject *>(this), exc ); 1004 } 1005 } 1006 1007 //______________________________________________________________________________ 1008 OUString PackageManagerImpl::getDeployPath( ActivePackages::Data const & data ) 1009 { 1010 ::rtl::OUStringBuffer buf; 1011 buf.append( data.temporaryName ); 1012 //The bundled extensions are not contained in an additional folder 1013 //with a unique name. data.temporaryName contains already the 1014 //UTF8 encoded folder name. See PackageManagerImpl::synchronize 1015 if (!m_context.equals(OUSTR("bundled")) 1016 && !m_context.equals(OUSTR("bundled_prereg"))) 1017 { 1018 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("_/") ); 1019 buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar, 1020 rtl_UriEncodeIgnoreEscapes, 1021 RTL_TEXTENCODING_UTF8 ) ); 1022 } 1023 return makeURL( m_activePackages, buf.makeStringAndClear() ); 1024 } 1025 1026 //______________________________________________________________________________ 1027 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_( 1028 OUString const & id, OUString const & fileName, 1029 Reference<XCommandEnvironment> const & xCmdEnv ) 1030 { 1031 ActivePackages::Data val; 1032 if (m_activePackagesDB->get( &val, id, fileName )) 1033 { 1034 return getDeployedPackage_( id, val, xCmdEnv, false ); 1035 } 1036 throw lang::IllegalArgumentException( 1037 getResourceString(RID_STR_NO_SUCH_PACKAGE) + id, 1038 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); 1039 } 1040 1041 //______________________________________________________________________________ 1042 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_( 1043 OUString const & id, ActivePackages::Data const & data, 1044 Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms ) 1045 { 1046 if (ignoreAlienPlatforms) 1047 { 1048 String type, subType; 1049 INetContentTypeParameterList params; 1050 if (INetContentTypes::parse( data.mediaType, type, subType, ¶ms )) 1051 { 1052 INetContentTypeParameter const * param = params.find( 1053 ByteString("platform") ); 1054 if (param != 0 && !platform_fits( param->m_sValue )) 1055 throw lang::IllegalArgumentException( 1056 getResourceString(RID_STR_NO_SUCH_PACKAGE) + id, 1057 static_cast<OWeakObject *>(this), 1058 static_cast<sal_Int16>(-1) ); 1059 } 1060 } 1061 Reference<deployment::XPackage> xExtension; 1062 try 1063 { 1064 //Ignore extensions where XPackage::checkPrerequisites failed. 1065 //They must not be usable for this user. 1066 if (data.failedPrerequisites.equals(OUSTR("0"))) 1067 { 1068 xExtension = m_xRegistry->bindPackage( 1069 getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv ); 1070 } 1071 } 1072 catch (deployment::InvalidRemovedParameterException& e) 1073 { 1074 xExtension = e.Extension; 1075 } 1076 return xExtension; 1077 } 1078 1079 //______________________________________________________________________________ 1080 Sequence< Reference<deployment::XPackage> > 1081 PackageManagerImpl::getDeployedPackages_( 1082 Reference<XCommandEnvironment> const & xCmdEnv ) 1083 { 1084 ::std::vector< Reference<deployment::XPackage> > packages; 1085 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 1086 ActivePackages::Entries::const_iterator iPos( id2temp.begin() ); 1087 ActivePackages::Entries::const_iterator const iEnd( id2temp.end() ); 1088 for ( ; iPos != iEnd; ++iPos ) 1089 { 1090 if (! iPos->second.failedPrerequisites.equals(OUSTR("0"))) 1091 continue; 1092 try { 1093 packages.push_back( 1094 getDeployedPackage_( 1095 iPos->first, iPos->second, xCmdEnv, 1096 true /* xxx todo: think of GUI: 1097 ignore other platforms than the current one */ ) ); 1098 } 1099 catch (lang::IllegalArgumentException & exc) { 1100 // ignore 1101 (void) exc; // avoid warnings 1102 OSL_ENSURE( 0, ::rtl::OUStringToOString( 1103 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 1104 } 1105 catch (deployment::DeploymentException& exc) { 1106 // ignore 1107 (void) exc; // avoid warnings 1108 OSL_ENSURE( 0, ::rtl::OUStringToOString( 1109 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 1110 } 1111 } 1112 return comphelper::containerToSequence(packages); 1113 } 1114 1115 //______________________________________________________________________________ 1116 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage( 1117 OUString const & id, ::rtl::OUString const & fileName, 1118 Reference<XCommandEnvironment> const & xCmdEnv_ ) 1119 throw (deployment::DeploymentException, CommandFailedException, 1120 lang::IllegalArgumentException, RuntimeException) 1121 { 1122 check(); 1123 Reference<XCommandEnvironment> xCmdEnv; 1124 if (m_xLogFile.is()) 1125 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 1126 else 1127 xCmdEnv.set( xCmdEnv_ ); 1128 1129 try { 1130 const ::osl::MutexGuard guard( getMutex() ); 1131 return getDeployedPackage_( id, fileName, xCmdEnv ); 1132 } 1133 catch (RuntimeException &) { 1134 throw; 1135 } 1136 catch (CommandFailedException & exc) { 1137 logIntern( Any(exc) ); 1138 throw; 1139 } 1140 catch (lang::IllegalArgumentException & exc) { 1141 logIntern( Any(exc) ); 1142 throw; 1143 } 1144 catch (deployment::DeploymentException & exc) { 1145 logIntern( Any(exc) ); 1146 throw; 1147 } 1148 catch (Exception &) { 1149 Any exc( ::cppu::getCaughtException() ); 1150 logIntern( exc ); 1151 throw deployment::DeploymentException( 1152 // ought never occur... 1153 OUSTR("error while accessing deployed package: ") + id, 1154 static_cast<OWeakObject *>(this), exc ); 1155 } 1156 } 1157 1158 //______________________________________________________________________________ 1159 Sequence< Reference<deployment::XPackage> > 1160 PackageManagerImpl::getDeployedPackages( 1161 Reference<task::XAbortChannel> const &, 1162 Reference<XCommandEnvironment> const & xCmdEnv_ ) 1163 throw (deployment::DeploymentException, CommandFailedException, 1164 CommandAbortedException, lang::IllegalArgumentException, 1165 RuntimeException) 1166 { 1167 check(); 1168 Reference<XCommandEnvironment> xCmdEnv; 1169 if (m_xLogFile.is()) 1170 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 1171 else 1172 xCmdEnv.set( xCmdEnv_ ); 1173 1174 try { 1175 const ::osl::MutexGuard guard( getMutex() ); 1176 return getDeployedPackages_( xCmdEnv ); 1177 } 1178 catch (RuntimeException &) { 1179 throw; 1180 } 1181 catch (CommandFailedException & exc) { 1182 logIntern( Any(exc) ); 1183 throw; 1184 } 1185 catch (CommandAbortedException & exc) { 1186 logIntern( Any(exc) ); 1187 throw; 1188 } 1189 catch (deployment::DeploymentException & exc) { 1190 logIntern( Any(exc) ); 1191 throw; 1192 } 1193 catch (Exception &) { 1194 Any exc( ::cppu::getCaughtException() ); 1195 logIntern( exc ); 1196 throw deployment::DeploymentException( 1197 // ought never occur... 1198 OUSTR("error while getting all deployed packages: ") + m_context, 1199 static_cast<OWeakObject *>(this), exc ); 1200 } 1201 } 1202 1203 //______________________________________________________________________________ 1204 1205 1206 //ToDo: the function must not call registerPackage, do this in 1207 //XExtensionManager.reinstallDeployedExtensions 1208 void PackageManagerImpl::reinstallDeployedPackages( 1209 Reference<task::XAbortChannel> const & /*xAbortChannel*/, 1210 Reference<XCommandEnvironment> const & xCmdEnv_ ) 1211 throw (deployment::DeploymentException, 1212 CommandFailedException, CommandAbortedException, 1213 lang::IllegalArgumentException, RuntimeException) 1214 { 1215 check(); 1216 if (office_is_running()) 1217 throw RuntimeException( 1218 OUSTR("You must close any running Office process before " 1219 "reinstalling packages!"), static_cast<OWeakObject *>(this) ); 1220 1221 Reference<XCommandEnvironment> xCmdEnv; 1222 if (m_xLogFile.is()) 1223 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 1224 else 1225 xCmdEnv.set( xCmdEnv_ ); 1226 1227 try { 1228 ProgressLevel progress( 1229 xCmdEnv, OUSTR("Reinstalling all deployed packages...") ); 1230 1231 try_dispose( m_xRegistry ); 1232 m_xRegistry.clear(); 1233 if (m_registryCache.getLength() > 0) 1234 erase_path( m_registryCache, xCmdEnv ); 1235 initRegistryBackends(); 1236 Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY ); 1237 if (xUpdatable.is()) 1238 xUpdatable->update(); 1239 1240 //registering is done by the ExtensionManager service. 1241 } 1242 catch (RuntimeException &) { 1243 throw; 1244 } 1245 catch (CommandFailedException & exc) { 1246 logIntern( Any(exc) ); 1247 throw; 1248 } 1249 catch (CommandAbortedException & exc) { 1250 logIntern( Any(exc) ); 1251 throw; 1252 } 1253 catch (deployment::DeploymentException & exc) { 1254 logIntern( Any(exc) ); 1255 throw; 1256 } 1257 catch (Exception &) { 1258 Any exc( ::cppu::getCaughtException() ); 1259 logIntern( exc ); 1260 throw deployment::DeploymentException( 1261 OUSTR("Error while reinstalling all previously deployed " 1262 "packages of context ") + m_context, 1263 static_cast<OWeakObject *>(this), exc ); 1264 } 1265 } 1266 1267 1268 ::sal_Bool SAL_CALL PackageManagerImpl::isReadOnly( ) 1269 throw (::com::sun::star::uno::RuntimeException) 1270 { 1271 return m_readOnly; 1272 } 1273 bool PackageManagerImpl::synchronizeRemovedExtensions( 1274 Reference<task::XAbortChannel> const & xAbortChannel, 1275 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) 1276 { 1277 1278 //find all which are in the extension data base but which 1279 //are removed already. 1280 OSL_ASSERT(!m_context.equals(OUSTR("user"))); 1281 bool bModified = false; 1282 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 1283 1284 typedef ActivePackages::Entries::const_iterator ITActive; 1285 bool bShared = m_context.equals(OUSTR("shared")); 1286 1287 for (ITActive i = id2temp.begin(); i != id2temp.end(); i++) 1288 { 1289 try 1290 { 1291 //Get the URL to the extensions folder, first make the url for the 1292 //shared repository including the temporary name 1293 OUString url = makeURL(m_activePackages, i->second.temporaryName); 1294 if (bShared) 1295 url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName); 1296 1297 bool bRemoved = false; 1298 //Check if the URL to the extension is still the same 1299 ::ucbhelper::Content contentExtension; 1300 1301 if (!create_ucb_content( 1302 &contentExtension, url, 1303 Reference<XCommandEnvironment>(), false)) 1304 { 1305 bRemoved = true; 1306 } 1307 1308 //The folder is in the extension database, but it can still be deleted. 1309 //look for the xxx.tmpremoved file 1310 //There can also be the case that a different extension was installed 1311 //in a "temp" folder with name that is already used. 1312 if (!bRemoved && bShared) 1313 { 1314 ::ucbhelper::Content contentRemoved; 1315 1316 if (create_ucb_content( 1317 &contentRemoved, 1318 m_activePackages_expanded + OUSTR("/") + 1319 i->second.temporaryName + OUSTR("removed"), 1320 Reference<XCommandEnvironment>(), false)) 1321 { 1322 bRemoved = true; 1323 } 1324 } 1325 1326 if (!bRemoved) 1327 { 1328 //There may be another extensions at the same place 1329 dp_misc::DescriptionInfoset infoset = 1330 dp_misc::getDescriptionInfoset(url); 1331 OSL_ENSURE(infoset.hasDescription(), 1332 "Extension Manager: bundled and shared extensions " 1333 "must have an identifer and a version"); 1334 if (infoset.hasDescription() && 1335 infoset.getIdentifier() && 1336 (! i->first.equals(*(infoset.getIdentifier())) 1337 || ! i->second.version.equals(infoset.getVersion()))) 1338 { 1339 bRemoved = true; 1340 } 1341 1342 } 1343 if (bRemoved) 1344 { 1345 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage( 1346 url, i->second.mediaType, true, i->first, xCmdEnv ); 1347 OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object. 1348 xPackage->revokePackage(xAbortChannel, xCmdEnv); 1349 removePackage(xPackage->getIdentifier().Value, xPackage->getName(), 1350 xAbortChannel, xCmdEnv); 1351 bModified |= true; 1352 } 1353 } 1354 catch( uno::Exception & ) 1355 { 1356 OSL_ASSERT(0); 1357 } 1358 } 1359 return bModified; 1360 } 1361 1362 1363 bool PackageManagerImpl::synchronizeAddedExtensions( 1364 Reference<task::XAbortChannel> const & xAbortChannel, 1365 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) 1366 { 1367 bool bModified = false; 1368 OSL_ASSERT(!m_context.equals(OUSTR("user"))); 1369 1370 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 1371 //check if the folder exist at all. The shared extension folder 1372 //may not exist for a normal user. 1373 if (!create_ucb_content( 1374 NULL, m_activePackages_expanded, Reference<css::ucb::XCommandEnvironment>(), false)) 1375 return bModified; 1376 ::ucbhelper::Content tempFolder( 1377 m_activePackages_expanded, xCmdEnv ); 1378 1379 Reference<sdbc::XResultSet> xResultSet( 1380 tempFolder.createCursor( 1381 Sequence<OUString>( &StrTitle::get(), 1 ), 1382 ::ucbhelper::INCLUDE_FOLDERS_ONLY ) ); 1383 1384 while (xResultSet->next()) 1385 { 1386 try 1387 { 1388 OUString title( 1389 Reference<sdbc::XRow>( 1390 xResultSet, UNO_QUERY_THROW )->getString( 1391 1 /* Title */ ) ); 1392 //The temporary folders of user and shared have an '_' at then end. 1393 //But the name in ActivePackages.temporaryName is saved without. 1394 OUString title2 = title; 1395 bool bShared = m_context.equals(OUSTR("shared")); 1396 if (bShared) 1397 { 1398 OSL_ASSERT(title2[title2.getLength() -1] == '_'); 1399 title2 = title2.copy(0, title2.getLength() -1); 1400 } 1401 OUString titleEncoded = ::rtl::Uri::encode( 1402 title2, rtl_UriCharClassPchar, 1403 rtl_UriEncodeIgnoreEscapes, 1404 RTL_TEXTENCODING_UTF8); 1405 1406 //It it sufficient to check for the folder name, because when the administor 1407 //installed the extension it was already checked if there is one with the 1408 //same identifier. 1409 const MatchTempDir match(titleEncoded); 1410 if (::std::find_if( id2temp.begin(), id2temp.end(), match ) == 1411 id2temp.end()) 1412 { 1413 1414 // The folder was not found in the data base, so it must be 1415 // an added extension 1416 OUString url(m_activePackages_expanded + OUSTR("/") + titleEncoded); 1417 OUString sExtFolder; 1418 if (bShared) //that is, shared 1419 { 1420 //Check if the extension was not "deleted" already which is indicated 1421 //by a xxx.tmpremoved file 1422 ::ucbhelper::Content contentRemoved; 1423 if (create_ucb_content(&contentRemoved, url + OUSTR("removed"), 1424 Reference<XCommandEnvironment>(), false)) 1425 continue; 1426 sExtFolder = getExtensionFolder( 1427 m_activePackages_expanded + 1428 OUString(OUSTR("/")) + titleEncoded + OUSTR("_"), xCmdEnv); 1429 url = makeURLAppendSysPathSegment(m_activePackages_expanded, title); 1430 url = makeURLAppendSysPathSegment(url, sExtFolder); 1431 } 1432 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage( 1433 url, OUString(), false, OUString(), xCmdEnv ); 1434 if (xPackage.is()) 1435 { 1436 //Prepare the database entry 1437 ActivePackages::Data dbData; 1438 1439 dbData.temporaryName = titleEncoded; 1440 if (bShared) 1441 dbData.fileName = sExtFolder; 1442 else 1443 dbData.fileName = title; 1444 dbData.mediaType = xPackage->getPackageType()->getMediaType(); 1445 dbData.version = xPackage->getVersion(); 1446 OSL_ENSURE(dbData.version.getLength() > 0, 1447 "Extension Manager: bundled and shared extensions must have " 1448 "an identifier and a version"); 1449 1450 OUString id = dp_misc::getIdentifier( xPackage ); 1451 1452 //We provide a special command environment that will prevent 1453 //showing a license if simple-licens/@accept-by = "admin" 1454 //It will also prevent showing the license for bundled extensions 1455 //which is not supported. 1456 OSL_ASSERT(!m_context.equals(OUSTR("user"))); 1457 1458 // shall the license be suppressed? 1459 DescriptionInfoset info = 1460 dp_misc::getDescriptionInfoset(url); 1461 ::boost::optional<dp_misc::SimpleLicenseAttributes> 1462 attr = info.getSimpleLicenseAttributes(); 1463 ExtensionProperties props(url,xCmdEnv); 1464 bool bNoLicense = false; 1465 if (attr && attr->suppressIfRequired && props.isSuppressedLicense()) 1466 bNoLicense = true; 1467 1468 Reference<ucb::XCommandEnvironment> licCmdEnv( 1469 new LicenseCommandEnv(xCmdEnv->getInteractionHandler(), 1470 bNoLicense, m_context)); 1471 sal_Int32 failedPrereq = xPackage->checkPrerequisites( 1472 xAbortChannel, licCmdEnv, false); 1473 //Remember that this failed. For example, the user 1474 //could have declined the license. Then the next time the 1475 //extension folder is investigated we do not want to 1476 //try to install the extension again. 1477 dbData.failedPrerequisites = OUString::valueOf(failedPrereq); 1478 insertToActivationLayerDB(id, dbData); 1479 bModified |= true; 1480 } 1481 } 1482 } 1483 catch (uno::Exception &) 1484 { 1485 OSL_ASSERT(0); 1486 } 1487 } 1488 return bModified; 1489 } 1490 1491 sal_Bool PackageManagerImpl::synchronize( 1492 Reference<task::XAbortChannel> const & xAbortChannel, 1493 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) 1494 throw (css::deployment::DeploymentException, 1495 css::ucb::CommandFailedException, 1496 css::ucb::CommandAbortedException, 1497 css::uno::RuntimeException) 1498 { 1499 check(); 1500 bool bModified = false; 1501 if (m_context.equals(OUSTR("user"))) 1502 return bModified; 1503 bModified |= 1504 synchronizeRemovedExtensions(xAbortChannel, xCmdEnv); 1505 bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv); 1506 1507 return bModified; 1508 } 1509 1510 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses( 1511 Reference<ucb::XCommandEnvironment> const & xCmdEnv) 1512 throw (deployment::DeploymentException, RuntimeException) 1513 { 1514 ::std::vector<Reference<deployment::XPackage> > vec; 1515 1516 try 1517 { 1518 const ::osl::MutexGuard guard( getMutex() ); 1519 // clean up activation layer, scan for zombie temp dirs: 1520 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 1521 1522 ActivePackages::Entries::const_iterator i = id2temp.begin(); 1523 bool bShared = m_context.equals(OUSTR("shared")); 1524 1525 for (; i != id2temp.end(); i++ ) 1526 { 1527 //Get the database entry 1528 ActivePackages::Data const & dbData = i->second; 1529 sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32(); 1530 //If the installation failed for other reason then the license then we 1531 //ignore it. 1532 if (failedPrereq ^= deployment::Prerequisites::LICENSE) 1533 continue; 1534 1535 //Prepare the URL to the extension 1536 OUString url = makeURL(m_activePackages, i->second.temporaryName); 1537 if (bShared) 1538 url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName); 1539 1540 Reference<deployment::XPackage> p = m_xRegistry->bindPackage( 1541 url, OUString(), false, OUString(), xCmdEnv ); 1542 1543 if (p.is()) 1544 vec.push_back(p); 1545 1546 } 1547 return ::comphelper::containerToSequence(vec); 1548 } 1549 catch (deployment::DeploymentException &) 1550 { 1551 throw; 1552 } 1553 catch (RuntimeException&) 1554 { 1555 throw; 1556 } 1557 catch (...) 1558 { 1559 Any exc = ::cppu::getCaughtException(); 1560 deployment::DeploymentException de( 1561 OUSTR("PackageManagerImpl::getExtensionsWithUnacceptedLicenses"), 1562 static_cast<OWeakObject*>(this), exc); 1563 exc <<= de; 1564 ::cppu::throwException(exc); 1565 } 1566 1567 return ::comphelper::containerToSequence(vec); 1568 } 1569 1570 sal_Int32 PackageManagerImpl::checkPrerequisites( 1571 css::uno::Reference<css::deployment::XPackage> const & extension, 1572 css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, 1573 css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) 1574 throw (css::deployment::DeploymentException, 1575 css::ucb::CommandFailedException, 1576 css::ucb::CommandAbortedException, 1577 css::lang::IllegalArgumentException, 1578 css::uno::RuntimeException) 1579 { 1580 try 1581 { 1582 if (!extension.is()) 1583 return 0; 1584 if (!m_context.equals(extension->getRepositoryName())) 1585 throw lang::IllegalArgumentException( 1586 OUSTR("PackageManagerImpl::checkPrerequisites: extension is not" 1587 " from this repository."), 0, 0); 1588 1589 ActivePackages::Data dbData; 1590 OUString id = dp_misc::getIdentifier(extension); 1591 if (m_activePackagesDB->get( &dbData, id, OUString())) 1592 { 1593 //If the license was already displayed, then do not show it again 1594 Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv; 1595 sal_Int32 prereq = dbData.failedPrerequisites.toInt32(); 1596 if ( !(prereq & deployment::Prerequisites::LICENSE)) 1597 _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler()); 1598 1599 sal_Int32 failedPrereq = extension->checkPrerequisites( 1600 xAbortChannel, _xCmdEnv, false); 1601 dbData.failedPrerequisites = OUString::valueOf(failedPrereq); 1602 insertToActivationLayerDB(id, dbData); 1603 } 1604 else 1605 { 1606 throw lang::IllegalArgumentException( 1607 OUSTR("PackageManagerImpl::checkPrerequisites: unknown extension"), 1608 0, 0); 1609 1610 } 1611 return 0; 1612 } 1613 catch (deployment::DeploymentException& ) { 1614 throw; 1615 } catch (ucb::CommandFailedException & ) { 1616 throw; 1617 } catch (ucb::CommandAbortedException & ) { 1618 throw; 1619 } catch (lang::IllegalArgumentException &) { 1620 throw; 1621 } catch (uno::RuntimeException &) { 1622 throw; 1623 } catch (...) { 1624 uno::Any excOccurred = ::cppu::getCaughtException(); 1625 deployment::DeploymentException exc( 1626 OUSTR("PackageManagerImpl::checkPrerequisites: exception "), 1627 static_cast<OWeakObject*>(this), excOccurred); 1628 throw exc; 1629 } 1630 } 1631 1632 //############################################################################## 1633 1634 //______________________________________________________________________________ 1635 PackageManagerImpl::CmdEnvWrapperImpl::~CmdEnvWrapperImpl() 1636 { 1637 } 1638 1639 //______________________________________________________________________________ 1640 PackageManagerImpl::CmdEnvWrapperImpl::CmdEnvWrapperImpl( 1641 Reference<XCommandEnvironment> const & xUserCmdEnv, 1642 Reference<XProgressHandler> const & xLogFile ) 1643 : m_xLogFile( xLogFile ) 1644 { 1645 if (xUserCmdEnv.is()) { 1646 m_xUserProgress.set( xUserCmdEnv->getProgressHandler() ); 1647 m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() ); 1648 } 1649 } 1650 1651 // XCommandEnvironment 1652 //______________________________________________________________________________ 1653 Reference<task::XInteractionHandler> 1654 PackageManagerImpl::CmdEnvWrapperImpl::getInteractionHandler() 1655 throw (RuntimeException) 1656 { 1657 return m_xUserInteractionHandler; 1658 } 1659 1660 //______________________________________________________________________________ 1661 Reference<XProgressHandler> 1662 PackageManagerImpl::CmdEnvWrapperImpl::getProgressHandler() 1663 throw (RuntimeException) 1664 { 1665 return this; 1666 } 1667 1668 // XProgressHandler 1669 //______________________________________________________________________________ 1670 void PackageManagerImpl::CmdEnvWrapperImpl::push( Any const & Status ) 1671 throw (RuntimeException) 1672 { 1673 if (m_xLogFile.is()) 1674 m_xLogFile->push( Status ); 1675 if (m_xUserProgress.is()) 1676 m_xUserProgress->push( Status ); 1677 } 1678 1679 //______________________________________________________________________________ 1680 void PackageManagerImpl::CmdEnvWrapperImpl::update( Any const & Status ) 1681 throw (RuntimeException) 1682 { 1683 if (m_xLogFile.is()) 1684 m_xLogFile->update( Status ); 1685 if (m_xUserProgress.is()) 1686 m_xUserProgress->update( Status ); 1687 } 1688 1689 //______________________________________________________________________________ 1690 void PackageManagerImpl::CmdEnvWrapperImpl::pop() throw (RuntimeException) 1691 { 1692 if (m_xLogFile.is()) 1693 m_xLogFile->pop(); 1694 if (m_xUserProgress.is()) 1695 m_xUserProgress->pop(); 1696 } 1697 1698 } // namespace dp_manager 1699 1700