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