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