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