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 //Do not call check here. We must not throw an exception here if the object 540 //is being disposed or is already disposed. See com.sun.star.lang.XComponent 541 WeakComponentImplHelperBase::dispose(); 542 } 543 544 //______________________________________________________________________________ 545 void PackageManagerImpl::addEventListener( 546 Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) 547 { 548 //Do not call check here. We must not throw an exception here if the object 549 //is being disposed or is already disposed. See com.sun.star.lang.XComponent 550 WeakComponentImplHelperBase::addEventListener( xListener ); 551 } 552 553 //______________________________________________________________________________ 554 void PackageManagerImpl::removeEventListener( 555 Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) 556 { 557 //Do not call check here. We must not throw an exception here if the object 558 //is being disposed or is already disposed. See com.sun.star.lang.XComponent 559 WeakComponentImplHelperBase::removeEventListener( xListener ); 560 } 561 562 // XPackageManager 563 //______________________________________________________________________________ 564 OUString PackageManagerImpl::getContext() throw (RuntimeException) 565 { 566 check(); 567 return m_context; 568 } 569 570 //______________________________________________________________________________ 571 Sequence< Reference<deployment::XPackageTypeInfo> > 572 PackageManagerImpl::getSupportedPackageTypes() throw (RuntimeException) 573 { 574 OSL_ASSERT( m_xRegistry.is() ); 575 return m_xRegistry->getSupportedPackageTypes(); 576 } 577 578 //______________________________________________________________________________ 579 Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel() 580 throw (RuntimeException) 581 { 582 check(); 583 return new AbortChannel; 584 } 585 586 // XModifyBroadcaster 587 //______________________________________________________________________________ 588 void PackageManagerImpl::addModifyListener( 589 Reference<util::XModifyListener> const & xListener ) 590 throw (RuntimeException) 591 { 592 check(); 593 rBHelper.addListener( ::getCppuType( &xListener ), xListener ); 594 } 595 596 //______________________________________________________________________________ 597 void PackageManagerImpl::removeModifyListener( 598 Reference<util::XModifyListener> const & xListener ) 599 throw (RuntimeException) 600 { 601 check(); 602 rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); 603 } 604 605 //______________________________________________________________________________ 606 OUString PackageManagerImpl::detectMediaType( 607 ::ucbhelper::Content const & ucbContent_, bool throw_exc ) 608 { 609 ::ucbhelper::Content ucbContent(ucbContent_); 610 OUString url( ucbContent.getURL() ); 611 OUString mediaType; 612 if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:") ) || 613 url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.pkg:") )) 614 { 615 try { 616 ucbContent.getPropertyValue( OUSTR("MediaType") ) >>= mediaType; 617 } 618 catch (beans::UnknownPropertyException &) { 619 } 620 OSL_ENSURE( mediaType.getLength() > 0, "### no media-type?!" ); 621 } 622 if (mediaType.getLength() == 0) 623 { 624 try { 625 Reference<deployment::XPackage> xPackage( 626 m_xRegistry->bindPackage( 627 url, OUString(), false, OUString(), ucbContent.getCommandEnvironment() ) ); 628 const Reference<deployment::XPackageTypeInfo> xPackageType( 629 xPackage->getPackageType() ); 630 OSL_ASSERT( xPackageType.is() ); 631 if (xPackageType.is()) 632 mediaType = xPackageType->getMediaType(); 633 } 634 catch (lang::IllegalArgumentException & exc) { 635 if (throw_exc) 636 throw; 637 (void) exc; 638 OSL_ENSURE( 0, ::rtl::OUStringToOString( 639 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 640 } 641 } 642 return mediaType; 643 } 644 645 //______________________________________________________________________________ 646 OUString PackageManagerImpl::insertToActivationLayer( 647 Sequence<beans::NamedValue> const & properties, 648 OUString const & mediaType, ::ucbhelper::Content const & sourceContent_, 649 OUString const & title, ActivePackages::Data * dbData ) 650 { 651 ::ucbhelper::Content sourceContent(sourceContent_); 652 Reference<XCommandEnvironment> xCmdEnv( 653 sourceContent.getCommandEnvironment() ); 654 655 String baseDir(m_activePackages_expanded); 656 ::utl::TempFile aTemp(&baseDir, sal_False); 657 OUString tempEntry = aTemp.GetURL(); 658 tempEntry = tempEntry.copy(tempEntry.lastIndexOf('/') + 1); 659 OUString destFolder = makeURL( m_activePackages, tempEntry); 660 destFolder += OUSTR("_"); 661 662 // prepare activation folder: 663 ::ucbhelper::Content destFolderContent; 664 create_folder( &destFolderContent, destFolder, xCmdEnv ); 665 666 // copy content into activation temp dir: 667 if (mediaType.matchIgnoreAsciiCaseAsciiL( 668 RTL_CONSTASCII_STRINGPARAM( 669 "application/vnd.sun.star.package-bundle") ) || 670 // xxx todo: more sophisticated parsing 671 mediaType.matchIgnoreAsciiCaseAsciiL( 672 RTL_CONSTASCII_STRINGPARAM( 673 "application/vnd.sun.star.legacy-package-bundle") )) 674 { 675 // inflate content: 676 ::rtl::OUStringBuffer buf; 677 if (!sourceContent.isFolder()) 678 { 679 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") ); 680 buf.append( ::rtl::Uri::encode( sourceContent.getURL(), 681 rtl_UriCharClassRegName, 682 rtl_UriEncodeIgnoreEscapes, 683 RTL_TEXTENCODING_UTF8 ) ); 684 } 685 else 686 { 687 //Folder. No need to unzip, just copy 688 buf.append(sourceContent.getURL()); 689 } 690 buf.append( static_cast<sal_Unicode>('/') ); 691 sourceContent = ::ucbhelper::Content( 692 buf.makeStringAndClear(), xCmdEnv ); 693 } 694 if (! destFolderContent.transferContent( 695 sourceContent, ::ucbhelper::InsertOperation_COPY, 696 title, NameClash::OVERWRITE )) 697 throw RuntimeException( OUSTR("UCB transferContent() failed!"), 0 ); 698 699 700 // write to DB: 701 //bundled extensions should only be added by the synchronizeAddedExtensions 702 //functions. Moreover, there is no "temporary folder" for bundled extensions. 703 OSL_ASSERT(!m_context.equals(OUSTR("bundled"))); 704 OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title); 705 DescriptionInfoset info = 706 dp_misc::getDescriptionInfoset(sFolderUrl); 707 dbData->temporaryName = tempEntry; 708 dbData->fileName = title; 709 dbData->mediaType = mediaType; 710 dbData->version = info.getVersion(); 711 712 //No write the properties file next to the extension 713 ExtensionProperties props(sFolderUrl, properties, xCmdEnv); 714 props.write(); 715 return destFolder; 716 } 717 718 //______________________________________________________________________________ 719 void PackageManagerImpl::insertToActivationLayerDB( 720 OUString const & id, ActivePackages::Data const & dbData ) 721 { 722 //access to the database must be guarded. See removePackage 723 const ::osl::MutexGuard guard( getMutex() ); 724 m_activePackagesDB->put( id, dbData ); 725 } 726 727 //______________________________________________________________________________ 728 /* The function returns true if there is an extension with the same id already 729 installed which needs to be uninstalled, before the new extension can be installed. 730 */ 731 bool PackageManagerImpl::isInstalled( 732 Reference<deployment::XPackage> const & package) 733 { 734 OUString id(dp_misc::getIdentifier(package)); 735 OUString fn(package->getName()); 736 bool bInstalled = false; 737 if (m_activePackagesDB->has( id, fn )) 738 { 739 bInstalled = true; 740 } 741 return bInstalled; 742 } 743 744 // XPackageManager 745 //______________________________________________________________________________ 746 Reference<deployment::XPackage> PackageManagerImpl::importExtension( 747 Reference<deployment::XPackage> const & extension, 748 Reference<task::XAbortChannel> const & xAbortChannel, 749 Reference<XCommandEnvironment> const & xCmdEnv_ ) 750 throw (deployment::DeploymentException, CommandFailedException, 751 CommandAbortedException, lang::IllegalArgumentException, 752 RuntimeException) 753 { 754 return addPackage(extension->getURL(), Sequence<beans::NamedValue>(), 755 OUString(), xAbortChannel, xCmdEnv_); 756 } 757 758 /* The function adds an extension but does not register it!!! 759 It may not do any user interaction. This is done in XExtensionManager::addExtension 760 */ 761 Reference<deployment::XPackage> PackageManagerImpl::addPackage( 762 OUString const & url, 763 css::uno::Sequence<css::beans::NamedValue> const & properties, 764 OUString const & mediaType_, 765 Reference<task::XAbortChannel> const & xAbortChannel, 766 Reference<XCommandEnvironment> const & xCmdEnv_ ) 767 throw (deployment::DeploymentException, CommandFailedException, 768 CommandAbortedException, lang::IllegalArgumentException, 769 RuntimeException) 770 { 771 check(); 772 if (m_readOnly) 773 { 774 OUString message; 775 if (m_context == OUSTR("shared")) 776 message = OUSTR("You need write permissions to install a shared extension!"); 777 else 778 message = OUSTR("You need write permissions to install this extension!"); 779 throw deployment::DeploymentException( 780 message, static_cast<OWeakObject *>(this), Any() ); 781 } 782 Reference<XCommandEnvironment> xCmdEnv; 783 if (m_xLogFile.is()) 784 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 785 else 786 xCmdEnv.set( xCmdEnv_ ); 787 788 try { 789 ::ucbhelper::Content sourceContent; 790 create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc 791 const OUString title(sourceContent.getPropertyValue( 792 StrTitle::get() ).get<OUString>() ); 793 const OUString title_enc( ::rtl::Uri::encode( 794 title, rtl_UriCharClassPchar, 795 rtl_UriEncodeIgnoreEscapes, 796 RTL_TEXTENCODING_UTF8 ) ); 797 OUString destFolder; 798 799 OUString mediaType(mediaType_); 800 if (mediaType.getLength() == 0) 801 mediaType = detectMediaType( sourceContent ); 802 803 Reference<deployment::XPackage> xPackage; 804 // copy file: 805 progressUpdate( 806 getResourceString(RID_STR_COPYING_PACKAGE) + title, xCmdEnv ); 807 if (m_activePackages.getLength() == 0) 808 { 809 ::ucbhelper::Content docFolderContent; 810 create_folder( &docFolderContent, m_context, xCmdEnv ); 811 // copy into document, first: 812 if (! docFolderContent.transferContent( 813 sourceContent, ::ucbhelper::InsertOperation_COPY, 814 OUString(), 815 NameClash::ASK /* xxx todo: ASK not needed? */)) 816 throw RuntimeException( 817 OUSTR("UCB transferContent() failed!"), 0 ); 818 // set media-type: 819 ::ucbhelper::Content docContent( 820 makeURL( m_context, title_enc ), xCmdEnv ); 821 //TODO #i73136#: using title instead of id can lead to 822 // clashes, but the whole m_activePackages.getLength()==0 823 // case (i.e., document-relative deployment) currently does 824 // not work, anyway. 825 docContent.setPropertyValue( 826 OUSTR("MediaType"), Any(mediaType) ); 827 828 // xxx todo: obsolete in the future 829 try { 830 docFolderContent.executeCommand( OUSTR("flush"), Any() ); 831 } 832 catch (UnsupportedCommandException &) { 833 } 834 } 835 ActivePackages::Data dbData; 836 destFolder = insertToActivationLayer( 837 properties, mediaType, sourceContent, title, &dbData ); 838 839 840 // bind activation package: 841 //Because every shared/user extension will be unpacked in a folder, 842 //which was created with a unique name we will always have two different 843 //XPackage objects, even if the second extension is the same. 844 //Therefore bindPackage does not need a guard here. 845 xPackage = m_xRegistry->bindPackage( 846 makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv ); 847 848 OSL_ASSERT( xPackage.is() ); 849 if (xPackage.is()) 850 { 851 bool install = false; 852 try 853 { 854 OUString const id = dp_misc::getIdentifier( xPackage ); 855 856 ::osl::MutexGuard g(m_addMutex); 857 if (isInstalled(xPackage)) 858 { 859 //Do not guard the complete function with the getMutex 860 removePackage(id, xPackage->getName(), xAbortChannel, 861 xCmdEnv); 862 } 863 install = true; 864 insertToActivationLayerDB(id, dbData); 865 } 866 catch (...) 867 { 868 deletePackageFromCache( xPackage, destFolder ); 869 throw; 870 } 871 if (!install) 872 { 873 deletePackageFromCache( xPackage, destFolder ); 874 } 875 //ToDo: We should notify only if the extension is registered 876 fireModified(); 877 } 878 return xPackage; 879 } 880 catch (RuntimeException &) { 881 throw; 882 } 883 catch (CommandFailedException & exc) { 884 logIntern( Any(exc) ); 885 throw; 886 } 887 catch (CommandAbortedException & exc) { 888 logIntern( Any(exc) ); 889 throw; 890 } 891 catch (deployment::DeploymentException & exc) { 892 logIntern( Any(exc) ); 893 throw; 894 } 895 catch (Exception &) { 896 Any exc( ::cppu::getCaughtException() ); 897 logIntern( exc ); 898 throw deployment::DeploymentException( 899 getResourceString(RID_STR_ERROR_WHILE_ADDING) + url, 900 static_cast<OWeakObject *>(this), exc ); 901 } 902 } 903 void PackageManagerImpl::deletePackageFromCache( 904 Reference<deployment::XPackage> const & xPackage, 905 OUString const & destFolder) 906 { 907 try_dispose( xPackage ); 908 909 //we remove the package from the uno cache 910 //no service from the package may be loaded at this time!!! 911 erase_path( destFolder, Reference<XCommandEnvironment>(), 912 false /* no throw: ignore errors */ ); 913 //rm last character '_' 914 OUString url = destFolder.copy(0, destFolder.getLength() - 1); 915 erase_path( url, Reference<XCommandEnvironment>(), 916 false /* no throw: ignore errors */ ); 917 918 } 919 //______________________________________________________________________________ 920 void PackageManagerImpl::removePackage( 921 OUString const & id, ::rtl::OUString const & fileName, 922 Reference<task::XAbortChannel> const & /*xAbortChannel*/, 923 Reference<XCommandEnvironment> const & xCmdEnv_ ) 924 throw (deployment::DeploymentException, CommandFailedException, 925 CommandAbortedException, lang::IllegalArgumentException, 926 RuntimeException) 927 { 928 check(); 929 930 Reference<XCommandEnvironment> xCmdEnv; 931 if (m_xLogFile.is()) 932 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 933 else 934 xCmdEnv.set( xCmdEnv_ ); 935 936 try { 937 Reference<deployment::XPackage> xPackage; 938 { 939 const ::osl::MutexGuard guard(getMutex()); 940 //Check if this extension exist and throw an IllegalArgumentException 941 //if it does not 942 //If the files of the extension are already removed, or there is a 943 //different extension at the same place, for example after updating the 944 //extension, then the returned object is that which uses the database data. 945 xPackage = getDeployedPackage_(id, fileName, xCmdEnv ); 946 947 948 //Because the extension is only removed the next time the extension 949 //manager runs after restarting OOo, we need to indicate that a 950 //shared extension was "deleted". When a user starts OOo, then it 951 //will check if something changed in the shared repository. Based on 952 //the flag file it will then recognize, that the extension was 953 //deleted and can then update the extnesion database of the shared 954 //extensions in the user installation. 955 if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && m_context.equals(OUSTR("shared"))) 956 { 957 ActivePackages::Data val; 958 m_activePackagesDB->get( & val, id, fileName); 959 OSL_ASSERT(val.temporaryName.getLength()); 960 OUString url(makeURL(m_activePackages_expanded, 961 val.temporaryName + OUSTR("removed"))); 962 ::ucbhelper::Content contentRemoved(url, xCmdEnv ); 963 OUString aUserName; 964 ::osl::Security aSecurity; 965 aSecurity.getUserName( aUserName ); 966 967 ::rtl::OString stamp = ::rtl::OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8); 968 Reference<css::io::XInputStream> xData( 969 ::xmlscript::createInputStream( 970 ::rtl::ByteSequence( 971 reinterpret_cast<sal_Int8 const *>(stamp.getStr()), 972 stamp.getLength() ) ) ); 973 contentRemoved.writeStream( xData, true /* replace existing */ ); 974 } 975 m_activePackagesDB->erase( id, fileName ); // to be removed upon next start 976 //remove any cached data hold by the backend 977 m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType()); 978 } 979 try_dispose( xPackage ); 980 981 fireModified(); 982 } 983 catch (RuntimeException &) { 984 throw; 985 } 986 catch (lang::IllegalArgumentException &) { 987 throw; 988 } 989 catch (CommandFailedException & exc) { 990 logIntern( Any(exc) ); 991 throw; 992 } 993 catch (CommandAbortedException & exc) { 994 logIntern( Any(exc) ); 995 throw; 996 } 997 catch (deployment::DeploymentException & exc) { 998 logIntern( Any(exc) ); 999 throw; 1000 } 1001 catch (Exception &) { 1002 Any exc( ::cppu::getCaughtException() ); 1003 logIntern( exc ); 1004 throw deployment::DeploymentException( 1005 getResourceString(RID_STR_ERROR_WHILE_REMOVING) + id, 1006 static_cast<OWeakObject *>(this), exc ); 1007 } 1008 } 1009 1010 //______________________________________________________________________________ 1011 OUString PackageManagerImpl::getDeployPath( ActivePackages::Data const & data ) 1012 { 1013 ::rtl::OUStringBuffer buf; 1014 buf.append( data.temporaryName ); 1015 //The bundled extensions are not contained in an additional folder 1016 //with a unique name. data.temporaryName contains already the 1017 //UTF8 encoded folder name. See PackageManagerImpl::synchronize 1018 if (!m_context.equals(OUSTR("bundled")) 1019 && !m_context.equals(OUSTR("bundled_prereg"))) 1020 { 1021 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("_/") ); 1022 buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar, 1023 rtl_UriEncodeIgnoreEscapes, 1024 RTL_TEXTENCODING_UTF8 ) ); 1025 } 1026 return makeURL( m_activePackages, buf.makeStringAndClear() ); 1027 } 1028 1029 //______________________________________________________________________________ 1030 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_( 1031 OUString const & id, OUString const & fileName, 1032 Reference<XCommandEnvironment> const & xCmdEnv ) 1033 { 1034 ActivePackages::Data val; 1035 if (m_activePackagesDB->get( &val, id, fileName )) 1036 { 1037 return getDeployedPackage_( id, val, xCmdEnv, false ); 1038 } 1039 throw lang::IllegalArgumentException( 1040 getResourceString(RID_STR_NO_SUCH_PACKAGE) + id, 1041 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); 1042 } 1043 1044 //______________________________________________________________________________ 1045 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_( 1046 OUString const & id, ActivePackages::Data const & data, 1047 Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms ) 1048 { 1049 if (ignoreAlienPlatforms) 1050 { 1051 String type, subType; 1052 INetContentTypeParameterList params; 1053 if (INetContentTypes::parse( data.mediaType, type, subType, ¶ms )) 1054 { 1055 INetContentTypeParameter const * param = params.find( 1056 ByteString("platform") ); 1057 if (param != 0 && !platform_fits( param->m_sValue )) 1058 throw lang::IllegalArgumentException( 1059 getResourceString(RID_STR_NO_SUCH_PACKAGE) + id, 1060 static_cast<OWeakObject *>(this), 1061 static_cast<sal_Int16>(-1) ); 1062 } 1063 } 1064 Reference<deployment::XPackage> xExtension; 1065 try 1066 { 1067 //Ignore extensions where XPackage::checkPrerequisites failed. 1068 //They must not be usable for this user. 1069 if (data.failedPrerequisites.equals(OUSTR("0"))) 1070 { 1071 xExtension = m_xRegistry->bindPackage( 1072 getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv ); 1073 } 1074 } 1075 catch (deployment::InvalidRemovedParameterException& e) 1076 { 1077 xExtension = e.Extension; 1078 } 1079 return xExtension; 1080 } 1081 1082 //______________________________________________________________________________ 1083 Sequence< Reference<deployment::XPackage> > 1084 PackageManagerImpl::getDeployedPackages_( 1085 Reference<XCommandEnvironment> const & xCmdEnv ) 1086 { 1087 ::std::vector< Reference<deployment::XPackage> > packages; 1088 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 1089 ActivePackages::Entries::const_iterator iPos( id2temp.begin() ); 1090 ActivePackages::Entries::const_iterator const iEnd( id2temp.end() ); 1091 for ( ; iPos != iEnd; ++iPos ) 1092 { 1093 if (! iPos->second.failedPrerequisites.equals(OUSTR("0"))) 1094 continue; 1095 try { 1096 packages.push_back( 1097 getDeployedPackage_( 1098 iPos->first, iPos->second, xCmdEnv, 1099 true /* xxx todo: think of GUI: 1100 ignore other platforms than the current one */ ) ); 1101 } 1102 catch (lang::IllegalArgumentException & exc) { 1103 // ignore 1104 (void) exc; // avoid warnings 1105 OSL_ENSURE( 0, ::rtl::OUStringToOString( 1106 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 1107 } 1108 catch (deployment::DeploymentException& exc) { 1109 // ignore 1110 (void) exc; // avoid warnings 1111 OSL_ENSURE( 0, ::rtl::OUStringToOString( 1112 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 1113 } 1114 } 1115 return comphelper::containerToSequence(packages); 1116 } 1117 1118 //______________________________________________________________________________ 1119 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage( 1120 OUString const & id, ::rtl::OUString const & fileName, 1121 Reference<XCommandEnvironment> const & xCmdEnv_ ) 1122 throw (deployment::DeploymentException, CommandFailedException, 1123 lang::IllegalArgumentException, RuntimeException) 1124 { 1125 check(); 1126 Reference<XCommandEnvironment> xCmdEnv; 1127 if (m_xLogFile.is()) 1128 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 1129 else 1130 xCmdEnv.set( xCmdEnv_ ); 1131 1132 try { 1133 const ::osl::MutexGuard guard( getMutex() ); 1134 return getDeployedPackage_( id, fileName, xCmdEnv ); 1135 } 1136 catch (RuntimeException &) { 1137 throw; 1138 } 1139 catch (CommandFailedException & exc) { 1140 logIntern( Any(exc) ); 1141 throw; 1142 } 1143 catch (lang::IllegalArgumentException & exc) { 1144 logIntern( Any(exc) ); 1145 throw; 1146 } 1147 catch (deployment::DeploymentException & exc) { 1148 logIntern( Any(exc) ); 1149 throw; 1150 } 1151 catch (Exception &) { 1152 Any exc( ::cppu::getCaughtException() ); 1153 logIntern( exc ); 1154 throw deployment::DeploymentException( 1155 // ought never occur... 1156 OUSTR("error while accessing deployed package: ") + id, 1157 static_cast<OWeakObject *>(this), exc ); 1158 } 1159 } 1160 1161 //______________________________________________________________________________ 1162 Sequence< Reference<deployment::XPackage> > 1163 PackageManagerImpl::getDeployedPackages( 1164 Reference<task::XAbortChannel> const &, 1165 Reference<XCommandEnvironment> const & xCmdEnv_ ) 1166 throw (deployment::DeploymentException, CommandFailedException, 1167 CommandAbortedException, lang::IllegalArgumentException, 1168 RuntimeException) 1169 { 1170 check(); 1171 Reference<XCommandEnvironment> xCmdEnv; 1172 if (m_xLogFile.is()) 1173 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 1174 else 1175 xCmdEnv.set( xCmdEnv_ ); 1176 1177 try { 1178 const ::osl::MutexGuard guard( getMutex() ); 1179 return getDeployedPackages_( xCmdEnv ); 1180 } 1181 catch (RuntimeException &) { 1182 throw; 1183 } 1184 catch (CommandFailedException & exc) { 1185 logIntern( Any(exc) ); 1186 throw; 1187 } 1188 catch (CommandAbortedException & exc) { 1189 logIntern( Any(exc) ); 1190 throw; 1191 } 1192 catch (deployment::DeploymentException & exc) { 1193 logIntern( Any(exc) ); 1194 throw; 1195 } 1196 catch (Exception &) { 1197 Any exc( ::cppu::getCaughtException() ); 1198 logIntern( exc ); 1199 throw deployment::DeploymentException( 1200 // ought never occur... 1201 OUSTR("error while getting all deployed packages: ") + m_context, 1202 static_cast<OWeakObject *>(this), exc ); 1203 } 1204 } 1205 1206 //______________________________________________________________________________ 1207 1208 1209 //ToDo: the function must not call registerPackage, do this in 1210 //XExtensionManager.reinstallDeployedExtensions 1211 void PackageManagerImpl::reinstallDeployedPackages( 1212 Reference<task::XAbortChannel> const & /*xAbortChannel*/, 1213 Reference<XCommandEnvironment> const & xCmdEnv_ ) 1214 throw (deployment::DeploymentException, 1215 CommandFailedException, CommandAbortedException, 1216 lang::IllegalArgumentException, RuntimeException) 1217 { 1218 check(); 1219 if (office_is_running()) 1220 throw RuntimeException( 1221 OUSTR("You must close any running Office process before " 1222 "reinstalling packages!"), static_cast<OWeakObject *>(this) ); 1223 1224 Reference<XCommandEnvironment> xCmdEnv; 1225 if (m_xLogFile.is()) 1226 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); 1227 else 1228 xCmdEnv.set( xCmdEnv_ ); 1229 1230 try { 1231 ProgressLevel progress( 1232 xCmdEnv, OUSTR("Reinstalling all deployed packages...") ); 1233 1234 try_dispose( m_xRegistry ); 1235 m_xRegistry.clear(); 1236 if (m_registryCache.getLength() > 0) 1237 erase_path( m_registryCache, xCmdEnv ); 1238 initRegistryBackends(); 1239 Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY ); 1240 if (xUpdatable.is()) 1241 xUpdatable->update(); 1242 1243 //registering is done by the ExtensionManager service. 1244 } 1245 catch (RuntimeException &) { 1246 throw; 1247 } 1248 catch (CommandFailedException & exc) { 1249 logIntern( Any(exc) ); 1250 throw; 1251 } 1252 catch (CommandAbortedException & exc) { 1253 logIntern( Any(exc) ); 1254 throw; 1255 } 1256 catch (deployment::DeploymentException & exc) { 1257 logIntern( Any(exc) ); 1258 throw; 1259 } 1260 catch (Exception &) { 1261 Any exc( ::cppu::getCaughtException() ); 1262 logIntern( exc ); 1263 throw deployment::DeploymentException( 1264 OUSTR("Error while reinstalling all previously deployed " 1265 "packages of context ") + m_context, 1266 static_cast<OWeakObject *>(this), exc ); 1267 } 1268 } 1269 1270 1271 ::sal_Bool SAL_CALL PackageManagerImpl::isReadOnly( ) 1272 throw (::com::sun::star::uno::RuntimeException) 1273 { 1274 return m_readOnly; 1275 } 1276 bool PackageManagerImpl::synchronizeRemovedExtensions( 1277 Reference<task::XAbortChannel> const & xAbortChannel, 1278 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) 1279 { 1280 1281 //find all which are in the extension data base but which 1282 //are removed already. 1283 OSL_ASSERT(!m_context.equals(OUSTR("user"))); 1284 bool bModified = false; 1285 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 1286 1287 typedef ActivePackages::Entries::const_iterator ITActive; 1288 bool bShared = m_context.equals(OUSTR("shared")); 1289 1290 for (ITActive i = id2temp.begin(); i != id2temp.end(); i++) 1291 { 1292 try 1293 { 1294 //Get the URL to the extensions folder, first make the url for the 1295 //shared repository including the temporary name 1296 OUString url = makeURL(m_activePackages, i->second.temporaryName); 1297 if (bShared) 1298 url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName); 1299 1300 bool bRemoved = false; 1301 //Check if the URL to the extension is still the same 1302 ::ucbhelper::Content contentExtension; 1303 1304 if (!create_ucb_content( 1305 &contentExtension, url, 1306 Reference<XCommandEnvironment>(), false)) 1307 { 1308 bRemoved = true; 1309 } 1310 1311 //The folder is in the extension database, but it can still be deleted. 1312 //look for the xxx.tmpremoved file 1313 //There can also be the case that a different extension was installed 1314 //in a "temp" folder with name that is already used. 1315 if (!bRemoved && bShared) 1316 { 1317 ::ucbhelper::Content contentRemoved; 1318 1319 if (create_ucb_content( 1320 &contentRemoved, 1321 m_activePackages_expanded + OUSTR("/") + 1322 i->second.temporaryName + OUSTR("removed"), 1323 Reference<XCommandEnvironment>(), false)) 1324 { 1325 bRemoved = true; 1326 } 1327 } 1328 1329 if (!bRemoved) 1330 { 1331 //There may be another extensions at the same place 1332 dp_misc::DescriptionInfoset infoset = 1333 dp_misc::getDescriptionInfoset(url); 1334 OSL_ENSURE(infoset.hasDescription(), 1335 "Extension Manager: bundled and shared extensions " 1336 "must have an identifer and a version"); 1337 if (infoset.hasDescription() && 1338 infoset.getIdentifier() && 1339 (! i->first.equals(*(infoset.getIdentifier())) 1340 || ! i->second.version.equals(infoset.getVersion()))) 1341 { 1342 bRemoved = true; 1343 } 1344 1345 } 1346 if (bRemoved) 1347 { 1348 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage( 1349 url, i->second.mediaType, true, i->first, xCmdEnv ); 1350 OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object. 1351 xPackage->revokePackage(xAbortChannel, xCmdEnv); 1352 removePackage(xPackage->getIdentifier().Value, xPackage->getName(), 1353 xAbortChannel, xCmdEnv); 1354 bModified |= true; 1355 } 1356 } 1357 catch( uno::Exception & ) 1358 { 1359 OSL_ASSERT(0); 1360 } 1361 } 1362 return bModified; 1363 } 1364 1365 1366 bool PackageManagerImpl::synchronizeAddedExtensions( 1367 Reference<task::XAbortChannel> const & xAbortChannel, 1368 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) 1369 { 1370 bool bModified = false; 1371 OSL_ASSERT(!m_context.equals(OUSTR("user"))); 1372 1373 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 1374 //check if the folder exist at all. The shared extension folder 1375 //may not exist for a normal user. 1376 if (!create_ucb_content( 1377 NULL, m_activePackages_expanded, Reference<css::ucb::XCommandEnvironment>(), false)) 1378 return bModified; 1379 ::ucbhelper::Content tempFolder( 1380 m_activePackages_expanded, xCmdEnv ); 1381 1382 Reference<sdbc::XResultSet> xResultSet( 1383 tempFolder.createCursor( 1384 Sequence<OUString>( &StrTitle::get(), 1 ), 1385 ::ucbhelper::INCLUDE_FOLDERS_ONLY ) ); 1386 1387 while (xResultSet->next()) 1388 { 1389 try 1390 { 1391 OUString title( 1392 Reference<sdbc::XRow>( 1393 xResultSet, UNO_QUERY_THROW )->getString( 1394 1 /* Title */ ) ); 1395 //The temporary folders of user and shared have an '_' at then end. 1396 //But the name in ActivePackages.temporaryName is saved without. 1397 OUString title2 = title; 1398 bool bShared = m_context.equals(OUSTR("shared")); 1399 if (bShared) 1400 { 1401 OSL_ASSERT(title2[title2.getLength() -1] == '_'); 1402 title2 = title2.copy(0, title2.getLength() -1); 1403 } 1404 OUString titleEncoded = ::rtl::Uri::encode( 1405 title2, rtl_UriCharClassPchar, 1406 rtl_UriEncodeIgnoreEscapes, 1407 RTL_TEXTENCODING_UTF8); 1408 1409 //It it sufficient to check for the folder name, because when the administor 1410 //installed the extension it was already checked if there is one with the 1411 //same identifier. 1412 const MatchTempDir match(titleEncoded); 1413 if (::std::find_if( id2temp.begin(), id2temp.end(), match ) == 1414 id2temp.end()) 1415 { 1416 1417 // The folder was not found in the data base, so it must be 1418 // an added extension 1419 OUString url(m_activePackages_expanded + OUSTR("/") + titleEncoded); 1420 OUString sExtFolder; 1421 if (bShared) //that is, shared 1422 { 1423 //Check if the extension was not "deleted" already which is indicated 1424 //by a xxx.tmpremoved file 1425 ::ucbhelper::Content contentRemoved; 1426 if (create_ucb_content(&contentRemoved, url + OUSTR("removed"), 1427 Reference<XCommandEnvironment>(), false)) 1428 continue; 1429 sExtFolder = getExtensionFolder( 1430 m_activePackages_expanded + 1431 OUString(OUSTR("/")) + titleEncoded + OUSTR("_"), xCmdEnv); 1432 url = makeURLAppendSysPathSegment(m_activePackages_expanded, title); 1433 url = makeURLAppendSysPathSegment(url, sExtFolder); 1434 } 1435 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage( 1436 url, OUString(), false, OUString(), xCmdEnv ); 1437 if (xPackage.is()) 1438 { 1439 //Prepare the database entry 1440 ActivePackages::Data dbData; 1441 1442 dbData.temporaryName = titleEncoded; 1443 if (bShared) 1444 dbData.fileName = sExtFolder; 1445 else 1446 dbData.fileName = title; 1447 dbData.mediaType = xPackage->getPackageType()->getMediaType(); 1448 dbData.version = xPackage->getVersion(); 1449 OSL_ENSURE(dbData.version.getLength() > 0, 1450 "Extension Manager: bundled and shared extensions must have " 1451 "an identifier and a version"); 1452 1453 OUString id = dp_misc::getIdentifier( xPackage ); 1454 1455 //We provide a special command environment that will prevent 1456 //showing a license if simple-licens/@accept-by = "admin" 1457 //It will also prevent showing the license for bundled extensions 1458 //which is not supported. 1459 OSL_ASSERT(!m_context.equals(OUSTR("user"))); 1460 1461 // shall the license be suppressed? 1462 DescriptionInfoset info = 1463 dp_misc::getDescriptionInfoset(url); 1464 ::boost::optional<dp_misc::SimpleLicenseAttributes> 1465 attr = info.getSimpleLicenseAttributes(); 1466 ExtensionProperties props(url,xCmdEnv); 1467 bool bNoLicense = false; 1468 if (attr && attr->suppressIfRequired && props.isSuppressedLicense()) 1469 bNoLicense = true; 1470 1471 Reference<ucb::XCommandEnvironment> licCmdEnv( 1472 new LicenseCommandEnv(xCmdEnv->getInteractionHandler(), 1473 bNoLicense, m_context)); 1474 sal_Int32 failedPrereq = xPackage->checkPrerequisites( 1475 xAbortChannel, licCmdEnv, false); 1476 //Remember that this failed. For example, the user 1477 //could have declined the license. Then the next time the 1478 //extension folder is investigated we do not want to 1479 //try to install the extension again. 1480 dbData.failedPrerequisites = OUString::valueOf(failedPrereq); 1481 insertToActivationLayerDB(id, dbData); 1482 bModified |= true; 1483 } 1484 } 1485 } 1486 catch (uno::Exception &) 1487 { 1488 OSL_ASSERT(0); 1489 } 1490 } 1491 return bModified; 1492 } 1493 1494 sal_Bool PackageManagerImpl::synchronize( 1495 Reference<task::XAbortChannel> const & xAbortChannel, 1496 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) 1497 throw (css::deployment::DeploymentException, 1498 css::ucb::CommandFailedException, 1499 css::ucb::CommandAbortedException, 1500 css::uno::RuntimeException) 1501 { 1502 check(); 1503 bool bModified = false; 1504 if (m_context.equals(OUSTR("user"))) 1505 return bModified; 1506 bModified |= 1507 synchronizeRemovedExtensions(xAbortChannel, xCmdEnv); 1508 bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv); 1509 1510 return bModified; 1511 } 1512 1513 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses( 1514 Reference<ucb::XCommandEnvironment> const & xCmdEnv) 1515 throw (deployment::DeploymentException, RuntimeException) 1516 { 1517 ::std::vector<Reference<deployment::XPackage> > vec; 1518 1519 try 1520 { 1521 const ::osl::MutexGuard guard( getMutex() ); 1522 // clean up activation layer, scan for zombie temp dirs: 1523 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); 1524 1525 ActivePackages::Entries::const_iterator i = id2temp.begin(); 1526 bool bShared = m_context.equals(OUSTR("shared")); 1527 1528 for (; i != id2temp.end(); i++ ) 1529 { 1530 //Get the database entry 1531 ActivePackages::Data const & dbData = i->second; 1532 sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32(); 1533 //If the installation failed for other reason then the license then we 1534 //ignore it. 1535 if (failedPrereq ^= deployment::Prerequisites::LICENSE) 1536 continue; 1537 1538 //Prepare the URL to the extension 1539 OUString url = makeURL(m_activePackages, i->second.temporaryName); 1540 if (bShared) 1541 url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName); 1542 1543 Reference<deployment::XPackage> p = m_xRegistry->bindPackage( 1544 url, OUString(), false, OUString(), xCmdEnv ); 1545 1546 if (p.is()) 1547 vec.push_back(p); 1548 1549 } 1550 return ::comphelper::containerToSequence(vec); 1551 } 1552 catch (deployment::DeploymentException &) 1553 { 1554 throw; 1555 } 1556 catch (RuntimeException&) 1557 { 1558 throw; 1559 } 1560 catch (...) 1561 { 1562 Any exc = ::cppu::getCaughtException(); 1563 deployment::DeploymentException de( 1564 OUSTR("PackageManagerImpl::getExtensionsWithUnacceptedLicenses"), 1565 static_cast<OWeakObject*>(this), exc); 1566 exc <<= de; 1567 ::cppu::throwException(exc); 1568 } 1569 1570 return ::comphelper::containerToSequence(vec); 1571 } 1572 1573 sal_Int32 PackageManagerImpl::checkPrerequisites( 1574 css::uno::Reference<css::deployment::XPackage> const & extension, 1575 css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, 1576 css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) 1577 throw (css::deployment::DeploymentException, 1578 css::ucb::CommandFailedException, 1579 css::ucb::CommandAbortedException, 1580 css::lang::IllegalArgumentException, 1581 css::uno::RuntimeException) 1582 { 1583 try 1584 { 1585 if (!extension.is()) 1586 return 0; 1587 if (!m_context.equals(extension->getRepositoryName())) 1588 throw lang::IllegalArgumentException( 1589 OUSTR("PackageManagerImpl::checkPrerequisites: extension is not" 1590 " from this repository."), 0, 0); 1591 1592 ActivePackages::Data dbData; 1593 OUString id = dp_misc::getIdentifier(extension); 1594 if (m_activePackagesDB->get( &dbData, id, OUString())) 1595 { 1596 //If the license was already displayed, then do not show it again 1597 Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv; 1598 sal_Int32 prereq = dbData.failedPrerequisites.toInt32(); 1599 if ( !(prereq & deployment::Prerequisites::LICENSE)) 1600 _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler()); 1601 1602 sal_Int32 failedPrereq = extension->checkPrerequisites( 1603 xAbortChannel, _xCmdEnv, false); 1604 dbData.failedPrerequisites = OUString::valueOf(failedPrereq); 1605 insertToActivationLayerDB(id, dbData); 1606 } 1607 else 1608 { 1609 throw lang::IllegalArgumentException( 1610 OUSTR("PackageManagerImpl::checkPrerequisites: unknown extension"), 1611 0, 0); 1612 1613 } 1614 return 0; 1615 } 1616 catch (deployment::DeploymentException& ) { 1617 throw; 1618 } catch (ucb::CommandFailedException & ) { 1619 throw; 1620 } catch (ucb::CommandAbortedException & ) { 1621 throw; 1622 } catch (lang::IllegalArgumentException &) { 1623 throw; 1624 } catch (uno::RuntimeException &) { 1625 throw; 1626 } catch (...) { 1627 uno::Any excOccurred = ::cppu::getCaughtException(); 1628 deployment::DeploymentException exc( 1629 OUSTR("PackageManagerImpl::checkPrerequisites: exception "), 1630 static_cast<OWeakObject*>(this), excOccurred); 1631 throw exc; 1632 } 1633 } 1634 1635 //############################################################################## 1636 1637 //______________________________________________________________________________ 1638 PackageManagerImpl::CmdEnvWrapperImpl::~CmdEnvWrapperImpl() 1639 { 1640 } 1641 1642 //______________________________________________________________________________ 1643 PackageManagerImpl::CmdEnvWrapperImpl::CmdEnvWrapperImpl( 1644 Reference<XCommandEnvironment> const & xUserCmdEnv, 1645 Reference<XProgressHandler> const & xLogFile ) 1646 : m_xLogFile( xLogFile ) 1647 { 1648 if (xUserCmdEnv.is()) { 1649 m_xUserProgress.set( xUserCmdEnv->getProgressHandler() ); 1650 m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() ); 1651 } 1652 } 1653 1654 // XCommandEnvironment 1655 //______________________________________________________________________________ 1656 Reference<task::XInteractionHandler> 1657 PackageManagerImpl::CmdEnvWrapperImpl::getInteractionHandler() 1658 throw (RuntimeException) 1659 { 1660 return m_xUserInteractionHandler; 1661 } 1662 1663 //______________________________________________________________________________ 1664 Reference<XProgressHandler> 1665 PackageManagerImpl::CmdEnvWrapperImpl::getProgressHandler() 1666 throw (RuntimeException) 1667 { 1668 return this; 1669 } 1670 1671 // XProgressHandler 1672 //______________________________________________________________________________ 1673 void PackageManagerImpl::CmdEnvWrapperImpl::push( Any const & Status ) 1674 throw (RuntimeException) 1675 { 1676 if (m_xLogFile.is()) 1677 m_xLogFile->push( Status ); 1678 if (m_xUserProgress.is()) 1679 m_xUserProgress->push( Status ); 1680 } 1681 1682 //______________________________________________________________________________ 1683 void PackageManagerImpl::CmdEnvWrapperImpl::update( Any const & Status ) 1684 throw (RuntimeException) 1685 { 1686 if (m_xLogFile.is()) 1687 m_xLogFile->update( Status ); 1688 if (m_xUserProgress.is()) 1689 m_xUserProgress->update( Status ); 1690 } 1691 1692 //______________________________________________________________________________ 1693 void PackageManagerImpl::CmdEnvWrapperImpl::pop() throw (RuntimeException) 1694 { 1695 if (m_xLogFile.is()) 1696 m_xLogFile->pop(); 1697 if (m_xUserProgress.is()) 1698 m_xUserProgress->pop(); 1699 } 1700 1701 } // namespace dp_manager 1702 1703