update credits
[LibreOffice.git] / desktop / source / deployment / manager / dp_manager.cxx
blob5bf0c91279f13342ca2fd20a3bc3061775b6f823
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "dp_ucb.h"
22 #include "dp_resource.h"
23 #include "dp_platform.hxx"
24 #include "dp_manager.h"
25 #include "dp_identifier.hxx"
26 #include "rtl/ustrbuf.hxx"
27 #include "rtl/string.hxx"
28 #include "rtl/uri.hxx"
29 #include "rtl/bootstrap.hxx"
30 #include "osl/diagnose.h"
31 #include "osl/file.hxx"
32 #include "osl/security.hxx"
33 #include "cppuhelper/weakref.hxx"
34 #include "cppuhelper/exc_hlp.hxx"
35 #include "cppuhelper/implbase1.hxx"
36 #include "cppuhelper/interfacecontainer.hxx"
37 #include "comphelper/servicedecl.hxx"
38 #include "comphelper/sequence.hxx"
39 #include "xmlscript/xml_helper.hxx"
40 #include "svl/inettype.hxx"
41 #include "com/sun/star/lang/DisposedException.hpp"
42 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
43 #include "com/sun/star/beans/UnknownPropertyException.hpp"
44 #include "com/sun/star/util/XUpdatable.hpp"
45 #include "com/sun/star/sdbc/XResultSet.hpp"
46 #include "com/sun/star/sdbc/XRow.hpp"
47 #include "com/sun/star/ucb/XContentAccess.hpp"
48 #include "com/sun/star/ucb/NameClash.hpp"
49 #include "com/sun/star/deployment/VersionException.hpp"
50 #include "com/sun/star/deployment/InstallException.hpp"
51 #include "com/sun/star/deployment/Prerequisites.hpp"
52 #include "com/sun/star/task/XInteractionApprove.hpp"
53 #include "com/sun/star/ucb/UnsupportedCommandException.hpp"
54 #include "boost/bind.hpp"
55 #include "unotools/tempfile.hxx"
57 #include <vector>
58 #include <list>
59 #include "dp_descriptioninfoset.hxx"
60 #include "dp_commandenvironments.hxx"
61 #include "dp_properties.hxx"
63 using namespace ::dp_misc;
64 using namespace ::com::sun::star;
65 using namespace ::com::sun::star::uno;
66 using namespace ::com::sun::star::ucb;
68 namespace dp_log {
69 extern comphelper::service_decl::ServiceDecl const serviceDecl;
72 namespace dp_registry {
73 Reference<deployment::XPackageRegistry> create(
74 OUString const & context,
75 OUString const & cachePath, bool readOnly,
76 Reference<XComponentContext> const & xComponentContext );
79 namespace dp_manager {
81 struct MatchTempDir
83 OUString m_str;
84 MatchTempDir( OUString const & str ) : m_str( str ) {}
85 bool operator () ( ActivePackages::Entries::value_type const & v ) const {
86 return v.second.temporaryName.equalsIgnoreAsciiCase( m_str );
91 namespace {
92 OUString getExtensionFolder(OUString const & parentFolder,
93 Reference<ucb::XCommandEnvironment> const & xCmdEnv,
94 Reference<uno::XComponentContext> const & xContext)
96 ::ucbhelper::Content tempFolder( parentFolder, xCmdEnv, xContext );
97 Reference<sdbc::XResultSet> xResultSet(
98 StrTitle::createCursor (tempFolder, ::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
100 OUString title;
101 while (xResultSet->next())
103 title = Reference<sdbc::XRow>(
104 xResultSet, UNO_QUERY_THROW )->getString(1 /* Title */ ) ;
105 break;
107 return title;
110 //______________________________________________________________________________
111 void PackageManagerImpl::initActivationLayer(
112 Reference<XCommandEnvironment> const & xCmdEnv )
114 if (m_activePackages.isEmpty())
116 OSL_ASSERT( m_registryCache.isEmpty() );
117 // documents temp activation:
118 m_activePackagesDB.reset( new ActivePackages );
119 ::ucbhelper::Content ucbContent;
120 if (create_ucb_content( &ucbContent, m_context, xCmdEnv,
121 false /* no throw */ ))
123 // scan for all entries in m_packagesDir:
124 Reference<sdbc::XResultSet> xResultSet(
125 StrTitle::createCursor (ucbContent, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
127 while (xResultSet->next())
129 Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW );
130 OUString title( xRow->getString( 1 /* Title */ ) );
131 // xxx todo: remove workaround for tdoc
132 if ( title == "this_is_a_dummy_stream_just_there_as_a_workaround_for_a_temporary_limitation_of_the_storage_api_implementation" )
133 continue;
134 if ( title == "META-INF" )
135 continue;
137 ::ucbhelper::Content sourceContent(
138 Reference<XContentAccess>(
139 xResultSet, UNO_QUERY_THROW )->queryContent(),
140 xCmdEnv, m_xComponentContext );
142 OUString mediaType( detectMediaType( sourceContent,
143 false /* no throw */) );
144 if (!mediaType.isEmpty())
146 ActivePackages::Data dbData;
147 insertToActivationLayer(
148 Sequence<css::beans::NamedValue>(),mediaType, sourceContent,
149 title, &dbData );
151 insertToActivationLayerDB( title, dbData );
152 //TODO #i73136#: insertToActivationLayerDB needs id not
153 // title, but the whole m_activePackages.getLength()==0
154 // case (i.e., document-relative deployment) currently
155 // does not work, anyway.
160 else
162 // user|share:
163 OSL_ASSERT( !m_activePackages.isEmpty() );
164 m_activePackages_expanded = expandUnoRcUrl( m_activePackages );
165 m_registrationData_expanded = expandUnoRcUrl(m_registrationData);
166 if (!m_readOnly)
167 create_folder( 0, m_activePackages_expanded, xCmdEnv, true);
169 OUString dbName;
170 if (m_context == "user")
171 dbName = m_activePackages_expanded + ".pmap";
172 else
174 // Create the extension data base in the user installation
175 create_folder( 0, m_registrationData_expanded, xCmdEnv, true);
176 dbName = m_registrationData_expanded + "/extensions.pmap";
178 // The data base can always be written because it it always in the user installation
179 m_activePackagesDB.reset( new ActivePackages( dbName, false ) );
181 if (! m_readOnly && ! (m_context == "bundled"))
183 // clean up activation layer, scan for zombie temp dirs:
184 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
186 ::ucbhelper::Content tempFolder( m_activePackages_expanded, xCmdEnv, m_xComponentContext );
187 Reference<sdbc::XResultSet> xResultSet(
188 StrTitle::createCursor (tempFolder,
189 ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) );
191 // get all temp directories:
192 ::std::vector<OUString> tempEntries;
193 ::std::vector<OUString> removedEntries;
194 while (xResultSet->next())
196 OUString title(
197 Reference<sdbc::XRow>(
198 xResultSet, UNO_QUERY_THROW )->getString(
199 1 /* Title */ ) );
201 const char extensionRemoved[] = "removed";
202 if (title.endsWith( extensionRemoved ))
204 //save the file name withouth the "removed" part
205 sal_Int32 index = title.lastIndexOfAsciiL(
206 extensionRemoved, sizeof(extensionRemoved) - 1);
207 OUString remFile = title.copy(0, index);
208 removedEntries.push_back(::rtl::Uri::encode(
209 remFile, rtl_UriCharClassPchar,
210 rtl_UriEncodeIgnoreEscapes,
211 RTL_TEXTENCODING_UTF8 ) );
213 else
215 tempEntries.push_back( ::rtl::Uri::encode(
216 title, rtl_UriCharClassPchar,
217 rtl_UriEncodeIgnoreEscapes,
218 RTL_TEXTENCODING_UTF8 ) );
222 bool bShared = (m_context == "shared") ? true : false;
223 for ( ::std::size_t pos = 0; pos < tempEntries.size(); ++pos )
225 OUString const & tempEntry = tempEntries[ pos ];
226 const MatchTempDir match( tempEntry );
227 if (::std::find_if( id2temp.begin(), id2temp.end(), match ) ==
228 id2temp.end())
230 const OUString url(
231 makeURL(m_activePackages_expanded, tempEntry ) );
233 //In case of shared extensions, new entries are regarded as
234 //added extensions if there is no xxx.tmpremoved file.
235 if (bShared)
237 if (::std::find(removedEntries.begin(), removedEntries.end(), tempEntry) ==
238 removedEntries.end())
240 continue;
242 else
244 //Make sure only the same user removes the extension, who
245 //previously unregistered it. This is avoid races if multiple instances
246 //of OOo are running which all have write access to the shared installation.
247 //For example, a user removes the extension, but keeps OOo
248 //running. Parts of the extension may still be loaded and used by OOo.
249 //Therefore the extension is only deleted the next time the extension manager is
250 //run after restarting OOo. While OOo is still running, another user starts OOo
251 //which would deleted the extension files. If the same user starts another
252 //instance of OOo then the lock file will prevent this.
253 OUString aUserName;
254 ::osl::Security aSecurity;
255 aSecurity.getUserName( aUserName );
256 ucbhelper::Content remFileContent(
257 url + "removed", Reference<XCommandEnvironment>(), m_xComponentContext);
258 ::rtl::ByteSequence data = dp_misc::readFile(remFileContent);
259 OString osData(reinterpret_cast<const sal_Char*>(data.getConstArray()),
260 data.getLength());
261 OUString sData = OStringToOUString(
262 osData, RTL_TEXTENCODING_UTF8);
263 if (!sData.equals(aUserName))
264 continue;
267 // temp entry not needed anymore:
268 erase_path( url + "_",
269 Reference<XCommandEnvironment>(),
270 false /* no throw: ignore errors */ );
271 erase_path( url, Reference<XCommandEnvironment>(),
272 false /* no throw: ignore errors */ );
273 //delete the xxx.tmpremoved file
274 erase_path(url + "removed",
275 Reference<XCommandEnvironment>(), false);
282 //______________________________________________________________________________
283 void PackageManagerImpl::initRegistryBackends()
285 if (!m_registryCache.isEmpty())
286 create_folder( 0, m_registryCache,
287 Reference<XCommandEnvironment>(), false);
288 m_xRegistry.set( ::dp_registry::create(
289 m_context, m_registryCache, false,
290 m_xComponentContext ) );
293 // this overcomes previous rumours that the sal API is misleading
294 // as to whether a directory is truly read-only or not
295 static bool isMacroURLReadOnly( const OUString &rMacro )
297 OUString aDirURL( rMacro );
298 ::rtl::Bootstrap::expandMacros( aDirURL );
300 ::osl::FileBase::RC aErr = ::osl::Directory::create( aDirURL );
301 if ( aErr == ::osl::FileBase::E_None )
302 return false; // it will be writeable
303 if ( aErr != ::osl::FileBase::E_EXIST )
304 return true; // some serious problem creating it
306 bool bError;
307 sal_uInt64 nWritten = 0;
308 OUString aFileURL( aDirURL + "/stamp.sys" );
309 ::osl::File aFile( aFileURL );
311 bError = aFile.open( osl_File_OpenFlag_Read |
312 osl_File_OpenFlag_Write |
313 osl_File_OpenFlag_Create ) != ::osl::FileBase::E_None;
314 if (!bError)
315 bError = aFile.write( "1", 1, nWritten ) != ::osl::FileBase::E_None;
316 if (aFile.close() != ::osl::FileBase::E_None)
317 bError = true;
318 if (osl::File::remove( aFileURL ) != ::osl::FileBase::E_None)
319 bError = true;
321 SAL_INFO(
322 "desktop.deployment",
323 "local url '" << rMacro << "' -> '" << aFileURL << "' "
324 << (bError ? "is" : "is not") << " readonly\n");
325 return bError;
328 //______________________________________________________________________________
329 Reference<deployment::XPackageManager> PackageManagerImpl::create(
330 Reference<XComponentContext> const & xComponentContext,
331 OUString const & context )
333 PackageManagerImpl * that = new PackageManagerImpl(
334 xComponentContext, context );
335 Reference<deployment::XPackageManager> xPackageManager( that );
337 OUString logFile, stamp;
338 if ( context == "user" ) {
339 that->m_activePackages = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages";
340 that->m_registrationData = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE";
341 that->m_registryCache = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/registry";
342 logFile = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/log.txt";
343 //We use the extension .sys for the file because on Windows Vista a sys
344 //(as well as exe and dll) file
345 //will not be written in the VirtualStore. For example if the process has no
346 //admin right once cannot write to the %programfiles% folder. However, when
347 //virtualization is used, the file will be written into the VirtualStore and
348 //it appears as if one could write to %programfiles%. When we test for write
349 //access to the office/shared folder for shared extensions then this typically
350 //fails because a normal user typically cannot write to this folder. However,
351 //using virtualization it appears that he/she can. Then a shared extension can
352 //be installed but is only visible for the user (because the extension is in
353 //the virtual store).
354 stamp = "$UNO_USER_PACKAGES_CACHE";
356 else if ( context == "shared" ) {
357 that->m_activePackages = "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages";
358 that->m_registrationData = "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER";
359 that->m_registryCache = "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/registry";
360 logFile = "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/log.txt";
361 stamp = "$UNO_SHARED_PACKAGES_CACHE";
363 else if ( context == "bundled" ) {
364 that->m_activePackages = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS";
365 that->m_registrationData = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER";
366 that->m_registryCache = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/registry";
367 logFile = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/log.txt";
368 //No stamp file. We assume that bundled is always readonly. It must not be
369 //modified from ExtensionManager but only by the installer
371 else if ( context == "tmp" ) {
372 that->m_activePackages = "vnd.sun.star.expand:$TMP_EXTENSIONS/extensions";
373 that->m_registrationData = "vnd.sun.star.expand:$TMP_EXTENSIONS";
374 that->m_registryCache = "vnd.sun.star.expand:$TMP_EXTENSIONS/registry";
375 stamp = "$TMP_EXTENSIONS";
377 else if (context == "bak") {
378 that->m_activePackages = "vnd.sun.star.expand:$BAK_EXTENSIONS/extensions";
379 that->m_registrationData = "vnd.sun.star.expand:$BAK_EXTENSIONS";
380 that->m_registryCache = "vnd.sun.star.expand:$BAK_EXTENSIONS/registry";
381 stamp = "$BAK_EXTENSIONS";
384 else if (! context.match("vnd.sun.star.tdoc:/")) {
385 throw lang::IllegalArgumentException(
386 "invalid context given: " + context,
387 Reference<XInterface>(), static_cast<sal_Int16>(-1) );
390 Reference<XCommandEnvironment> xCmdEnv;
392 try {
393 // There is no stamp for the bundled folder:
394 if (!stamp.isEmpty())
395 that->m_readOnly = isMacroURLReadOnly( stamp );
397 if (!that->m_readOnly && !logFile.isEmpty())
399 const Any any_logFile(logFile);
400 that->m_xLogFile.set(
401 that->m_xComponentContext->getServiceManager()
402 ->createInstanceWithArgumentsAndContext(
403 dp_log::serviceDecl.getSupportedServiceNames()[0],
404 Sequence<Any>( &any_logFile, 1 ),
405 that->m_xComponentContext ),
406 UNO_QUERY_THROW );
407 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv, that->m_xLogFile ) );
410 that->initRegistryBackends();
411 that->initActivationLayer( xCmdEnv );
413 return xPackageManager;
416 catch (const RuntimeException &) {
417 throw;
419 catch (const Exception & e) {
420 Any exc( ::cppu::getCaughtException() );
421 throw lang::WrappedTargetRuntimeException(
422 ("[context=\"" + context + "\"] caught unexpected "
423 + exc.getValueType().getTypeName() + ": " + e.Message),
424 Reference<XInterface>(), exc );
428 //______________________________________________________________________________
429 PackageManagerImpl::~PackageManagerImpl()
433 //______________________________________________________________________________
434 void PackageManagerImpl::fireModified()
436 ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer(
437 util::XModifyListener::static_type() );
438 if (pContainer != 0) {
439 pContainer->forEach<util::XModifyListener>(
440 boost::bind(&util::XModifyListener::modified, _1,
441 lang::EventObject(static_cast<OWeakObject *>(this))) );
445 //______________________________________________________________________________
446 void PackageManagerImpl::disposing()
448 try {
449 // // xxx todo: guarding?
450 // ::osl::MutexGuard guard( getMutex() );
451 try_dispose( m_xLogFile );
452 m_xLogFile.clear();
453 try_dispose( m_xRegistry );
454 m_xRegistry.clear();
455 m_activePackagesDB.reset(0);
456 m_xComponentContext.clear();
458 t_pm_helper::disposing();
461 catch (const RuntimeException &) {
462 throw;
464 catch (const Exception &) {
465 Any exc( ::cppu::getCaughtException() );
466 throw lang::WrappedTargetRuntimeException(
467 "caught unexpected exception while disposing...",
468 static_cast<OWeakObject *>(this), exc );
472 // XComponent
473 //______________________________________________________________________________
474 void PackageManagerImpl::dispose() throw (RuntimeException)
476 //Do not call check here. We must not throw an exception here if the object
477 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
478 WeakComponentImplHelperBase::dispose();
481 //______________________________________________________________________________
482 void PackageManagerImpl::addEventListener(
483 Reference<lang::XEventListener> const & xListener ) throw (RuntimeException)
485 //Do not call check here. We must not throw an exception here if the object
486 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
487 WeakComponentImplHelperBase::addEventListener( xListener );
490 //______________________________________________________________________________
491 void PackageManagerImpl::removeEventListener(
492 Reference<lang::XEventListener> const & xListener ) throw (RuntimeException)
494 //Do not call check here. We must not throw an exception here if the object
495 //is being disposed or is already disposed. See com.sun.star.lang.XComponent
496 WeakComponentImplHelperBase::removeEventListener( xListener );
499 // XPackageManager
500 //______________________________________________________________________________
501 OUString PackageManagerImpl::getContext() throw (RuntimeException)
503 check();
504 return m_context;
507 //______________________________________________________________________________
508 Sequence< Reference<deployment::XPackageTypeInfo> >
509 PackageManagerImpl::getSupportedPackageTypes() throw (RuntimeException)
511 OSL_ASSERT( m_xRegistry.is() );
512 return m_xRegistry->getSupportedPackageTypes();
515 //______________________________________________________________________________
516 Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel()
517 throw (RuntimeException)
519 check();
520 return new AbortChannel;
523 // XModifyBroadcaster
524 //______________________________________________________________________________
525 void PackageManagerImpl::addModifyListener(
526 Reference<util::XModifyListener> const & xListener )
527 throw (RuntimeException)
529 check();
530 rBHelper.addListener( ::getCppuType( &xListener ), xListener );
533 //______________________________________________________________________________
534 void PackageManagerImpl::removeModifyListener(
535 Reference<util::XModifyListener> const & xListener )
536 throw (RuntimeException)
538 check();
539 rBHelper.removeListener( ::getCppuType( &xListener ), xListener );
542 //______________________________________________________________________________
543 OUString PackageManagerImpl::detectMediaType(
544 ::ucbhelper::Content const & ucbContent_, bool throw_exc )
546 ::ucbhelper::Content ucbContent(ucbContent_);
547 OUString url( ucbContent.getURL() );
548 OUString mediaType;
549 if (url.match( "vnd.sun.star.tdoc:" ) || url.match( "vnd.sun.star.pkg:" ))
551 try {
552 ucbContent.getPropertyValue( "MediaType" ) >>= mediaType;
554 catch (const beans::UnknownPropertyException &) {
556 OSL_ENSURE( !mediaType.isEmpty(), "### no media-type?!" );
558 if (mediaType.isEmpty())
560 try {
561 Reference<deployment::XPackage> xPackage(
562 m_xRegistry->bindPackage(
563 url, OUString(), false, OUString(), ucbContent.getCommandEnvironment() ) );
564 const Reference<deployment::XPackageTypeInfo> xPackageType(
565 xPackage->getPackageType() );
566 OSL_ASSERT( xPackageType.is() );
567 if (xPackageType.is())
568 mediaType = xPackageType->getMediaType();
570 catch (const lang::IllegalArgumentException & exc) {
571 if (throw_exc)
572 throw;
573 (void) exc;
574 OSL_FAIL( OUStringToOString(
575 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
578 return mediaType;
581 //______________________________________________________________________________
582 OUString PackageManagerImpl::insertToActivationLayer(
583 Sequence<beans::NamedValue> const & properties,
584 OUString const & mediaType, ::ucbhelper::Content const & sourceContent_,
585 OUString const & title, ActivePackages::Data * dbData )
587 ::ucbhelper::Content sourceContent(sourceContent_);
588 Reference<XCommandEnvironment> xCmdEnv(
589 sourceContent.getCommandEnvironment() );
591 String baseDir(m_activePackages_expanded);
592 ::utl::TempFile aTemp(&baseDir, sal_False);
593 OUString tempEntry = aTemp.GetURL();
594 tempEntry = tempEntry.copy(tempEntry.lastIndexOf('/') + 1);
595 OUString destFolder = makeURL( m_activePackages, tempEntry);
596 destFolder += "_";
598 // prepare activation folder:
599 ::ucbhelper::Content destFolderContent;
600 create_folder( &destFolderContent, destFolder, xCmdEnv );
602 // copy content into activation temp dir:
603 if (mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.package-bundle") ||
604 // xxx todo: more sophisticated parsing
605 mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.legacy-package-bundle"))
607 // inflate content:
608 OUStringBuffer buf;
609 if (!sourceContent.isFolder())
611 buf.appendAscii( "vnd.sun.star.zip://" );
612 buf.append( ::rtl::Uri::encode( sourceContent.getURL(),
613 rtl_UriCharClassRegName,
614 rtl_UriEncodeIgnoreEscapes,
615 RTL_TEXTENCODING_UTF8 ) );
617 else
619 //Folder. No need to unzip, just copy
620 buf.append(sourceContent.getURL());
622 buf.append( static_cast<sal_Unicode>('/') );
623 sourceContent = ::ucbhelper::Content(
624 buf.makeStringAndClear(), xCmdEnv, m_xComponentContext );
626 if (! destFolderContent.transferContent(
627 sourceContent, ::ucbhelper::InsertOperation_COPY,
628 title, NameClash::OVERWRITE ))
629 throw RuntimeException( "UCB transferContent() failed!", 0 );
632 // write to DB:
633 //bundled extensions should only be added by the synchronizeAddedExtensions
634 //functions. Moreover, there is no "temporary folder" for bundled extensions.
635 OSL_ASSERT(!(m_context == "bundled"));
636 OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title);
637 DescriptionInfoset info =
638 dp_misc::getDescriptionInfoset(sFolderUrl);
639 dbData->temporaryName = tempEntry;
640 dbData->fileName = title;
641 dbData->mediaType = mediaType;
642 dbData->version = info.getVersion();
644 //No write the properties file next to the extension
645 ExtensionProperties props(sFolderUrl, properties, xCmdEnv, m_xComponentContext);
646 props.write();
647 return destFolder;
650 //______________________________________________________________________________
651 void PackageManagerImpl::insertToActivationLayerDB(
652 OUString const & id, ActivePackages::Data const & dbData )
654 //access to the database must be guarded. See removePackage
655 const ::osl::MutexGuard guard( getMutex() );
656 m_activePackagesDB->put( id, dbData );
659 //______________________________________________________________________________
660 /* The function returns true if there is an extension with the same id already
661 installed which needs to be uninstalled, before the new extension can be installed.
663 bool PackageManagerImpl::isInstalled(
664 Reference<deployment::XPackage> const & package)
666 OUString id(dp_misc::getIdentifier(package));
667 OUString fn(package->getName());
668 bool bInstalled = false;
669 if (m_activePackagesDB->has( id, fn ))
671 bInstalled = true;
673 return bInstalled;
676 // XPackageManager
677 //______________________________________________________________________________
678 Reference<deployment::XPackage> PackageManagerImpl::importExtension(
679 Reference<deployment::XPackage> const & extension,
680 Reference<task::XAbortChannel> const & xAbortChannel,
681 Reference<XCommandEnvironment> const & xCmdEnv_ )
682 throw (deployment::DeploymentException, CommandFailedException,
683 CommandAbortedException, lang::IllegalArgumentException,
684 RuntimeException)
686 return addPackage(extension->getURL(), Sequence<beans::NamedValue>(),
687 OUString(), xAbortChannel, xCmdEnv_);
690 /* The function adds an extension but does not register it!!!
691 It may not do any user interaction. This is done in XExtensionManager::addExtension
693 Reference<deployment::XPackage> PackageManagerImpl::addPackage(
694 OUString const & url,
695 css::uno::Sequence<css::beans::NamedValue> const & properties,
696 OUString const & mediaType_,
697 Reference<task::XAbortChannel> const & xAbortChannel,
698 Reference<XCommandEnvironment> const & xCmdEnv_ )
699 throw (deployment::DeploymentException, CommandFailedException,
700 CommandAbortedException, lang::IllegalArgumentException,
701 RuntimeException)
703 check();
704 if (m_readOnly)
706 OUString message;
707 if (m_context == "shared")
708 message = "You need write permissions to install a shared extension!";
709 else
710 message = "You need write permissions to install this extension!";
711 throw deployment::DeploymentException(
712 message, static_cast<OWeakObject *>(this), Any() );
714 Reference<XCommandEnvironment> xCmdEnv;
715 if (m_xLogFile.is())
716 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
717 else
718 xCmdEnv.set( xCmdEnv_ );
720 try {
721 ::ucbhelper::Content sourceContent;
722 create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc
723 const OUString title( StrTitle::getTitle( sourceContent ) );
724 const OUString title_enc( ::rtl::Uri::encode(
725 title, rtl_UriCharClassPchar,
726 rtl_UriEncodeIgnoreEscapes,
727 RTL_TEXTENCODING_UTF8 ) );
728 OUString destFolder;
730 OUString mediaType(mediaType_);
731 if (mediaType.isEmpty())
732 mediaType = detectMediaType( sourceContent );
734 Reference<deployment::XPackage> xPackage;
735 // copy file:
736 progressUpdate(
737 getResourceString(RID_STR_COPYING_PACKAGE) + title, xCmdEnv );
738 if (m_activePackages.isEmpty())
740 ::ucbhelper::Content docFolderContent;
741 create_folder( &docFolderContent, m_context, xCmdEnv );
742 // copy into document, first:
743 if (! docFolderContent.transferContent(
744 sourceContent, ::ucbhelper::InsertOperation_COPY,
745 OUString(),
746 NameClash::ASK /* xxx todo: ASK not needed? */))
747 throw RuntimeException("UCB transferContent() failed!", 0 );
748 // set media-type:
749 ::ucbhelper::Content docContent(
750 makeURL( m_context, title_enc ), xCmdEnv, m_xComponentContext );
751 //TODO #i73136#: using title instead of id can lead to
752 // clashes, but the whole m_activePackages.getLength()==0
753 // case (i.e., document-relative deployment) currently does
754 // not work, anyway.
755 docContent.setPropertyValue("MediaType", Any(mediaType) );
757 // xxx todo: obsolete in the future
758 try {
759 docFolderContent.executeCommand( "flush", Any() );
761 catch (const UnsupportedCommandException &) {
764 ActivePackages::Data dbData;
765 destFolder = insertToActivationLayer(
766 properties, mediaType, sourceContent, title, &dbData );
769 // bind activation package:
770 //Because every shared/user extension will be unpacked in a folder,
771 //which was created with a unique name we will always have two different
772 //XPackage objects, even if the second extension is the same.
773 //Therefore bindPackage does not need a guard here.
774 xPackage = m_xRegistry->bindPackage(
775 makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv );
777 OSL_ASSERT( xPackage.is() );
778 if (xPackage.is())
780 bool install = false;
783 OUString const id = dp_misc::getIdentifier( xPackage );
785 ::osl::MutexGuard g(m_addMutex);
786 if (isInstalled(xPackage))
788 //Do not guard the complete function with the getMutex
789 removePackage(id, xPackage->getName(), xAbortChannel,
790 xCmdEnv);
792 install = true;
793 insertToActivationLayerDB(id, dbData);
795 catch (...)
797 deletePackageFromCache( xPackage, destFolder );
798 throw;
800 if (!install)
802 deletePackageFromCache( xPackage, destFolder );
804 //ToDo: We should notify only if the extension is registered
805 fireModified();
807 return xPackage;
809 catch (const RuntimeException &) {
810 throw;
812 catch (const CommandFailedException & exc) {
813 logIntern( Any(exc) );
814 throw;
816 catch (const CommandAbortedException & exc) {
817 logIntern( Any(exc) );
818 throw;
820 catch (const deployment::DeploymentException & exc) {
821 logIntern( Any(exc) );
822 throw;
824 catch (const Exception &) {
825 Any exc( ::cppu::getCaughtException() );
826 logIntern( exc );
827 throw deployment::DeploymentException(
828 getResourceString(RID_STR_ERROR_WHILE_ADDING) + url,
829 static_cast<OWeakObject *>(this), exc );
832 void PackageManagerImpl::deletePackageFromCache(
833 Reference<deployment::XPackage> const & xPackage,
834 OUString const & destFolder)
836 try_dispose( xPackage );
838 //we remove the package from the uno cache
839 //no service from the package may be loaded at this time!!!
840 erase_path( destFolder, Reference<XCommandEnvironment>(),
841 false /* no throw: ignore errors */ );
842 //rm last character '_'
843 OUString url = destFolder.copy(0, destFolder.getLength() - 1);
844 erase_path( url, Reference<XCommandEnvironment>(),
845 false /* no throw: ignore errors */ );
848 //______________________________________________________________________________
849 void PackageManagerImpl::removePackage(
850 OUString const & id, OUString const & fileName,
851 Reference<task::XAbortChannel> const & /*xAbortChannel*/,
852 Reference<XCommandEnvironment> const & xCmdEnv_ )
853 throw (deployment::DeploymentException, CommandFailedException,
854 CommandAbortedException, lang::IllegalArgumentException,
855 RuntimeException)
857 check();
859 Reference<XCommandEnvironment> xCmdEnv;
860 if (m_xLogFile.is())
861 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
862 else
863 xCmdEnv.set( xCmdEnv_ );
865 try {
866 Reference<deployment::XPackage> xPackage;
868 const ::osl::MutexGuard guard(getMutex());
869 //Check if this extension exist and throw an IllegalArgumentException
870 //if it does not
871 //If the files of the extension are already removed, or there is a
872 //different extension at the same place, for example after updating the
873 //extension, then the returned object is that which uses the database data.
874 xPackage = getDeployedPackage_(id, fileName, xCmdEnv );
877 //Because the extension is only removed the next time the extension
878 //manager runs after restarting OOo, we need to indicate that a
879 //shared extension was "deleted". When a user starts OOo, then it
880 //will check if something changed in the shared repository. Based on
881 //the flag file it will then recognize, that the extension was
882 //deleted and can then update the extnesion database of the shared
883 //extensions in the user installation.
884 if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && (m_context == "shared"))
886 ActivePackages::Data val;
887 m_activePackagesDB->get( & val, id, fileName);
888 OSL_ASSERT(!val.temporaryName.isEmpty());
889 OUString url(makeURL(m_activePackages_expanded,
890 val.temporaryName + "removed"));
891 ::ucbhelper::Content contentRemoved(url, xCmdEnv, m_xComponentContext);
892 OUString aUserName;
893 ::osl::Security aSecurity;
894 aSecurity.getUserName( aUserName );
896 OString stamp = OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8);
897 Reference<css::io::XInputStream> xData(
898 ::xmlscript::createInputStream(
899 ::rtl::ByteSequence(
900 reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
901 stamp.getLength() ) ) );
902 contentRemoved.writeStream( xData, true /* replace existing */ );
904 m_activePackagesDB->erase( id, fileName ); // to be removed upon next start
905 //remove any cached data hold by the backend
906 m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType());
908 try_dispose( xPackage );
910 fireModified();
912 catch (const RuntimeException &) {
913 throw;
915 catch (const CommandFailedException & exc) {
916 logIntern( Any(exc) );
917 throw;
919 catch (const CommandAbortedException & exc) {
920 logIntern( Any(exc) );
921 throw;
923 catch (const deployment::DeploymentException & exc) {
924 logIntern( Any(exc) );
925 throw;
927 catch (const Exception &) {
928 Any exc( ::cppu::getCaughtException() );
929 logIntern( exc );
930 throw deployment::DeploymentException(
931 getResourceString(RID_STR_ERROR_WHILE_REMOVING) + id,
932 static_cast<OWeakObject *>(this), exc );
936 //______________________________________________________________________________
937 OUString PackageManagerImpl::getDeployPath( ActivePackages::Data const & data )
939 OUStringBuffer buf;
940 buf.append( data.temporaryName );
941 //The bundled extensions are not contained in an additional folder
942 //with a unique name. data.temporaryName contains already the
943 //UTF8 encoded folder name. See PackageManagerImpl::synchronize
944 if (!(m_context == "bundled"))
946 buf.appendAscii( "_/" );
947 buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar,
948 rtl_UriEncodeIgnoreEscapes,
949 RTL_TEXTENCODING_UTF8 ) );
951 return makeURL( m_activePackages, buf.makeStringAndClear() );
954 //______________________________________________________________________________
955 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
956 OUString const & id, OUString const & fileName,
957 Reference<XCommandEnvironment> const & xCmdEnv )
959 ActivePackages::Data val;
960 if (m_activePackagesDB->get( &val, id, fileName ))
962 return getDeployedPackage_( id, val, xCmdEnv, false );
964 throw lang::IllegalArgumentException(
965 getResourceString(RID_STR_NO_SUCH_PACKAGE) + id,
966 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
969 //______________________________________________________________________________
970 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
971 OUString const & id, ActivePackages::Data const & data,
972 Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms )
974 if (ignoreAlienPlatforms)
976 OUString type, subType;
977 INetContentTypeParameterList params;
978 if (INetContentTypes::parse( data.mediaType, type, subType, &params ))
980 INetContentTypeParameter const * param = params.find(
981 OString("platform") );
982 if (param != 0 && !platform_fits( param->m_sValue ))
983 throw lang::IllegalArgumentException(
984 getResourceString(RID_STR_NO_SUCH_PACKAGE) + id,
985 static_cast<OWeakObject *>(this),
986 static_cast<sal_Int16>(-1) );
989 Reference<deployment::XPackage> xExtension;
992 //Ignore extensions where XPackage::checkPrerequisites failed.
993 //They must not be usable for this user.
994 if (data.failedPrerequisites == "0")
996 xExtension = m_xRegistry->bindPackage(
997 getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv );
1000 catch (const deployment::InvalidRemovedParameterException& e)
1002 xExtension = e.Extension;
1004 return xExtension;
1007 //______________________________________________________________________________
1008 Sequence< Reference<deployment::XPackage> >
1009 PackageManagerImpl::getDeployedPackages_(
1010 Reference<XCommandEnvironment> const & xCmdEnv )
1012 ::std::vector< Reference<deployment::XPackage> > packages;
1013 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1014 ActivePackages::Entries::const_iterator iPos( id2temp.begin() );
1015 ActivePackages::Entries::const_iterator const iEnd( id2temp.end() );
1016 for ( ; iPos != iEnd; ++iPos )
1018 if (! (iPos->second.failedPrerequisites == "0"))
1019 continue;
1020 try {
1021 packages.push_back(
1022 getDeployedPackage_(
1023 iPos->first, iPos->second, xCmdEnv,
1024 true /* xxx todo: think of GUI:
1025 ignore other platforms than the current one */ ) );
1027 catch (const lang::IllegalArgumentException & exc) {
1028 // ignore
1029 (void) exc; // avoid warnings
1030 OSL_FAIL( OUStringToOString(
1031 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1033 catch (const deployment::DeploymentException& exc) {
1034 // ignore
1035 (void) exc; // avoid warnings
1036 OSL_FAIL( OUStringToOString(
1037 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1040 return comphelper::containerToSequence(packages);
1043 //______________________________________________________________________________
1044 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage(
1045 OUString const & id, OUString const & fileName,
1046 Reference<XCommandEnvironment> const & xCmdEnv_ )
1047 throw (deployment::DeploymentException, CommandFailedException,
1048 lang::IllegalArgumentException, RuntimeException)
1050 check();
1051 Reference<XCommandEnvironment> xCmdEnv;
1052 if (m_xLogFile.is())
1053 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1054 else
1055 xCmdEnv.set( xCmdEnv_ );
1057 try {
1058 const ::osl::MutexGuard guard( getMutex() );
1059 return getDeployedPackage_( id, fileName, xCmdEnv );
1061 catch (const lang::IllegalArgumentException & exc) {
1062 logIntern( Any(exc) );
1063 throw;
1065 catch (const RuntimeException &) {
1066 throw;
1068 catch (const CommandFailedException & exc) {
1069 logIntern( Any(exc) );
1070 throw;
1072 catch (const deployment::DeploymentException & exc) {
1073 logIntern( Any(exc) );
1074 throw;
1076 catch (const Exception &) {
1077 Any exc( ::cppu::getCaughtException() );
1078 logIntern( exc );
1079 throw deployment::DeploymentException(
1080 // ought never occur...
1081 "error while accessing deployed package: " + id,
1082 static_cast<OWeakObject *>(this), exc );
1086 //______________________________________________________________________________
1087 Sequence< Reference<deployment::XPackage> >
1088 PackageManagerImpl::getDeployedPackages(
1089 Reference<task::XAbortChannel> const &,
1090 Reference<XCommandEnvironment> const & xCmdEnv_ )
1091 throw (deployment::DeploymentException, CommandFailedException,
1092 CommandAbortedException, lang::IllegalArgumentException,
1093 RuntimeException)
1095 check();
1096 Reference<XCommandEnvironment> xCmdEnv;
1097 if (m_xLogFile.is())
1098 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1099 else
1100 xCmdEnv.set( xCmdEnv_ );
1102 try {
1103 const ::osl::MutexGuard guard( getMutex() );
1104 return getDeployedPackages_( xCmdEnv );
1106 catch (const RuntimeException &) {
1107 throw;
1109 catch (const CommandFailedException & exc) {
1110 logIntern( Any(exc) );
1111 throw;
1113 catch (const CommandAbortedException & exc) {
1114 logIntern( Any(exc) );
1115 throw;
1117 catch (const deployment::DeploymentException & exc) {
1118 logIntern( Any(exc) );
1119 throw;
1121 catch (const Exception &) {
1122 Any exc( ::cppu::getCaughtException() );
1123 logIntern( exc );
1124 throw deployment::DeploymentException(
1125 // ought never occur...
1126 "error while getting all deployed packages: " + m_context,
1127 static_cast<OWeakObject *>(this), exc );
1131 //______________________________________________________________________________
1134 //ToDo: the function must not call registerPackage, do this in
1135 //XExtensionManager.reinstallDeployedExtensions
1136 void PackageManagerImpl::reinstallDeployedPackages(
1137 sal_Bool force, Reference<task::XAbortChannel> const & /*xAbortChannel*/,
1138 Reference<XCommandEnvironment> const & xCmdEnv_ )
1139 throw (deployment::DeploymentException,
1140 CommandFailedException, CommandAbortedException,
1141 lang::IllegalArgumentException, RuntimeException)
1143 check();
1144 if (!force && office_is_running())
1145 throw RuntimeException(
1146 "You must close any running Office process before reinstalling packages!",
1147 static_cast<OWeakObject *>(this) );
1149 Reference<XCommandEnvironment> xCmdEnv;
1150 if (m_xLogFile.is())
1151 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1152 else
1153 xCmdEnv.set( xCmdEnv_ );
1155 try {
1156 ProgressLevel progress(
1157 xCmdEnv, "Reinstalling all deployed packages..." );
1159 try_dispose( m_xRegistry );
1160 m_xRegistry.clear();
1161 if (!m_registryCache.isEmpty())
1162 erase_path( m_registryCache, xCmdEnv );
1163 initRegistryBackends();
1164 Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
1165 if (xUpdatable.is())
1166 xUpdatable->update();
1168 //registering is done by the ExtensionManager service.
1170 catch (const RuntimeException &) {
1171 throw;
1173 catch (const CommandFailedException & exc) {
1174 logIntern( Any(exc) );
1175 throw;
1177 catch (const CommandAbortedException & exc) {
1178 logIntern( Any(exc) );
1179 throw;
1181 catch (const deployment::DeploymentException & exc) {
1182 logIntern( Any(exc) );
1183 throw;
1185 catch (const Exception &) {
1186 Any exc( ::cppu::getCaughtException() );
1187 logIntern( exc );
1188 throw deployment::DeploymentException(
1189 "Error while reinstalling all previously deployed packages of context " + m_context,
1190 static_cast<OWeakObject *>(this), exc );
1195 ::sal_Bool SAL_CALL PackageManagerImpl::isReadOnly( )
1196 throw (::com::sun::star::uno::RuntimeException)
1198 return m_readOnly;
1200 bool PackageManagerImpl::synchronizeRemovedExtensions(
1201 Reference<task::XAbortChannel> const & xAbortChannel,
1202 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1205 //find all which are in the extension data base but which
1206 //are removed already.
1207 OSL_ASSERT(!(m_context == "user"));
1208 bool bModified = false;
1209 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1211 typedef ActivePackages::Entries::const_iterator ITActive;
1212 bool bShared = (m_context == "shared");
1214 for (ITActive i = id2temp.begin(); i != id2temp.end(); ++i)
1218 //Get the URL to the extensions folder, first make the url for the
1219 //shared repository including the temporary name
1220 OUString url = makeURL(m_activePackages, i->second.temporaryName);
1221 if (bShared)
1222 url = makeURLAppendSysPathSegment( url + "_", i->second.fileName);
1224 bool bRemoved = false;
1225 //Check if the URL to the extension is still the same
1226 ::ucbhelper::Content contentExtension;
1228 if (!create_ucb_content(
1229 &contentExtension, url,
1230 Reference<XCommandEnvironment>(), false))
1232 bRemoved = true;
1235 //The folder is in the extension database, but it can still be deleted.
1236 //look for the xxx.tmpremoved file
1237 //There can also be the case that a different extension was installed
1238 //in a "temp" folder with name that is already used.
1239 if (!bRemoved && bShared)
1241 ::ucbhelper::Content contentRemoved;
1243 if (create_ucb_content(
1244 &contentRemoved,
1245 m_activePackages_expanded + "/" +
1246 i->second.temporaryName + "removed",
1247 Reference<XCommandEnvironment>(), false))
1249 bRemoved = true;
1253 if (!bRemoved)
1255 //There may be another extensions at the same place
1256 dp_misc::DescriptionInfoset infoset =
1257 dp_misc::getDescriptionInfoset(url);
1258 OSL_ENSURE(infoset.hasDescription() && infoset.getIdentifier(),
1259 "Extension Manager: bundled and shared extensions "
1260 "must have an identifer and a version");
1261 if (infoset.hasDescription() &&
1262 infoset.getIdentifier() &&
1263 (! i->first.equals(*(infoset.getIdentifier()))
1264 || ! i->second.version.equals(infoset.getVersion())))
1266 bRemoved = true;
1270 if (bRemoved)
1272 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1273 url, i->second.mediaType, true, i->first, xCmdEnv );
1274 OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
1275 xPackage->revokePackage(true, xAbortChannel, xCmdEnv);
1276 removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
1277 xAbortChannel, xCmdEnv);
1278 bModified |= true;
1281 catch( const uno::Exception & e )
1283 SAL_WARN("desktop.deployment", e.Message);
1286 return bModified;
1290 bool PackageManagerImpl::synchronizeAddedExtensions(
1291 Reference<task::XAbortChannel> const & xAbortChannel,
1292 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1294 bool bModified = false;
1295 OSL_ASSERT(!(m_context == "user"));
1297 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1298 //check if the folder exist at all. The shared extension folder
1299 //may not exist for a normal user.
1300 if (!create_ucb_content(
1301 NULL, m_activePackages_expanded, Reference<css::ucb::XCommandEnvironment>(), false))
1302 return bModified;
1304 ::ucbhelper::Content tempFolder( m_activePackages_expanded, xCmdEnv, m_xComponentContext );
1305 Reference<sdbc::XResultSet> xResultSet(
1306 StrTitle::createCursor( tempFolder,
1307 ::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
1309 while (xResultSet->next())
1313 OUString title(
1314 Reference<sdbc::XRow>(
1315 xResultSet, UNO_QUERY_THROW )->getString(
1316 1 /* Title */ ) );
1317 //The temporary folders of user and shared have an '_' at then end.
1318 //But the name in ActivePackages.temporaryName is saved without.
1319 OUString title2 = title;
1320 bool bShared = (m_context == "shared");
1321 if (bShared)
1323 OSL_ASSERT(title2[title2.getLength() -1] == '_');
1324 title2 = title2.copy(0, title2.getLength() -1);
1326 OUString titleEncoded = ::rtl::Uri::encode(
1327 title2, rtl_UriCharClassPchar,
1328 rtl_UriEncodeIgnoreEscapes,
1329 RTL_TEXTENCODING_UTF8);
1331 //It it sufficient to check for the folder name, because when the administor
1332 //installed the extension it was already checked if there is one with the
1333 //same identifier.
1334 const MatchTempDir match(titleEncoded);
1335 if (::std::find_if( id2temp.begin(), id2temp.end(), match ) ==
1336 id2temp.end())
1339 // The folder was not found in the data base, so it must be
1340 // an added extension
1341 OUString url(m_activePackages_expanded + "/" + titleEncoded);
1342 OUString sExtFolder;
1343 if (bShared) //that is, shared
1345 //Check if the extension was not "deleted" already which is indicated
1346 //by a xxx.tmpremoved file
1347 ::ucbhelper::Content contentRemoved;
1348 if (create_ucb_content(&contentRemoved, url + "removed",
1349 Reference<XCommandEnvironment>(), false))
1350 continue;
1351 sExtFolder = getExtensionFolder(
1352 m_activePackages_expanded + "/" + titleEncoded + "_",
1353 xCmdEnv, m_xComponentContext);
1354 url = makeURLAppendSysPathSegment(m_activePackages_expanded, title);
1355 url = makeURLAppendSysPathSegment(url, sExtFolder);
1357 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1358 url, OUString(), false, OUString(), xCmdEnv );
1359 if (xPackage.is())
1361 //Prepare the database entry
1362 ActivePackages::Data dbData;
1364 dbData.temporaryName = titleEncoded;
1365 if (bShared)
1366 dbData.fileName = sExtFolder;
1367 else
1368 dbData.fileName = title;
1369 dbData.mediaType = xPackage->getPackageType()->getMediaType();
1370 dbData.version = xPackage->getVersion();
1371 OSL_ENSURE(!dbData.version.isEmpty(),
1372 "Extension Manager: bundled and shared extensions must have "
1373 "an identifier and a version");
1375 OUString id = dp_misc::getIdentifier( xPackage );
1377 //We provide a special command environment that will prevent
1378 //showing a license if simple-licens/@accept-by = "admin"
1379 //It will also prevent showing the license for bundled extensions
1380 //which is not supported.
1381 OSL_ASSERT(!(m_context == "user"));
1383 // shall the license be suppressed?
1384 DescriptionInfoset info =
1385 dp_misc::getDescriptionInfoset(url);
1386 ::boost::optional<dp_misc::SimpleLicenseAttributes>
1387 attr = info.getSimpleLicenseAttributes();
1388 ExtensionProperties props(url, xCmdEnv, m_xComponentContext);
1389 bool bNoLicense = false;
1390 if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
1391 bNoLicense = true;
1393 Reference<ucb::XCommandEnvironment> licCmdEnv(
1394 new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
1395 bNoLicense, m_context));
1396 sal_Int32 failedPrereq = xPackage->checkPrerequisites(
1397 xAbortChannel, licCmdEnv, false);
1398 //Remember that this failed. For example, the user
1399 //could have declined the license. Then the next time the
1400 //extension folder is investigated we do not want to
1401 //try to install the extension again.
1402 dbData.failedPrerequisites = OUString::valueOf(failedPrereq);
1403 insertToActivationLayerDB(id, dbData);
1404 bModified |= true;
1408 catch (const uno::Exception & e)
1410 // Looks like exceptions being caught here is not an uncommon case.
1411 SAL_WARN("desktop.deployment", e.Message);
1414 return bModified;
1417 sal_Bool PackageManagerImpl::synchronize(
1418 Reference<task::XAbortChannel> const & xAbortChannel,
1419 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1420 throw (css::deployment::DeploymentException,
1421 css::ucb::CommandFailedException,
1422 css::ucb::CommandAbortedException,
1423 css::uno::RuntimeException)
1425 check();
1426 bool bModified = false;
1427 if (m_context == "user")
1428 return bModified;
1429 bModified |=
1430 synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
1431 bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
1433 return bModified;
1436 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
1437 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1438 throw (deployment::DeploymentException, RuntimeException)
1440 ::std::vector<Reference<deployment::XPackage> > vec;
1444 const ::osl::MutexGuard guard( getMutex() );
1445 // clean up activation layer, scan for zombie temp dirs:
1446 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1448 ActivePackages::Entries::const_iterator i = id2temp.begin();
1449 bool bShared = (m_context == "shared");
1451 for (; i != id2temp.end(); ++i )
1453 //Get the database entry
1454 ActivePackages::Data const & dbData = i->second;
1455 sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
1456 //If the installation failed for other reason then the license then we
1457 //ignore it.
1458 if (failedPrereq ^= deployment::Prerequisites::LICENSE)
1459 continue;
1461 //Prepare the URL to the extension
1462 OUString url = makeURL(m_activePackages, i->second.temporaryName);
1463 if (bShared)
1464 url = makeURLAppendSysPathSegment( url + "_", i->second.fileName);
1466 Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
1467 url, OUString(), false, OUString(), xCmdEnv );
1469 if (p.is())
1470 vec.push_back(p);
1473 return ::comphelper::containerToSequence(vec);
1475 catch (const deployment::DeploymentException &)
1477 throw;
1479 catch (const RuntimeException&)
1481 throw;
1483 catch (...)
1485 Any exc = ::cppu::getCaughtException();
1486 deployment::DeploymentException de(
1487 "PackageManagerImpl::getExtensionsWithUnacceptedLicenses",
1488 static_cast<OWeakObject*>(this), exc);
1489 exc <<= de;
1490 ::cppu::throwException(exc);
1493 return ::comphelper::containerToSequence(vec);
1496 sal_Int32 PackageManagerImpl::checkPrerequisites(
1497 css::uno::Reference<css::deployment::XPackage> const & extension,
1498 css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
1499 css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
1500 throw (css::deployment::DeploymentException,
1501 css::ucb::CommandFailedException,
1502 css::ucb::CommandAbortedException,
1503 css::lang::IllegalArgumentException,
1504 css::uno::RuntimeException)
1508 if (!extension.is())
1509 return 0;
1510 if (!m_context.equals(extension->getRepositoryName()))
1511 throw lang::IllegalArgumentException(
1512 "PackageManagerImpl::checkPrerequisites: extension is not from this repository.",
1513 0, 0);
1515 ActivePackages::Data dbData;
1516 OUString id = dp_misc::getIdentifier(extension);
1517 if (m_activePackagesDB->get( &dbData, id, OUString()))
1519 //If the license was already displayed, then do not show it again
1520 Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
1521 sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
1522 if ( !(prereq & deployment::Prerequisites::LICENSE))
1523 _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
1525 sal_Int32 failedPrereq = extension->checkPrerequisites(
1526 xAbortChannel, _xCmdEnv, false);
1527 dbData.failedPrerequisites = OUString::valueOf(failedPrereq);
1528 insertToActivationLayerDB(id, dbData);
1530 else
1532 throw lang::IllegalArgumentException(
1533 "PackageManagerImpl::checkPrerequisites: unknown extension",
1534 0, 0);
1537 return 0;
1539 catch ( const deployment::DeploymentException& ) {
1540 throw;
1541 } catch ( const ucb::CommandFailedException & ) {
1542 throw;
1543 } catch ( const ucb::CommandAbortedException & ) {
1544 throw;
1545 } catch (const lang::IllegalArgumentException &) {
1546 throw;
1547 } catch (const uno::RuntimeException &) {
1548 throw;
1549 } catch (...) {
1550 uno::Any excOccurred = ::cppu::getCaughtException();
1551 deployment::DeploymentException exc(
1552 "PackageManagerImpl::checkPrerequisites: exception ",
1553 static_cast<OWeakObject*>(this), excOccurred);
1554 throw exc;
1559 //______________________________________________________________________________
1560 PackageManagerImpl::CmdEnvWrapperImpl::~CmdEnvWrapperImpl()
1564 //______________________________________________________________________________
1565 PackageManagerImpl::CmdEnvWrapperImpl::CmdEnvWrapperImpl(
1566 Reference<XCommandEnvironment> const & xUserCmdEnv,
1567 Reference<XProgressHandler> const & xLogFile )
1568 : m_xLogFile( xLogFile )
1570 if (xUserCmdEnv.is()) {
1571 m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
1572 m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
1576 // XCommandEnvironment
1577 //______________________________________________________________________________
1578 Reference<task::XInteractionHandler>
1579 PackageManagerImpl::CmdEnvWrapperImpl::getInteractionHandler()
1580 throw (RuntimeException)
1582 return m_xUserInteractionHandler;
1585 //______________________________________________________________________________
1586 Reference<XProgressHandler>
1587 PackageManagerImpl::CmdEnvWrapperImpl::getProgressHandler()
1588 throw (RuntimeException)
1590 return this;
1593 // XProgressHandler
1594 //______________________________________________________________________________
1595 void PackageManagerImpl::CmdEnvWrapperImpl::push( Any const & Status )
1596 throw (RuntimeException)
1598 if (m_xLogFile.is())
1599 m_xLogFile->push( Status );
1600 if (m_xUserProgress.is())
1601 m_xUserProgress->push( Status );
1604 //______________________________________________________________________________
1605 void PackageManagerImpl::CmdEnvWrapperImpl::update( Any const & Status )
1606 throw (RuntimeException)
1608 if (m_xLogFile.is())
1609 m_xLogFile->update( Status );
1610 if (m_xUserProgress.is())
1611 m_xUserProgress->update( Status );
1614 //______________________________________________________________________________
1615 void PackageManagerImpl::CmdEnvWrapperImpl::pop() throw (RuntimeException)
1617 if (m_xLogFile.is())
1618 m_xLogFile->pop();
1619 if (m_xUserProgress.is())
1620 m_xUserProgress->pop();
1623 } // namespace dp_manager
1625 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */