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