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