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