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