blob: 1e97e396b098e140616e8b973b9029b4c2ed49e3 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"
#include "dp_ucb.h"
#include "dp_resource.h"
#include "dp_platform.hxx"
#include "dp_manager.h"
#include "dp_identifier.hxx"
#include "rtl/ustrbuf.hxx"
#include "rtl/string.hxx"
#include "rtl/uri.hxx"
#include "rtl/bootstrap.hxx"
#include "osl/diagnose.h"
#include "osl/file.hxx"
#include "osl/security.hxx"
#include "cppuhelper/weakref.hxx"
#include "cppuhelper/exc_hlp.hxx"
#include "cppuhelper/implbase1.hxx"
#include "cppuhelper/interfacecontainer.hxx"
#include "comphelper/servicedecl.hxx"
#include "comphelper/sequence.hxx"
#include "xmlscript/xml_helper.hxx"
#include "svl/inettype.hxx"
#include "com/sun/star/lang/DisposedException.hpp"
#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
#include "com/sun/star/beans/UnknownPropertyException.hpp"
#include "com/sun/star/util/XUpdatable.hpp"
#include "com/sun/star/sdbc/XResultSet.hpp"
#include "com/sun/star/sdbc/XRow.hpp"
#include "com/sun/star/ucb/XContentAccess.hpp"
#include "com/sun/star/ucb/NameClash.hpp"
#include "com/sun/star/deployment/VersionException.hpp"
#include "com/sun/star/deployment/InstallException.hpp"
#include "com/sun/star/deployment/Prerequisites.hpp"
#include "com/sun/star/task/XInteractionApprove.hpp"
#include "com/sun/star/ucb/UnsupportedCommandException.hpp"
#include "boost/bind.hpp"
#include "tools/urlobj.hxx"
#include "unotools/tempfile.hxx"
#include "osl/file.hxx"
#include <vector>
#include <list>
#include "dp_descriptioninfoset.hxx"
#include "dp_commandenvironments.hxx"
#include "dp_properties.hxx"
using namespace ::dp_misc;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ucb;
using ::rtl::OUString;
namespace dp_log {
extern comphelper::service_decl::ServiceDecl const serviceDecl;
}
namespace dp_registry {
Reference<deployment::XPackageRegistry> create(
OUString const & context,
OUString const & cachePath, bool readOnly,
Reference<XComponentContext> const & xComponentContext );
}
namespace dp_manager {
struct MatchTempDir
{
OUString m_str;
MatchTempDir( OUString const & str ) : m_str( str ) {}
bool operator () ( ActivePackages::Entries::value_type const & v ) const {
return v.second.temporaryName.equalsIgnoreAsciiCase( m_str );
}
};
namespace {
OUString getExtensionFolder(OUString const & parentFolder,
Reference<ucb::XCommandEnvironment> const & xCmdEnv)
{
::ucbhelper::Content tempFolder(
parentFolder, xCmdEnv );
Reference<sdbc::XResultSet> xResultSet(
tempFolder.createCursor(
Sequence<OUString>( &StrTitle::get(), 1 ),
::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
OUString title;
while (xResultSet->next())
{
title = Reference<sdbc::XRow>(
xResultSet, UNO_QUERY_THROW )->getString(1 /* Title */ ) ;
break;
}
return title;
}
}
//______________________________________________________________________________
void PackageManagerImpl::initActivationLayer(
Reference<XCommandEnvironment> const & xCmdEnv )
{
if (m_activePackages.getLength() == 0)
{
OSL_ASSERT( m_registryCache.getLength() == 0 );
// documents temp activation:
m_activePackagesDB.reset( new ActivePackages );
::ucbhelper::Content ucbContent;
if (create_ucb_content( &ucbContent, m_context, xCmdEnv,
false /* no throw */ ))
{
// scan for all entries in m_packagesDir:
Reference<sdbc::XResultSet> xResultSet(
ucbContent.createCursor(
Sequence<OUString>( &StrTitle::get(), 1 ),
::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
while (xResultSet->next())
{
Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW );
OUString title( xRow->getString( 1 /* Title */ ) );
// xxx todo: remove workaround for tdoc
if (title.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
"this_is_a_dummy_stream_just_there_"
"as_a_workaround_for_a_"
"temporary_limitation_of_the_"
"storage_api_implementation") ))
continue;
if (title.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
"META-INF") ) )
continue;
::ucbhelper::Content sourceContent(
Reference<XContentAccess>(
xResultSet, UNO_QUERY_THROW )->queryContent(),
xCmdEnv );
OUString mediaType( detectMediaType( sourceContent,
false /* no throw */) );
if (mediaType.getLength() >0)
{
ActivePackages::Data dbData;
insertToActivationLayer(
Sequence<css::beans::NamedValue>(),mediaType, sourceContent,
title, &dbData );
insertToActivationLayerDB( title, dbData );
//TODO #i73136#: insertToActivationLayerDB needs id not
// title, but the whole m_activePackages.getLength()==0
// case (i.e., document-relative deployment) currently
// does not work, anyway.
}
}
}
}
else
{
// user|share:
OSL_ASSERT( m_activePackages.getLength() > 0 );
m_activePackages_expanded = expandUnoRcUrl( m_activePackages );
m_registrationData_expanded = expandUnoRcUrl(m_registrationData);
if (!m_readOnly)
create_folder( 0, m_activePackages_expanded, xCmdEnv, true);
OUString dbName;
if (m_context.equals(OUSTR("user")))
dbName = m_activePackages_expanded + OUSTR(".pmap");
else
{
//Create the extension data base in the user installation
create_folder( 0, m_registrationData_expanded, xCmdEnv, true);
dbName = m_registrationData_expanded + OUSTR("/extensions.pmap");
}
//The data base can always be written because it it always in the user installation
m_activePackagesDB.reset(
new ActivePackages( dbName, false ) );
if (! m_readOnly && ! m_context.equals(OUSTR("bundled")))
{
// clean up activation layer, scan for zombie temp dirs:
ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
::ucbhelper::Content tempFolder(
m_activePackages_expanded, xCmdEnv );
Reference<sdbc::XResultSet> xResultSet(
tempFolder.createCursor(
Sequence<OUString>( &StrTitle::get(), 1 ),
::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) );
// get all temp directories:
::std::vector<OUString> tempEntries;
::std::vector<OUString> removedEntries;
while (xResultSet->next())
{
OUString title(
Reference<sdbc::XRow>(
xResultSet, UNO_QUERY_THROW )->getString(
1 /* Title */ ) );
const char extensionRemoved[] = "removed";
if (title.endsWithAsciiL(
extensionRemoved, sizeof(extensionRemoved) - 1))
{
//save the file name withouth the "removed" part
sal_Int32 index = title.lastIndexOfAsciiL(
extensionRemoved, sizeof(extensionRemoved) - 1);
OUString remFile = title.copy(0, index);
removedEntries.push_back(::rtl::Uri::encode(
remFile, rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 ) );
}
else
{
tempEntries.push_back( ::rtl::Uri::encode(
title, rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 ) );
}
}
bool bShared = m_context.equals(OUSTR("shared")) ? true : false;
for ( ::std::size_t pos = 0; pos < tempEntries.size(); ++pos )
{
OUString const & tempEntry = tempEntries[ pos ];
const MatchTempDir match( tempEntry );
if (::std::find_if( id2temp.begin(), id2temp.end(), match ) ==
id2temp.end())
{
const OUString url(
makeURL(m_activePackages_expanded, tempEntry ) );
//In case of shared extensions, new entries are regarded as
//added extensions if there is no xxx.tmpremoved file.
if (bShared)
{
if (::std::find(removedEntries.begin(), removedEntries.end(), tempEntry) ==
removedEntries.end())
{
continue;
}
else
{
//Make sure only the same user removes the extension, who
//previously unregistered it. This is avoid races if multiple instances
//of OOo are running which all have write access to the shared installation.
//For example, a user removes the extension, but keeps OOo
//running. Parts of the extension may still be loaded and used by OOo.
//Therefore the extension is only deleted the next time the extension manager is
//run after restarting OOo. While OOo is still running, another user starts OOo
//which would deleted the extension files. If the same user starts another
//instance of OOo then the lock file will prevent this.
OUString aUserName;
::osl::Security aSecurity;
aSecurity.getUserName( aUserName );
ucbhelper::Content remFileContent(
url + OUSTR("removed"), Reference<XCommandEnvironment>());
::rtl::ByteSequence data = dp_misc::readFile(remFileContent);
::rtl::OString osData(reinterpret_cast<const sal_Char*>(data.getConstArray()),
data.getLength());
OUString sData = ::rtl::OStringToOUString(
osData, RTL_TEXTENCODING_UTF8);
if (!sData.equals(aUserName))
continue;
}
}
// temp entry not needed anymore:
erase_path( url + OUSTR("_"),
Reference<XCommandEnvironment>(),
false /* no throw: ignore errors */ );
erase_path( url, Reference<XCommandEnvironment>(),
false /* no throw: ignore errors */ );
//delete the xxx.tmpremoved file
erase_path(url + OUSTR("removed"),
Reference<XCommandEnvironment>(), false);
}
}
}
}
}
//______________________________________________________________________________
void PackageManagerImpl::initRegistryBackends()
{
if (m_registryCache.getLength() > 0)
create_folder( 0, m_registryCache,
Reference<XCommandEnvironment>(), false);
m_xRegistry.set( ::dp_registry::create(
m_context, m_registryCache, false,
m_xComponentContext ) );
}
//______________________________________________________________________________
Reference<deployment::XPackageManager> PackageManagerImpl::create(
Reference<XComponentContext> const & xComponentContext,
OUString const & context )
{
PackageManagerImpl * that = new PackageManagerImpl(
xComponentContext, context );
Reference<deployment::XPackageManager> xPackageManager( that );
OUString packages, logFile, stampURL;
if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("user") )) {
that->m_activePackages = OUSTR(
"vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages");
that->m_registrationData = OUSTR(
"vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE");
that->m_registryCache = OUSTR(
"vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/registry");
logFile = OUSTR(
"vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/log.txt");
//We use the extension .sys for the file because on Windows Vista a sys
//(as well as exe and dll) file
//will not be written in the VirtualStore. For example if the process has no
//admin right once cannot write to the %programfiles% folder. However, when
//virtualization is used, the file will be written into the VirtualStore and
//it appears as if one could write to %programfiles%. When we test for write
//access to the office/shared folder for shared extensions then this typically
//fails because a normal user typically cannot write to this folder. However,
//using virtualization it appears that he/she can. Then a shared extension can
//be installed but is only visible for the user (because the extension is in
//the virtual store).
stampURL = OUSTR(
"vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/stamp.sys");
}
else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("shared") )) {
that->m_activePackages = OUSTR(
"vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages");
that->m_registrationData = OUSTR(
"vnd.sun.star.expand:$SHARED_EXTENSIONS_USER");
that->m_registryCache = OUSTR(
"vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/registry");
logFile = OUSTR(
"vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/log.txt");
stampURL = OUSTR(
"vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/stamp.sys");
}
else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bundled") )) {
that->m_activePackages = OUSTR(
"vnd.sun.star.expand:$BUNDLED_EXTENSIONS");
that->m_registrationData = OUSTR(
"vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER");
that->m_registryCache = OUSTR(
"vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/registry");
logFile = OUSTR(
"vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/log.txt");
//No stamp file. We assume that bundled is always readonly. It must not be
//modified from ExtensionManager but only by the installer
}
else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bundled_prereg") )) {
//This is a bundled repository but the registration data
//is in the brand layer: share/prereg
//It is special because the registration data are copied at the first startup
//into the user installation. The processed help and xcu files are not
//copied. Instead the backenddb.xml for the help backend references the help
//by using $BUNDLED_EXTENSION_PREREG instead $BUNDLED_EXTENSIONS_USER. The
//configmgr.ini also used $BUNDLED_EXTENSIONS_PREREG to refer to the xcu file
//which contain the replacement for %origin%.
that->m_activePackages = OUSTR(
"vnd.sun.star.expand:$BUNDLED_EXTENSIONS_PREREG");
that->m_registrationData = OUSTR(
"vnd.sun.star.expand:$BUNDLED_EXTENSIONS_PREREG");
that->m_registryCache = OUSTR(
"vnd.sun.star.expand:$BUNDLED_EXTENSIONS_PREREG/registry");
logFile = OUSTR(
"vnd.sun.star.expand:$BUNDLED_EXTENSIONS_PREREG/log.txt");
}
else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("tmp") )) {
that->m_activePackages = OUSTR(
"vnd.sun.star.expand:$TMP_EXTENSIONS/extensions");
that->m_registrationData = OUSTR(
"vnd.sun.star.expand:$TMP_EXTENSIONS");
that->m_registryCache = OUSTR(
"vnd.sun.star.expand:$TMP_EXTENSIONS/registry");
stampURL = OUSTR(
"vnd.sun.star.expand:$TMP_EXTENSIONS/stamp.sys");
}
else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bak") )) {
that->m_activePackages = OUSTR(
"vnd.sun.star.expand:$BAK_EXTENSIONS/extensions");
that->m_registrationData = OUSTR(
"vnd.sun.star.expand:$BAK_EXTENSIONS");
that->m_registryCache = OUSTR(
"vnd.sun.star.expand:$BAK_EXTENSIONS/registry");
stampURL = OUSTR(
"vnd.sun.star.expand:$BAK_EXTENSIONS/stamp.sys");
}
else if (! context.matchAsciiL(
RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:/") )) {
throw lang::IllegalArgumentException(
OUSTR("invalid context given: ") + context,
Reference<XInterface>(), static_cast<sal_Int16>(-1) );
}
Reference<XCommandEnvironment> xCmdEnv;
try {
//There is no stampURL for the bundled folder
if (stampURL.getLength() > 0)
{
#define CURRENT_STAMP "1"
try {
//The osl file API does not allow to find out if one can write
//into a folder. Therefore we try to write a file. Then we delete
//it, so that it does not hinder uninstallation of OOo
// probe writing:
::ucbhelper::Content ucbStamp( stampURL, xCmdEnv );
::rtl::OString stamp(
RTL_CONSTASCII_STRINGPARAM(CURRENT_STAMP) );
Reference<io::XInputStream> xData(
::xmlscript::createInputStream(
::rtl::ByteSequence(
reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
stamp.getLength() ) ) );
ucbStamp.writeStream( xData, true /* replace existing */ );
that->m_readOnly = false;
erase_path( stampURL, xCmdEnv );
}
catch (RuntimeException &) {
try {
erase_path( stampURL, xCmdEnv );
} catch (...)
{
}
throw;
}
catch (Exception &) {
that->m_readOnly = true;
}
}
if (!that->m_readOnly && logFile.getLength() > 0)
{
const Any any_logFile(logFile);
that->m_xLogFile.set(
that->m_xComponentContext->getServiceManager()
->createInstanceWithArgumentsAndContext(
dp_log::serviceDecl.getSupportedServiceNames()[0],
Sequence<Any>( &any_logFile, 1 ),
that->m_xComponentContext ),
UNO_QUERY_THROW );
xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv, that->m_xLogFile ) );
}
that->initRegistryBackends();
that->initActivationLayer( xCmdEnv );
return xPackageManager;
}
catch (RuntimeException &) {
throw;
}
catch (Exception &) {
Any exc( ::cppu::getCaughtException() );
::rtl::OUStringBuffer buf;
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[context=\"") );
buf.append( context );
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
"\"] caught unexpected exception!") );
throw lang::WrappedTargetRuntimeException(
buf.makeStringAndClear(), Reference<XInterface>(), exc );
}
}
//______________________________________________________________________________
PackageManagerImpl::~PackageManagerImpl()
{
}
//______________________________________________________________________________
void PackageManagerImpl::fireModified()
{
::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer(
util::XModifyListener::static_type() );
if (pContainer != 0) {
pContainer->forEach<util::XModifyListener>(
boost::bind(&util::XModifyListener::modified, _1,
lang::EventObject(static_cast<OWeakObject *>(this))) );
}
}
//______________________________________________________________________________
void PackageManagerImpl::disposing()
{
try {
// // xxx todo: guarding?
// ::osl::MutexGuard guard( getMutex() );
try_dispose( m_xLogFile );
m_xLogFile.clear();
try_dispose( m_xRegistry );
m_xRegistry.clear();
m_activePackagesDB.reset(0);
m_xComponentContext.clear();
t_pm_helper::disposing();
}
catch (RuntimeException &) {
throw;
}
catch (Exception &) {
Any exc( ::cppu::getCaughtException() );
throw lang::WrappedTargetRuntimeException(
OUSTR("caught unexpected exception while disposing..."),
static_cast<OWeakObject *>(this), exc );
}
}
// XComponent
//______________________________________________________________________________
void PackageManagerImpl::dispose() throw (RuntimeException)
{
//Do not call check here. We must not throw an exception here if the object
//is being disposed or is already disposed. See com.sun.star.lang.XComponent
WeakComponentImplHelperBase::dispose();
}
//______________________________________________________________________________
void PackageManagerImpl::addEventListener(
Reference<lang::XEventListener> const & xListener ) throw (RuntimeException)
{
//Do not call check here. We must not throw an exception here if the object
//is being disposed or is already disposed. See com.sun.star.lang.XComponent
WeakComponentImplHelperBase::addEventListener( xListener );
}
//______________________________________________________________________________
void PackageManagerImpl::removeEventListener(
Reference<lang::XEventListener> const & xListener ) throw (RuntimeException)
{
//Do not call check here. We must not throw an exception here if the object
//is being disposed or is already disposed. See com.sun.star.lang.XComponent
WeakComponentImplHelperBase::removeEventListener( xListener );
}
// XPackageManager
//______________________________________________________________________________
OUString PackageManagerImpl::getContext() throw (RuntimeException)
{
check();
return m_context;
}
//______________________________________________________________________________
Sequence< Reference<deployment::XPackageTypeInfo> >
PackageManagerImpl::getSupportedPackageTypes() throw (RuntimeException)
{
OSL_ASSERT( m_xRegistry.is() );
return m_xRegistry->getSupportedPackageTypes();
}
//______________________________________________________________________________
Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel()
throw (RuntimeException)
{
check();
return new AbortChannel;
}
// XModifyBroadcaster
//______________________________________________________________________________
void PackageManagerImpl::addModifyListener(
Reference<util::XModifyListener> const & xListener )
throw (RuntimeException)
{
check();
rBHelper.addListener( ::getCppuType( &xListener ), xListener );
}
//______________________________________________________________________________
void PackageManagerImpl::removeModifyListener(
Reference<util::XModifyListener> const & xListener )
throw (RuntimeException)
{
check();
rBHelper.removeListener( ::getCppuType( &xListener ), xListener );
}
//______________________________________________________________________________
OUString PackageManagerImpl::detectMediaType(
::ucbhelper::Content const & ucbContent_, bool throw_exc )
{
::ucbhelper::Content ucbContent(ucbContent_);
OUString url( ucbContent.getURL() );
OUString mediaType;
if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:") ) ||
url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.pkg:") ))
{
try {
ucbContent.getPropertyValue( OUSTR("MediaType") ) >>= mediaType;
}
catch (beans::UnknownPropertyException &) {
}
OSL_ENSURE( mediaType.getLength() > 0, "### no media-type?!" );
}
if (mediaType.getLength() == 0)
{
try {
Reference<deployment::XPackage> xPackage(
m_xRegistry->bindPackage(
url, OUString(), false, OUString(), ucbContent.getCommandEnvironment() ) );
const Reference<deployment::XPackageTypeInfo> xPackageType(
xPackage->getPackageType() );
OSL_ASSERT( xPackageType.is() );
if (xPackageType.is())
mediaType = xPackageType->getMediaType();
}
catch (lang::IllegalArgumentException & exc) {
if (throw_exc)
throw;
(void) exc;
OSL_ENSURE( 0, ::rtl::OUStringToOString(
exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
}
}
return mediaType;
}
//______________________________________________________________________________
OUString PackageManagerImpl::insertToActivationLayer(
Sequence<beans::NamedValue> const & properties,
OUString const & mediaType, ::ucbhelper::Content const & sourceContent_,
OUString const & title, ActivePackages::Data * dbData )
{
::ucbhelper::Content sourceContent(sourceContent_);
Reference<XCommandEnvironment> xCmdEnv(
sourceContent.getCommandEnvironment() );
String baseDir(m_activePackages_expanded);
::utl::TempFile aTemp(&baseDir, sal_False);
OUString tempEntry = aTemp.GetURL();
tempEntry = tempEntry.copy(tempEntry.lastIndexOf('/') + 1);
OUString destFolder = makeURL( m_activePackages, tempEntry);
destFolder += OUSTR("_");
// prepare activation folder:
::ucbhelper::Content destFolderContent;
create_folder( &destFolderContent, destFolder, xCmdEnv );
// copy content into activation temp dir:
if (mediaType.matchIgnoreAsciiCaseAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"application/vnd.sun.star.package-bundle") ) ||
// xxx todo: more sophisticated parsing
mediaType.matchIgnoreAsciiCaseAsciiL(
RTL_CONSTASCII_STRINGPARAM(
"application/vnd.sun.star.legacy-package-bundle") ))
{
// inflate content:
::rtl::OUStringBuffer buf;
if (!sourceContent.isFolder())
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") );
buf.append( ::rtl::Uri::encode( sourceContent.getURL(),
rtl_UriCharClassRegName,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 ) );
}
else
{
//Folder. No need to unzip, just copy
buf.append(sourceContent.getURL());
}
buf.append( static_cast<sal_Unicode>('/') );
sourceContent = ::ucbhelper::Content(
buf.makeStringAndClear(), xCmdEnv );
}
if (! destFolderContent.transferContent(
sourceContent, ::ucbhelper::InsertOperation_COPY,
title, NameClash::OVERWRITE ))
throw RuntimeException( OUSTR("UCB transferContent() failed!"), 0 );
// write to DB:
//bundled extensions should only be added by the synchronizeAddedExtensions
//functions. Moreover, there is no "temporary folder" for bundled extensions.
OSL_ASSERT(!m_context.equals(OUSTR("bundled")));
OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title);
DescriptionInfoset info =
dp_misc::getDescriptionInfoset(sFolderUrl);
dbData->temporaryName = tempEntry;
dbData->fileName = title;
dbData->mediaType = mediaType;
dbData->version = info.getVersion();
//No write the properties file next to the extension
ExtensionProperties props(sFolderUrl, properties, xCmdEnv);
props.write();
return destFolder;
}
//______________________________________________________________________________
void PackageManagerImpl::insertToActivationLayerDB(
OUString const & id, ActivePackages::Data const & dbData )
{
//access to the database must be guarded. See removePackage
const ::osl::MutexGuard guard( getMutex() );
m_activePackagesDB->put( id, dbData );
}
//______________________________________________________________________________
/* The function returns true if there is an extension with the same id already
installed which needs to be uninstalled, before the new extension can be installed.
*/
bool PackageManagerImpl::isInstalled(
Reference<deployment::XPackage> const & package)
{
OUString id(dp_misc::getIdentifier(package));
OUString fn(package->getName());
bool bInstalled = false;
if (m_activePackagesDB->has( id, fn ))
{
bInstalled = true;
}
return bInstalled;
}
// XPackageManager
//______________________________________________________________________________
Reference<deployment::XPackage> PackageManagerImpl::importExtension(
Reference<deployment::XPackage> const & extension,
Reference<task::XAbortChannel> const & xAbortChannel,
Reference<XCommandEnvironment> const & xCmdEnv_ )
throw (deployment::DeploymentException, CommandFailedException,
CommandAbortedException, lang::IllegalArgumentException,
RuntimeException)
{
return addPackage(extension->getURL(), Sequence<beans::NamedValue>(),
OUString(), xAbortChannel, xCmdEnv_);
}
/* The function adds an extension but does not register it!!!
It may not do any user interaction. This is done in XExtensionManager::addExtension
*/
Reference<deployment::XPackage> PackageManagerImpl::addPackage(
OUString const & url,
css::uno::Sequence<css::beans::NamedValue> const & properties,
OUString const & mediaType_,
Reference<task::XAbortChannel> const & xAbortChannel,
Reference<XCommandEnvironment> const & xCmdEnv_ )
throw (deployment::DeploymentException, CommandFailedException,
CommandAbortedException, lang::IllegalArgumentException,
RuntimeException)
{
check();
if (m_readOnly)
{
OUString message;
if (m_context == OUSTR("shared"))
message = OUSTR("You need write permissions to install a shared extension!");
else
message = OUSTR("You need write permissions to install this extension!");
throw deployment::DeploymentException(
message, static_cast<OWeakObject *>(this), Any() );
}
Reference<XCommandEnvironment> xCmdEnv;
if (m_xLogFile.is())
xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
else
xCmdEnv.set( xCmdEnv_ );
try {
::ucbhelper::Content sourceContent;
create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc
const OUString title(sourceContent.getPropertyValue(
StrTitle::get() ).get<OUString>() );
const OUString title_enc( ::rtl::Uri::encode(
title, rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 ) );
OUString destFolder;
OUString mediaType(mediaType_);
if (mediaType.getLength() == 0)
mediaType = detectMediaType( sourceContent );
Reference<deployment::XPackage> xPackage;
// copy file:
progressUpdate(
getResourceString(RID_STR_COPYING_PACKAGE) + title, xCmdEnv );
if (m_activePackages.getLength() == 0)
{
::ucbhelper::Content docFolderContent;
create_folder( &docFolderContent, m_context, xCmdEnv );
// copy into document, first:
if (! docFolderContent.transferContent(
sourceContent, ::ucbhelper::InsertOperation_COPY,
OUString(),
NameClash::ASK /* xxx todo: ASK not needed? */))
throw RuntimeException(
OUSTR("UCB transferContent() failed!"), 0 );
// set media-type:
::ucbhelper::Content docContent(
makeURL( m_context, title_enc ), xCmdEnv );
//TODO #i73136#: using title instead of id can lead to
// clashes, but the whole m_activePackages.getLength()==0
// case (i.e., document-relative deployment) currently does
// not work, anyway.
docContent.setPropertyValue(
OUSTR("MediaType"), Any(mediaType) );
// xxx todo: obsolete in the future
try {
docFolderContent.executeCommand( OUSTR("flush"), Any() );
}
catch (UnsupportedCommandException &) {
}
}
ActivePackages::Data dbData;
destFolder = insertToActivationLayer(
properties, mediaType, sourceContent, title, &dbData );
// bind activation package:
//Because every shared/user extension will be unpacked in a folder,
//which was created with a unique name we will always have two different
//XPackage objects, even if the second extension is the same.
//Therefore bindPackage does not need a guard here.
xPackage = m_xRegistry->bindPackage(
makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv );
OSL_ASSERT( xPackage.is() );
if (xPackage.is())
{
bool install = false;
try
{
OUString const id = dp_misc::getIdentifier( xPackage );
::osl::MutexGuard g(m_addMutex);
if (isInstalled(xPackage))
{
//Do not guard the complete function with the getMutex
removePackage(id, xPackage->getName(), xAbortChannel,
xCmdEnv);
}
install = true;
insertToActivationLayerDB(id, dbData);
}
catch (...)
{
deletePackageFromCache( xPackage, destFolder );
throw;
}
if (!install)
{
deletePackageFromCache( xPackage, destFolder );
}
//ToDo: We should notify only if the extension is registered
fireModified();
}
return xPackage;
}
catch (RuntimeException &) {
throw;
}
catch (CommandFailedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (CommandAbortedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (deployment::DeploymentException & exc) {
logIntern( Any(exc) );
throw;
}
catch (Exception &) {
Any exc( ::cppu::getCaughtException() );
logIntern( exc );
throw deployment::DeploymentException(
getResourceString(RID_STR_ERROR_WHILE_ADDING) + url,
static_cast<OWeakObject *>(this), exc );
}
}
void PackageManagerImpl::deletePackageFromCache(
Reference<deployment::XPackage> const & xPackage,
OUString const & destFolder)
{
try_dispose( xPackage );
//we remove the package from the uno cache
//no service from the package may be loaded at this time!!!
erase_path( destFolder, Reference<XCommandEnvironment>(),
false /* no throw: ignore errors */ );
//rm last character '_'
OUString url = destFolder.copy(0, destFolder.getLength() - 1);
erase_path( url, Reference<XCommandEnvironment>(),
false /* no throw: ignore errors */ );
}
//______________________________________________________________________________
void PackageManagerImpl::removePackage(
OUString const & id, ::rtl::OUString const & fileName,
Reference<task::XAbortChannel> const & /*xAbortChannel*/,
Reference<XCommandEnvironment> const & xCmdEnv_ )
throw (deployment::DeploymentException, CommandFailedException,
CommandAbortedException, lang::IllegalArgumentException,
RuntimeException)
{
check();
Reference<XCommandEnvironment> xCmdEnv;
if (m_xLogFile.is())
xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
else
xCmdEnv.set( xCmdEnv_ );
try {
Reference<deployment::XPackage> xPackage;
{
const ::osl::MutexGuard guard(getMutex());
//Check if this extension exist and throw an IllegalArgumentException
//if it does not
//If the files of the extension are already removed, or there is a
//different extension at the same place, for example after updating the
//extension, then the returned object is that which uses the database data.
xPackage = getDeployedPackage_(id, fileName, xCmdEnv );
//Because the extension is only removed the next time the extension
//manager runs after restarting OOo, we need to indicate that a
//shared extension was "deleted". When a user starts OOo, then it
//will check if something changed in the shared repository. Based on
//the flag file it will then recognize, that the extension was
//deleted and can then update the extnesion database of the shared
//extensions in the user installation.
if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && m_context.equals(OUSTR("shared")))
{
ActivePackages::Data val;
m_activePackagesDB->get( & val, id, fileName);
OSL_ASSERT(val.temporaryName.getLength());
OUString url(makeURL(m_activePackages_expanded,
val.temporaryName + OUSTR("removed")));
::ucbhelper::Content contentRemoved(url, xCmdEnv );
OUString aUserName;
::osl::Security aSecurity;
aSecurity.getUserName( aUserName );
::rtl::OString stamp = ::rtl::OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8);
Reference<css::io::XInputStream> xData(
::xmlscript::createInputStream(
::rtl::ByteSequence(
reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
stamp.getLength() ) ) );
contentRemoved.writeStream( xData, true /* replace existing */ );
}
m_activePackagesDB->erase( id, fileName ); // to be removed upon next start
//remove any cached data hold by the backend
m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType());
}
try_dispose( xPackage );
fireModified();
}
catch (RuntimeException &) {
throw;
}
catch (lang::IllegalArgumentException &) {
throw;
}
catch (CommandFailedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (CommandAbortedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (deployment::DeploymentException & exc) {
logIntern( Any(exc) );
throw;
}
catch (Exception &) {
Any exc( ::cppu::getCaughtException() );
logIntern( exc );
throw deployment::DeploymentException(
getResourceString(RID_STR_ERROR_WHILE_REMOVING) + id,
static_cast<OWeakObject *>(this), exc );
}
}
//______________________________________________________________________________
OUString PackageManagerImpl::getDeployPath( ActivePackages::Data const & data )
{
::rtl::OUStringBuffer buf;
buf.append( data.temporaryName );
//The bundled extensions are not contained in an additional folder
//with a unique name. data.temporaryName contains already the
//UTF8 encoded folder name. See PackageManagerImpl::synchronize
if (!m_context.equals(OUSTR("bundled"))
&& !m_context.equals(OUSTR("bundled_prereg")))
{
buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("_/") );
buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8 ) );
}
return makeURL( m_activePackages, buf.makeStringAndClear() );
}
//______________________________________________________________________________
Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
OUString const & id, OUString const & fileName,
Reference<XCommandEnvironment> const & xCmdEnv )
{
ActivePackages::Data val;
if (m_activePackagesDB->get( &val, id, fileName ))
{
return getDeployedPackage_( id, val, xCmdEnv, false );
}
throw lang::IllegalArgumentException(
getResourceString(RID_STR_NO_SUCH_PACKAGE) + id,
static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
}
//______________________________________________________________________________
Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
OUString const & id, ActivePackages::Data const & data,
Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms )
{
if (ignoreAlienPlatforms)
{
String type, subType;
INetContentTypeParameterList params;
if (INetContentTypes::parse( data.mediaType, type, subType, &params ))
{
INetContentTypeParameter const * param = params.find(
ByteString("platform") );
if (param != 0 && !platform_fits( param->m_sValue ))
throw lang::IllegalArgumentException(
getResourceString(RID_STR_NO_SUCH_PACKAGE) + id,
static_cast<OWeakObject *>(this),
static_cast<sal_Int16>(-1) );
}
}
Reference<deployment::XPackage> xExtension;
try
{
//Ignore extensions where XPackage::checkPrerequisites failed.
//They must not be usable for this user.
if (data.failedPrerequisites.equals(OUSTR("0")))
{
xExtension = m_xRegistry->bindPackage(
getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv );
}
}
catch (deployment::InvalidRemovedParameterException& e)
{
xExtension = e.Extension;
}
return xExtension;
}
//______________________________________________________________________________
Sequence< Reference<deployment::XPackage> >
PackageManagerImpl::getDeployedPackages_(
Reference<XCommandEnvironment> const & xCmdEnv )
{
::std::vector< Reference<deployment::XPackage> > packages;
ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
ActivePackages::Entries::const_iterator iPos( id2temp.begin() );
ActivePackages::Entries::const_iterator const iEnd( id2temp.end() );
for ( ; iPos != iEnd; ++iPos )
{
if (! iPos->second.failedPrerequisites.equals(OUSTR("0")))
continue;
try {
packages.push_back(
getDeployedPackage_(
iPos->first, iPos->second, xCmdEnv,
true /* xxx todo: think of GUI:
ignore other platforms than the current one */ ) );
}
catch (lang::IllegalArgumentException & exc) {
// ignore
(void) exc; // avoid warnings
OSL_ENSURE( 0, ::rtl::OUStringToOString(
exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
}
catch (deployment::DeploymentException& exc) {
// ignore
(void) exc; // avoid warnings
OSL_ENSURE( 0, ::rtl::OUStringToOString(
exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
}
}
return comphelper::containerToSequence(packages);
}
//______________________________________________________________________________
Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage(
OUString const & id, ::rtl::OUString const & fileName,
Reference<XCommandEnvironment> const & xCmdEnv_ )
throw (deployment::DeploymentException, CommandFailedException,
lang::IllegalArgumentException, RuntimeException)
{
check();
Reference<XCommandEnvironment> xCmdEnv;
if (m_xLogFile.is())
xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
else
xCmdEnv.set( xCmdEnv_ );
try {
const ::osl::MutexGuard guard( getMutex() );
return getDeployedPackage_( id, fileName, xCmdEnv );
}
catch (RuntimeException &) {
throw;
}
catch (CommandFailedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (lang::IllegalArgumentException & exc) {
logIntern( Any(exc) );
throw;
}
catch (deployment::DeploymentException & exc) {
logIntern( Any(exc) );
throw;
}
catch (Exception &) {
Any exc( ::cppu::getCaughtException() );
logIntern( exc );
throw deployment::DeploymentException(
// ought never occur...
OUSTR("error while accessing deployed package: ") + id,
static_cast<OWeakObject *>(this), exc );
}
}
//______________________________________________________________________________
Sequence< Reference<deployment::XPackage> >
PackageManagerImpl::getDeployedPackages(
Reference<task::XAbortChannel> const &,
Reference<XCommandEnvironment> const & xCmdEnv_ )
throw (deployment::DeploymentException, CommandFailedException,
CommandAbortedException, lang::IllegalArgumentException,
RuntimeException)
{
check();
Reference<XCommandEnvironment> xCmdEnv;
if (m_xLogFile.is())
xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
else
xCmdEnv.set( xCmdEnv_ );
try {
const ::osl::MutexGuard guard( getMutex() );
return getDeployedPackages_( xCmdEnv );
}
catch (RuntimeException &) {
throw;
}
catch (CommandFailedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (CommandAbortedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (deployment::DeploymentException & exc) {
logIntern( Any(exc) );
throw;
}
catch (Exception &) {
Any exc( ::cppu::getCaughtException() );
logIntern( exc );
throw deployment::DeploymentException(
// ought never occur...
OUSTR("error while getting all deployed packages: ") + m_context,
static_cast<OWeakObject *>(this), exc );
}
}
//______________________________________________________________________________
//ToDo: the function must not call registerPackage, do this in
//XExtensionManager.reinstallDeployedExtensions
void PackageManagerImpl::reinstallDeployedPackages(
Reference<task::XAbortChannel> const & /*xAbortChannel*/,
Reference<XCommandEnvironment> const & xCmdEnv_ )
throw (deployment::DeploymentException,
CommandFailedException, CommandAbortedException,
lang::IllegalArgumentException, RuntimeException)
{
check();
if (office_is_running())
throw RuntimeException(
OUSTR("You must close any running Office process before "
"reinstalling packages!"), static_cast<OWeakObject *>(this) );
Reference<XCommandEnvironment> xCmdEnv;
if (m_xLogFile.is())
xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
else
xCmdEnv.set( xCmdEnv_ );
try {
ProgressLevel progress(
xCmdEnv, OUSTR("Reinstalling all deployed packages...") );
try_dispose( m_xRegistry );
m_xRegistry.clear();
if (m_registryCache.getLength() > 0)
erase_path( m_registryCache, xCmdEnv );
initRegistryBackends();
Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
if (xUpdatable.is())
xUpdatable->update();
//registering is done by the ExtensionManager service.
}
catch (RuntimeException &) {
throw;
}
catch (CommandFailedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (CommandAbortedException & exc) {
logIntern( Any(exc) );
throw;
}
catch (deployment::DeploymentException & exc) {
logIntern( Any(exc) );
throw;
}
catch (Exception &) {
Any exc( ::cppu::getCaughtException() );
logIntern( exc );
throw deployment::DeploymentException(
OUSTR("Error while reinstalling all previously deployed "
"packages of context ") + m_context,
static_cast<OWeakObject *>(this), exc );
}
}
::sal_Bool SAL_CALL PackageManagerImpl::isReadOnly( )
throw (::com::sun::star::uno::RuntimeException)
{
return m_readOnly;
}
bool PackageManagerImpl::synchronizeRemovedExtensions(
Reference<task::XAbortChannel> const & xAbortChannel,
Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
{
//find all which are in the extension data base but which
//are removed already.
OSL_ASSERT(!m_context.equals(OUSTR("user")));
bool bModified = false;
ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
typedef ActivePackages::Entries::const_iterator ITActive;
bool bShared = m_context.equals(OUSTR("shared"));
for (ITActive i = id2temp.begin(); i != id2temp.end(); i++)
{
try
{
//Get the URL to the extensions folder, first make the url for the
//shared repository including the temporary name
OUString url = makeURL(m_activePackages, i->second.temporaryName);
if (bShared)
url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName);
bool bRemoved = false;
//Check if the URL to the extension is still the same
::ucbhelper::Content contentExtension;
if (!create_ucb_content(
&contentExtension, url,
Reference<XCommandEnvironment>(), false))
{
bRemoved = true;
}
//The folder is in the extension database, but it can still be deleted.
//look for the xxx.tmpremoved file
//There can also be the case that a different extension was installed
//in a "temp" folder with name that is already used.
if (!bRemoved && bShared)
{
::ucbhelper::Content contentRemoved;
if (create_ucb_content(
&contentRemoved,
m_activePackages_expanded + OUSTR("/") +
i->second.temporaryName + OUSTR("removed"),
Reference<XCommandEnvironment>(), false))
{
bRemoved = true;
}
}
if (!bRemoved)
{
//There may be another extensions at the same place
dp_misc::DescriptionInfoset infoset =
dp_misc::getDescriptionInfoset(url);
OSL_ENSURE(infoset.hasDescription(),
"Extension Manager: bundled and shared extensions "
"must have an identifer and a version");
if (infoset.hasDescription() &&
infoset.getIdentifier() &&
(! i->first.equals(*(infoset.getIdentifier()))
|| ! i->second.version.equals(infoset.getVersion())))
{
bRemoved = true;
}
}
if (bRemoved)
{
Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
url, i->second.mediaType, true, i->first, xCmdEnv );
OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
xPackage->revokePackage(xAbortChannel, xCmdEnv);
removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
xAbortChannel, xCmdEnv);
bModified |= true;
}
}
catch( uno::Exception & )
{
OSL_ASSERT(0);
}
}
return bModified;
}
bool PackageManagerImpl::synchronizeAddedExtensions(
Reference<task::XAbortChannel> const & xAbortChannel,
Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
{
bool bModified = false;
OSL_ASSERT(!m_context.equals(OUSTR("user")));
ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
//check if the folder exist at all. The shared extension folder
//may not exist for a normal user.
if (!create_ucb_content(
NULL, m_activePackages_expanded, Reference<css::ucb::XCommandEnvironment>(), false))
return bModified;
::ucbhelper::Content tempFolder(
m_activePackages_expanded, xCmdEnv );
Reference<sdbc::XResultSet> xResultSet(
tempFolder.createCursor(
Sequence<OUString>( &StrTitle::get(), 1 ),
::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
while (xResultSet->next())
{
try
{
OUString title(
Reference<sdbc::XRow>(
xResultSet, UNO_QUERY_THROW )->getString(
1 /* Title */ ) );
//The temporary folders of user and shared have an '_' at then end.
//But the name in ActivePackages.temporaryName is saved without.
OUString title2 = title;
bool bShared = m_context.equals(OUSTR("shared"));
if (bShared)
{
OSL_ASSERT(title2[title2.getLength() -1] == '_');
title2 = title2.copy(0, title2.getLength() -1);
}
OUString titleEncoded = ::rtl::Uri::encode(
title2, rtl_UriCharClassPchar,
rtl_UriEncodeIgnoreEscapes,
RTL_TEXTENCODING_UTF8);
//It it sufficient to check for the folder name, because when the administor
//installed the extension it was already checked if there is one with the
//same identifier.
const MatchTempDir match(titleEncoded);
if (::std::find_if( id2temp.begin(), id2temp.end(), match ) ==
id2temp.end())
{
// The folder was not found in the data base, so it must be
// an added extension
OUString url(m_activePackages_expanded + OUSTR("/") + titleEncoded);
OUString sExtFolder;
if (bShared) //that is, shared
{
//Check if the extension was not "deleted" already which is indicated
//by a xxx.tmpremoved file
::ucbhelper::Content contentRemoved;
if (create_ucb_content(&contentRemoved, url + OUSTR("removed"),
Reference<XCommandEnvironment>(), false))
continue;
sExtFolder = getExtensionFolder(
m_activePackages_expanded +
OUString(OUSTR("/")) + titleEncoded + OUSTR("_"), xCmdEnv);
url = makeURLAppendSysPathSegment(m_activePackages_expanded, title);
url = makeURLAppendSysPathSegment(url, sExtFolder);
}
Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
url, OUString(), false, OUString(), xCmdEnv );
if (xPackage.is())
{
//Prepare the database entry
ActivePackages::Data dbData;
dbData.temporaryName = titleEncoded;
if (bShared)
dbData.fileName = sExtFolder;
else
dbData.fileName = title;
dbData.mediaType = xPackage->getPackageType()->getMediaType();
dbData.version = xPackage->getVersion();
OSL_ENSURE(dbData.version.getLength() > 0,
"Extension Manager: bundled and shared extensions must have "
"an identifier and a version");
OUString id = dp_misc::getIdentifier( xPackage );
//We provide a special command environment that will prevent
//showing a license if simple-licens/@accept-by = "admin"
//It will also prevent showing the license for bundled extensions
//which is not supported.
OSL_ASSERT(!m_context.equals(OUSTR("user")));
// shall the license be suppressed?
DescriptionInfoset info =
dp_misc::getDescriptionInfoset(url);
::boost::optional<dp_misc::SimpleLicenseAttributes>
attr = info.getSimpleLicenseAttributes();
ExtensionProperties props(url,xCmdEnv);
bool bNoLicense = false;
if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
bNoLicense = true;
Reference<ucb::XCommandEnvironment> licCmdEnv(
new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
bNoLicense, m_context));
sal_Int32 failedPrereq = xPackage->checkPrerequisites(
xAbortChannel, licCmdEnv, false);
//Remember that this failed. For example, the user
//could have declined the license. Then the next time the
//extension folder is investigated we do not want to
//try to install the extension again.
dbData.failedPrerequisites = OUString::valueOf(failedPrereq);
insertToActivationLayerDB(id, dbData);
bModified |= true;
}
}
}
catch (uno::Exception &)
{
// Looks like exceptions being caught here is not an
// uncommon case.
OSL_TRACE("caught exception in PackageManagerImpl::synchronizeAddedExtensions");
}
}
return bModified;
}
sal_Bool PackageManagerImpl::synchronize(
Reference<task::XAbortChannel> const & xAbortChannel,
Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
throw (css::deployment::DeploymentException,
css::ucb::CommandFailedException,
css::ucb::CommandAbortedException,
css::uno::RuntimeException)
{
check();
bool bModified = false;
if (m_context.equals(OUSTR("user")))
return bModified;
bModified |=
synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
return bModified;
}
Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
Reference<ucb::XCommandEnvironment> const & xCmdEnv)
throw (deployment::DeploymentException, RuntimeException)
{
::std::vector<Reference<deployment::XPackage> > vec;
try
{
const ::osl::MutexGuard guard( getMutex() );
// clean up activation layer, scan for zombie temp dirs:
ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
ActivePackages::Entries::const_iterator i = id2temp.begin();
bool bShared = m_context.equals(OUSTR("shared"));
for (; i != id2temp.end(); i++ )
{
//Get the database entry
ActivePackages::Data const & dbData = i->second;
sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
//If the installation failed for other reason then the license then we
//ignore it.
if (failedPrereq ^= deployment::Prerequisites::LICENSE)
continue;
//Prepare the URL to the extension
OUString url = makeURL(m_activePackages, i->second.temporaryName);
if (bShared)
url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName);
Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
url, OUString(), false, OUString(), xCmdEnv );
if (p.is())
vec.push_back(p);
}
return ::comphelper::containerToSequence(vec);
}
catch (deployment::DeploymentException &)
{
throw;
}
catch (RuntimeException&)
{
throw;
}
catch (...)
{
Any exc = ::cppu::getCaughtException();
deployment::DeploymentException de(
OUSTR("PackageManagerImpl::getExtensionsWithUnacceptedLicenses"),
static_cast<OWeakObject*>(this), exc);
exc <<= de;
::cppu::throwException(exc);
}
return ::comphelper::containerToSequence(vec);
}
sal_Int32 PackageManagerImpl::checkPrerequisites(
css::uno::Reference<css::deployment::XPackage> const & extension,
css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
throw (css::deployment::DeploymentException,
css::ucb::CommandFailedException,
css::ucb::CommandAbortedException,
css::lang::IllegalArgumentException,
css::uno::RuntimeException)
{
try
{
if (!extension.is())
return 0;
if (!m_context.equals(extension->getRepositoryName()))
throw lang::IllegalArgumentException(
OUSTR("PackageManagerImpl::checkPrerequisites: extension is not"
" from this repository."), 0, 0);
ActivePackages::Data dbData;
OUString id = dp_misc::getIdentifier(extension);
if (m_activePackagesDB->get( &dbData, id, OUString()))
{
//If the license was already displayed, then do not show it again
Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
if ( !(prereq & deployment::Prerequisites::LICENSE))
_xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
sal_Int32 failedPrereq = extension->checkPrerequisites(
xAbortChannel, _xCmdEnv, false);
dbData.failedPrerequisites = OUString::valueOf(failedPrereq);
insertToActivationLayerDB(id, dbData);
}
else
{
throw lang::IllegalArgumentException(
OUSTR("PackageManagerImpl::checkPrerequisites: unknown extension"),
0, 0);
}
return 0;
}
catch (deployment::DeploymentException& ) {
throw;
} catch (ucb::CommandFailedException & ) {
throw;
} catch (ucb::CommandAbortedException & ) {
throw;
} catch (lang::IllegalArgumentException &) {
throw;
} catch (uno::RuntimeException &) {
throw;
} catch (...) {
uno::Any excOccurred = ::cppu::getCaughtException();
deployment::DeploymentException exc(
OUSTR("PackageManagerImpl::checkPrerequisites: exception "),
static_cast<OWeakObject*>(this), excOccurred);
throw exc;
}
}
//##############################################################################
//______________________________________________________________________________
PackageManagerImpl::CmdEnvWrapperImpl::~CmdEnvWrapperImpl()
{
}
//______________________________________________________________________________
PackageManagerImpl::CmdEnvWrapperImpl::CmdEnvWrapperImpl(
Reference<XCommandEnvironment> const & xUserCmdEnv,
Reference<XProgressHandler> const & xLogFile )
: m_xLogFile( xLogFile )
{
if (xUserCmdEnv.is()) {
m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
}
}
// XCommandEnvironment
//______________________________________________________________________________
Reference<task::XInteractionHandler>
PackageManagerImpl::CmdEnvWrapperImpl::getInteractionHandler()
throw (RuntimeException)
{
return m_xUserInteractionHandler;
}
//______________________________________________________________________________
Reference<XProgressHandler>
PackageManagerImpl::CmdEnvWrapperImpl::getProgressHandler()
throw (RuntimeException)
{
return this;
}
// XProgressHandler
//______________________________________________________________________________
void PackageManagerImpl::CmdEnvWrapperImpl::push( Any const & Status )
throw (RuntimeException)
{
if (m_xLogFile.is())
m_xLogFile->push( Status );
if (m_xUserProgress.is())
m_xUserProgress->push( Status );
}
//______________________________________________________________________________
void PackageManagerImpl::CmdEnvWrapperImpl::update( Any const & Status )
throw (RuntimeException)
{
if (m_xLogFile.is())
m_xLogFile->update( Status );
if (m_xUserProgress.is())
m_xUserProgress->update( Status );
}
//______________________________________________________________________________
void PackageManagerImpl::CmdEnvWrapperImpl::pop() throw (RuntimeException)
{
if (m_xLogFile.is())
m_xLogFile->pop();
if (m_xUserProgress.is())
m_xUserProgress->pop();
}
} // namespace dp_manager