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()
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 )
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 )
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()
561 {
562 check();
563 return m_context;
564 }
565
566 //______________________________________________________________________________
567 Sequence< Reference<deployment::XPackageTypeInfo> >
getSupportedPackageTypes()568 PackageManagerImpl::getSupportedPackageTypes()
569 {
570 OSL_ASSERT( m_xRegistry.is() );
571 return m_xRegistry->getSupportedPackageTypes();
572 }
573
574 //______________________________________________________________________________
createAbortChannel()575 Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel()
576 {
577 check();
578 return new AbortChannel;
579 }
580
581 // XModifyBroadcaster
582 //______________________________________________________________________________
addModifyListener(Reference<util::XModifyListener> const & xListener)583 void PackageManagerImpl::addModifyListener(
584 Reference<util::XModifyListener> const & xListener )
585 {
586 check();
587 rBHelper.addListener( ::getCppuType( &xListener ), xListener );
588 }
589
590 //______________________________________________________________________________
removeModifyListener(Reference<util::XModifyListener> const & xListener)591 void PackageManagerImpl::removeModifyListener(
592 Reference<util::XModifyListener> const & xListener )
593 {
594 check();
595 rBHelper.removeListener( ::getCppuType( &xListener ), xListener );
596 }
597
598 //______________________________________________________________________________
detectMediaType(::ucbhelper::Content const & ucbContent_,bool throw_exc)599 OUString PackageManagerImpl::detectMediaType(
600 ::ucbhelper::Content const & ucbContent_, bool throw_exc )
601 {
602 ::ucbhelper::Content ucbContent(ucbContent_);
603 OUString url( ucbContent.getURL() );
604 OUString mediaType;
605 if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:") ) ||
606 url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.pkg:") ))
607 {
608 try {
609 ucbContent.getPropertyValue( OUSTR("MediaType") ) >>= mediaType;
610 }
611 catch (beans::UnknownPropertyException &) {
612 }
613 OSL_ENSURE( mediaType.getLength() > 0, "### no media-type?!" );
614 }
615 if (mediaType.getLength() == 0)
616 {
617 try {
618 Reference<deployment::XPackage> xPackage(
619 m_xRegistry->bindPackage(
620 url, OUString(), false, OUString(), ucbContent.getCommandEnvironment() ) );
621 const Reference<deployment::XPackageTypeInfo> xPackageType(
622 xPackage->getPackageType() );
623 OSL_ASSERT( xPackageType.is() );
624 if (xPackageType.is())
625 mediaType = xPackageType->getMediaType();
626 }
627 catch (lang::IllegalArgumentException & exc) {
628 if (throw_exc)
629 throw;
630 (void) exc;
631 OSL_ENSURE( 0, ::rtl::OUStringToOString(
632 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
633 }
634 }
635 return mediaType;
636 }
637
638 //______________________________________________________________________________
insertToActivationLayer(Sequence<beans::NamedValue> const & properties,OUString const & mediaType,::ucbhelper::Content const & sourceContent_,OUString const & title,ActivePackages::Data * dbData)639 OUString PackageManagerImpl::insertToActivationLayer(
640 Sequence<beans::NamedValue> const & properties,
641 OUString const & mediaType, ::ucbhelper::Content const & sourceContent_,
642 OUString const & title, ActivePackages::Data * dbData )
643 {
644 ::ucbhelper::Content sourceContent(sourceContent_);
645 Reference<XCommandEnvironment> xCmdEnv(
646 sourceContent.getCommandEnvironment() );
647
648 String baseDir(m_activePackages_expanded);
649 ::utl::TempFile aTemp(&baseDir, sal_False);
650 OUString tempEntry = aTemp.GetURL();
651 tempEntry = tempEntry.copy(tempEntry.lastIndexOf('/') + 1);
652 OUString destFolder = makeURL( m_activePackages, tempEntry);
653 destFolder += OUSTR("_");
654
655 // prepare activation folder:
656 ::ucbhelper::Content destFolderContent;
657 create_folder( &destFolderContent, destFolder, xCmdEnv );
658
659 // copy content into activation temp dir:
660 if (mediaType.matchIgnoreAsciiCaseAsciiL(
661 RTL_CONSTASCII_STRINGPARAM(
662 "application/vnd.sun.star.package-bundle") ) ||
663 // xxx todo: more sophisticated parsing
664 mediaType.matchIgnoreAsciiCaseAsciiL(
665 RTL_CONSTASCII_STRINGPARAM(
666 "application/vnd.sun.star.legacy-package-bundle") ))
667 {
668 // inflate content:
669 ::rtl::OUStringBuffer buf;
670 if (!sourceContent.isFolder())
671 {
672 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") );
673 buf.append( ::rtl::Uri::encode( sourceContent.getURL(),
674 rtl_UriCharClassRegName,
675 rtl_UriEncodeIgnoreEscapes,
676 RTL_TEXTENCODING_UTF8 ) );
677 }
678 else
679 {
680 //Folder. No need to unzip, just copy
681 buf.append(sourceContent.getURL());
682 }
683 buf.append( static_cast<sal_Unicode>('/') );
684 sourceContent = ::ucbhelper::Content(
685 buf.makeStringAndClear(), xCmdEnv );
686 }
687 if (! destFolderContent.transferContent(
688 sourceContent, ::ucbhelper::InsertOperation_COPY,
689 title, NameClash::OVERWRITE ))
690 throw RuntimeException( OUSTR("UCB transferContent() failed!"), 0 );
691
692
693 // write to DB:
694 //bundled extensions should only be added by the synchronizeAddedExtensions
695 //functions. Moreover, there is no "temporary folder" for bundled extensions.
696 OSL_ASSERT(!m_context.equals(OUSTR("bundled")));
697 OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title);
698 DescriptionInfoset info =
699 dp_misc::getDescriptionInfoset(sFolderUrl);
700 dbData->temporaryName = tempEntry;
701 dbData->fileName = title;
702 dbData->mediaType = mediaType;
703 dbData->version = info.getVersion();
704
705 //No write the properties file next to the extension
706 ExtensionProperties props(sFolderUrl, properties, xCmdEnv);
707 props.write();
708 return destFolder;
709 }
710
711 //______________________________________________________________________________
insertToActivationLayerDB(OUString const & id,ActivePackages::Data const & dbData)712 void PackageManagerImpl::insertToActivationLayerDB(
713 OUString const & id, ActivePackages::Data const & dbData )
714 {
715 //access to the database must be guarded. See removePackage
716 const ::osl::MutexGuard guard( getMutex() );
717 m_activePackagesDB->put( id, dbData );
718 }
719
720 //______________________________________________________________________________
721 /* The function returns true if there is an extension with the same id already
722 installed which needs to be uninstalled, before the new extension can be installed.
723 */
isInstalled(Reference<deployment::XPackage> const & package)724 bool PackageManagerImpl::isInstalled(
725 Reference<deployment::XPackage> const & package)
726 {
727 OUString id(dp_misc::getIdentifier(package));
728 OUString fn(package->getName());
729 bool bInstalled = false;
730 if (m_activePackagesDB->has( id, fn ))
731 {
732 bInstalled = true;
733 }
734 return bInstalled;
735 }
736
737 // XPackageManager
738 //______________________________________________________________________________
importExtension(Reference<deployment::XPackage> const & extension,Reference<task::XAbortChannel> const & xAbortChannel,Reference<XCommandEnvironment> const & xCmdEnv_)739 Reference<deployment::XPackage> PackageManagerImpl::importExtension(
740 Reference<deployment::XPackage> const & extension,
741 Reference<task::XAbortChannel> const & xAbortChannel,
742 Reference<XCommandEnvironment> const & xCmdEnv_ )
743 {
744 return addPackage(extension->getURL(), Sequence<beans::NamedValue>(),
745 OUString(), xAbortChannel, xCmdEnv_);
746 }
747
748 /* The function adds an extension but does not register it!!!
749 It may not do any user interaction. This is done in XExtensionManager::addExtension
750 */
addPackage(OUString const & url,css::uno::Sequence<css::beans::NamedValue> const & properties,OUString const & mediaType_,Reference<task::XAbortChannel> const & xAbortChannel,Reference<XCommandEnvironment> const & xCmdEnv_)751 Reference<deployment::XPackage> PackageManagerImpl::addPackage(
752 OUString const & url,
753 css::uno::Sequence<css::beans::NamedValue> const & properties,
754 OUString const & mediaType_,
755 Reference<task::XAbortChannel> const & xAbortChannel,
756 Reference<XCommandEnvironment> const & xCmdEnv_ )
757 {
758 check();
759 if (m_readOnly)
760 {
761 OUString message;
762 if (m_context == OUSTR("shared"))
763 message = OUSTR("You need write permissions to install a shared extension!");
764 else
765 message = OUSTR("You need write permissions to install this extension!");
766 throw deployment::DeploymentException(
767 message, static_cast<OWeakObject *>(this), Any() );
768 }
769 Reference<XCommandEnvironment> xCmdEnv;
770 if (m_xLogFile.is())
771 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
772 else
773 xCmdEnv.set( xCmdEnv_ );
774
775 try {
776 ::ucbhelper::Content sourceContent;
777 create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc
778 const OUString title(sourceContent.getPropertyValue(
779 StrTitle::get() ).get<OUString>() );
780 const OUString title_enc( ::rtl::Uri::encode(
781 title, rtl_UriCharClassPchar,
782 rtl_UriEncodeIgnoreEscapes,
783 RTL_TEXTENCODING_UTF8 ) );
784 OUString destFolder;
785
786 OUString mediaType(mediaType_);
787 if (mediaType.getLength() == 0)
788 mediaType = detectMediaType( sourceContent );
789
790 Reference<deployment::XPackage> xPackage;
791 // copy file:
792 progressUpdate(
793 getResourceString(RID_STR_COPYING_PACKAGE) + title, xCmdEnv );
794 if (m_activePackages.getLength() == 0)
795 {
796 ::ucbhelper::Content docFolderContent;
797 create_folder( &docFolderContent, m_context, xCmdEnv );
798 // copy into document, first:
799 if (! docFolderContent.transferContent(
800 sourceContent, ::ucbhelper::InsertOperation_COPY,
801 OUString(),
802 NameClash::ASK /* xxx todo: ASK not needed? */))
803 throw RuntimeException(
804 OUSTR("UCB transferContent() failed!"), 0 );
805 // set media-type:
806 ::ucbhelper::Content docContent(
807 makeURL( m_context, title_enc ), xCmdEnv );
808 //TODO #i73136#: using title instead of id can lead to
809 // clashes, but the whole m_activePackages.getLength()==0
810 // case (i.e., document-relative deployment) currently does
811 // not work, anyway.
812 docContent.setPropertyValue(
813 OUSTR("MediaType"), Any(mediaType) );
814
815 // xxx todo: obsolete in the future
816 try {
817 docFolderContent.executeCommand( OUSTR("flush"), Any() );
818 }
819 catch (UnsupportedCommandException &) {
820 }
821 }
822 ActivePackages::Data dbData;
823 destFolder = insertToActivationLayer(
824 properties, mediaType, sourceContent, title, &dbData );
825
826
827 // bind activation package:
828 //Because every shared/user extension will be unpacked in a folder,
829 //which was created with a unique name we will always have two different
830 //XPackage objects, even if the second extension is the same.
831 //Therefore bindPackage does not need a guard here.
832 xPackage = m_xRegistry->bindPackage(
833 makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv );
834
835 OSL_ASSERT( xPackage.is() );
836 if (xPackage.is())
837 {
838 bool install = false;
839 try
840 {
841 OUString const id = dp_misc::getIdentifier( xPackage );
842
843 ::osl::MutexGuard g(m_addMutex);
844 if (isInstalled(xPackage))
845 {
846 //Do not guard the complete function with the getMutex
847 removePackage(id, xPackage->getName(), xAbortChannel,
848 xCmdEnv);
849 }
850 install = true;
851 insertToActivationLayerDB(id, dbData);
852 }
853 catch (...)
854 {
855 deletePackageFromCache( xPackage, destFolder );
856 throw;
857 }
858 if (!install)
859 {
860 deletePackageFromCache( xPackage, destFolder );
861 }
862 //ToDo: We should notify only if the extension is registered
863 fireModified();
864 }
865 return xPackage;
866 }
867 catch (RuntimeException &) {
868 throw;
869 }
870 catch (CommandFailedException & exc) {
871 logIntern( Any(exc) );
872 throw;
873 }
874 catch (CommandAbortedException & exc) {
875 logIntern( Any(exc) );
876 throw;
877 }
878 catch (deployment::DeploymentException & exc) {
879 logIntern( Any(exc) );
880 throw;
881 }
882 catch (Exception &) {
883 Any exc( ::cppu::getCaughtException() );
884 logIntern( exc );
885 throw deployment::DeploymentException(
886 getResourceString(RID_STR_ERROR_WHILE_ADDING) + url,
887 static_cast<OWeakObject *>(this), exc );
888 }
889 }
deletePackageFromCache(Reference<deployment::XPackage> const & xPackage,OUString const & destFolder)890 void PackageManagerImpl::deletePackageFromCache(
891 Reference<deployment::XPackage> const & xPackage,
892 OUString const & destFolder)
893 {
894 try_dispose( xPackage );
895
896 //we remove the package from the uno cache
897 //no service from the package may be loaded at this time!!!
898 erase_path( destFolder, Reference<XCommandEnvironment>(),
899 false /* no throw: ignore errors */ );
900 //rm last character '_'
901 OUString url = destFolder.copy(0, destFolder.getLength() - 1);
902 erase_path( url, Reference<XCommandEnvironment>(),
903 false /* no throw: ignore errors */ );
904
905 }
906 //______________________________________________________________________________
removePackage(OUString const & id,::rtl::OUString const & fileName,Reference<task::XAbortChannel> const &,Reference<XCommandEnvironment> const & xCmdEnv_)907 void PackageManagerImpl::removePackage(
908 OUString const & id, ::rtl::OUString const & fileName,
909 Reference<task::XAbortChannel> const & /*xAbortChannel*/,
910 Reference<XCommandEnvironment> const & xCmdEnv_ )
911 {
912 check();
913
914 Reference<XCommandEnvironment> xCmdEnv;
915 if (m_xLogFile.is())
916 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
917 else
918 xCmdEnv.set( xCmdEnv_ );
919
920 try {
921 Reference<deployment::XPackage> xPackage;
922 {
923 const ::osl::MutexGuard guard(getMutex());
924 //Check if this extension exists and throw an IllegalArgumentException
925 //if it does not
926 //If the files of the extension are already removed, or there is a
927 //different extension at the same place, for example after updating the
928 //extension, then the returned object is that which uses the database data.
929 xPackage = getDeployedPackage_(id, fileName, xCmdEnv );
930
931
932 //Because the extension is only removed the next time the extension
933 //manager runs after restarting AOO, we need to indicate that a
934 //shared extension was "deleted". When a user starts AOO, then it
935 //will check if something changed in the shared repository. Based on
936 //the flag file it will then recognize, that the extension was
937 //deleted and can then update the extension database of the shared
938 //extensions in the user installation.
939 if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && m_context.equals(OUSTR("shared")))
940 {
941 ActivePackages::Data val;
942 m_activePackagesDB->get( & val, id, fileName);
943 OSL_ASSERT(val.temporaryName.getLength());
944 OUString url(makeURL(m_activePackages_expanded,
945 val.temporaryName + OUSTR("removed")));
946 ::ucbhelper::Content contentRemoved(url, xCmdEnv );
947 OUString aUserName;
948 ::osl::Security aSecurity;
949 aSecurity.getUserName( aUserName );
950
951 ::rtl::OString stamp = ::rtl::OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8);
952 Reference<css::io::XInputStream> xData(
953 ::xmlscript::createInputStream(
954 ::rtl::ByteSequence(
955 reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
956 stamp.getLength() ) ) );
957 contentRemoved.writeStream( xData, true /* replace existing */ );
958 }
959 m_activePackagesDB->erase( id, fileName ); // to be removed upon next start
960 //remove any cached data hold by the backend
961 m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType());
962 }
963 try_dispose( xPackage );
964
965 fireModified();
966 }
967 catch (RuntimeException &) {
968 throw;
969 }
970 catch (lang::IllegalArgumentException &) {
971 throw;
972 }
973 catch (CommandFailedException & exc) {
974 logIntern( Any(exc) );
975 throw;
976 }
977 catch (CommandAbortedException & exc) {
978 logIntern( Any(exc) );
979 throw;
980 }
981 catch (deployment::DeploymentException & exc) {
982 logIntern( Any(exc) );
983 throw;
984 }
985 catch (Exception &) {
986 Any exc( ::cppu::getCaughtException() );
987 logIntern( exc );
988 throw deployment::DeploymentException(
989 getResourceString(RID_STR_ERROR_WHILE_REMOVING) + id,
990 static_cast<OWeakObject *>(this), exc );
991 }
992 }
993
994 //______________________________________________________________________________
getDeployPath(ActivePackages::Data const & data)995 OUString PackageManagerImpl::getDeployPath( ActivePackages::Data const & data )
996 {
997 ::rtl::OUStringBuffer buf;
998 buf.append( data.temporaryName );
999 //The bundled extensions are not contained in an additional folder
1000 //with a unique name. data.temporaryName contains already the
1001 //UTF8 encoded folder name. See PackageManagerImpl::synchronize
1002 if (!m_context.equals(OUSTR("bundled"))
1003 && !m_context.equals(OUSTR("bundled_prereg")))
1004 {
1005 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("_/") );
1006 buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar,
1007 rtl_UriEncodeIgnoreEscapes,
1008 RTL_TEXTENCODING_UTF8 ) );
1009 }
1010 return makeURL( m_activePackages, buf.makeStringAndClear() );
1011 }
1012
1013 //______________________________________________________________________________
getDeployedPackage_(OUString const & id,OUString const & fileName,Reference<XCommandEnvironment> const & xCmdEnv)1014 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
1015 OUString const & id, OUString const & fileName,
1016 Reference<XCommandEnvironment> const & xCmdEnv )
1017 {
1018 ActivePackages::Data val;
1019 if (m_activePackagesDB->get( &val, id, fileName ))
1020 {
1021 return getDeployedPackage_( id, val, xCmdEnv, false );
1022 }
1023 throw lang::IllegalArgumentException(
1024 getResourceString(RID_STR_NO_SUCH_PACKAGE) + id,
1025 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
1026 }
1027
1028 //______________________________________________________________________________
getDeployedPackage_(OUString const & id,ActivePackages::Data const & data,Reference<XCommandEnvironment> const & xCmdEnv,bool ignoreAlienPlatforms)1029 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
1030 OUString const & id, ActivePackages::Data const & data,
1031 Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms )
1032 {
1033 if (ignoreAlienPlatforms)
1034 {
1035 String type, subType;
1036 INetContentTypeParameterList params;
1037 if (INetContentTypes::parse( data.mediaType, type, subType, ¶ms ))
1038 {
1039 INetContentTypeParameter const * param = params.find(
1040 ByteString("platform") );
1041 if (param != 0 && !platform_fits( param->m_sValue ))
1042 throw lang::IllegalArgumentException(
1043 getResourceString(RID_STR_NO_SUCH_PACKAGE) + id,
1044 static_cast<OWeakObject *>(this),
1045 static_cast<sal_Int16>(-1) );
1046 }
1047 }
1048 Reference<deployment::XPackage> xExtension;
1049 try
1050 {
1051 //Ignore extensions where XPackage::checkPrerequisites failed.
1052 //They must not be usable for this user.
1053 if (data.failedPrerequisites.equals(OUSTR("0")))
1054 {
1055 xExtension = m_xRegistry->bindPackage(
1056 getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv );
1057 }
1058 }
1059 catch (deployment::InvalidRemovedParameterException& e)
1060 {
1061 xExtension = e.Extension;
1062 }
1063 return xExtension;
1064 }
1065
1066 //______________________________________________________________________________
1067 Sequence< Reference<deployment::XPackage> >
getDeployedPackages_(Reference<XCommandEnvironment> const & xCmdEnv)1068 PackageManagerImpl::getDeployedPackages_(
1069 Reference<XCommandEnvironment> const & xCmdEnv )
1070 {
1071 ::std::vector< Reference<deployment::XPackage> > packages;
1072 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1073 ActivePackages::Entries::const_iterator iPos( id2temp.begin() );
1074 ActivePackages::Entries::const_iterator const iEnd( id2temp.end() );
1075 for ( ; iPos != iEnd; ++iPos )
1076 {
1077 if (! iPos->second.failedPrerequisites.equals(OUSTR("0")))
1078 continue;
1079 try {
1080 packages.push_back(
1081 getDeployedPackage_(
1082 iPos->first, iPos->second, xCmdEnv,
1083 true /* xxx todo: think of GUI:
1084 ignore other platforms than the current one */ ) );
1085 }
1086 catch (lang::IllegalArgumentException & exc) {
1087 // ignore
1088 (void) exc; // avoid warnings
1089 OSL_ENSURE( 0, ::rtl::OUStringToOString(
1090 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1091 }
1092 catch (deployment::DeploymentException& exc) {
1093 // ignore
1094 (void) exc; // avoid warnings
1095 OSL_ENSURE( 0, ::rtl::OUStringToOString(
1096 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1097 }
1098 }
1099 return comphelper::containerToSequence(packages);
1100 }
1101
1102 //______________________________________________________________________________
getDeployedPackage(OUString const & id,::rtl::OUString const & fileName,Reference<XCommandEnvironment> const & xCmdEnv_)1103 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage(
1104 OUString const & id, ::rtl::OUString const & fileName,
1105 Reference<XCommandEnvironment> const & xCmdEnv_ )
1106 {
1107 check();
1108 Reference<XCommandEnvironment> xCmdEnv;
1109 if (m_xLogFile.is())
1110 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1111 else
1112 xCmdEnv.set( xCmdEnv_ );
1113
1114 try {
1115 const ::osl::MutexGuard guard( getMutex() );
1116 return getDeployedPackage_( id, fileName, xCmdEnv );
1117 }
1118 catch (RuntimeException &) {
1119 throw;
1120 }
1121 catch (CommandFailedException & exc) {
1122 logIntern( Any(exc) );
1123 throw;
1124 }
1125 catch (lang::IllegalArgumentException & exc) {
1126 logIntern( Any(exc) );
1127 throw;
1128 }
1129 catch (deployment::DeploymentException & exc) {
1130 logIntern( Any(exc) );
1131 throw;
1132 }
1133 catch (Exception &) {
1134 Any exc( ::cppu::getCaughtException() );
1135 logIntern( exc );
1136 throw deployment::DeploymentException(
1137 // ought never occur...
1138 OUSTR("error while accessing deployed package: ") + id,
1139 static_cast<OWeakObject *>(this), exc );
1140 }
1141 }
1142
1143 //______________________________________________________________________________
1144 Sequence< Reference<deployment::XPackage> >
getDeployedPackages(Reference<task::XAbortChannel> const &,Reference<XCommandEnvironment> const & xCmdEnv_)1145 PackageManagerImpl::getDeployedPackages(
1146 Reference<task::XAbortChannel> const &,
1147 Reference<XCommandEnvironment> const & xCmdEnv_ )
1148 {
1149 check();
1150 Reference<XCommandEnvironment> xCmdEnv;
1151 if (m_xLogFile.is())
1152 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1153 else
1154 xCmdEnv.set( xCmdEnv_ );
1155
1156 try {
1157 const ::osl::MutexGuard guard( getMutex() );
1158 return getDeployedPackages_( xCmdEnv );
1159 }
1160 catch (RuntimeException &) {
1161 throw;
1162 }
1163 catch (CommandFailedException & exc) {
1164 logIntern( Any(exc) );
1165 throw;
1166 }
1167 catch (CommandAbortedException & exc) {
1168 logIntern( Any(exc) );
1169 throw;
1170 }
1171 catch (deployment::DeploymentException & exc) {
1172 logIntern( Any(exc) );
1173 throw;
1174 }
1175 catch (Exception &) {
1176 Any exc( ::cppu::getCaughtException() );
1177 logIntern( exc );
1178 throw deployment::DeploymentException(
1179 // ought never occur...
1180 OUSTR("error while getting all deployed packages: ") + m_context,
1181 static_cast<OWeakObject *>(this), exc );
1182 }
1183 }
1184
1185 //______________________________________________________________________________
1186
1187
1188 //ToDo: the function must not call registerPackage, do this in
1189 //XExtensionManager.reinstallDeployedExtensions
reinstallDeployedPackages(Reference<task::XAbortChannel> const &,Reference<XCommandEnvironment> const & xCmdEnv_)1190 void PackageManagerImpl::reinstallDeployedPackages(
1191 Reference<task::XAbortChannel> const & /*xAbortChannel*/,
1192 Reference<XCommandEnvironment> const & xCmdEnv_ )
1193 {
1194 check();
1195 if (office_is_running())
1196 throw RuntimeException(
1197 OUSTR("You must close any running Office process before "
1198 "reinstalling packages!"), static_cast<OWeakObject *>(this) );
1199
1200 Reference<XCommandEnvironment> xCmdEnv;
1201 if (m_xLogFile.is())
1202 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1203 else
1204 xCmdEnv.set( xCmdEnv_ );
1205
1206 try {
1207 ProgressLevel progress(
1208 xCmdEnv, OUSTR("Reinstalling all deployed packages...") );
1209
1210 try_dispose( m_xRegistry );
1211 m_xRegistry.clear();
1212 if (m_registryCache.getLength() > 0)
1213 erase_path( m_registryCache, xCmdEnv );
1214 initRegistryBackends();
1215 Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
1216 if (xUpdatable.is())
1217 xUpdatable->update();
1218
1219 //registering is done by the ExtensionManager service.
1220 }
1221 catch (RuntimeException &) {
1222 throw;
1223 }
1224 catch (CommandFailedException & exc) {
1225 logIntern( Any(exc) );
1226 throw;
1227 }
1228 catch (CommandAbortedException & exc) {
1229 logIntern( Any(exc) );
1230 throw;
1231 }
1232 catch (deployment::DeploymentException & exc) {
1233 logIntern( Any(exc) );
1234 throw;
1235 }
1236 catch (Exception &) {
1237 Any exc( ::cppu::getCaughtException() );
1238 logIntern( exc );
1239 throw deployment::DeploymentException(
1240 OUSTR("Error while reinstalling all previously deployed "
1241 "packages of context ") + m_context,
1242 static_cast<OWeakObject *>(this), exc );
1243 }
1244 }
1245
1246
isReadOnly()1247 ::sal_Bool SAL_CALL PackageManagerImpl::isReadOnly( )
1248 {
1249 return m_readOnly;
1250 }
synchronizeRemovedExtensions(Reference<task::XAbortChannel> const & xAbortChannel,Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)1251 bool PackageManagerImpl::synchronizeRemovedExtensions(
1252 Reference<task::XAbortChannel> const & xAbortChannel,
1253 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1254 {
1255
1256 //find all which are in the extension data base but which
1257 //are removed already.
1258 OSL_ASSERT(!m_context.equals(OUSTR("user")));
1259 bool bModified = false;
1260 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1261
1262 typedef ActivePackages::Entries::const_iterator ITActive;
1263 bool bShared = m_context.equals(OUSTR("shared"));
1264
1265 for (ITActive i = id2temp.begin(); i != id2temp.end(); i++)
1266 {
1267 try
1268 {
1269 //Get the URL to the extensions folder, first make the url for the
1270 //shared repository including the temporary name
1271 OUString url = makeURL(m_activePackages, i->second.temporaryName);
1272 if (bShared)
1273 url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName);
1274
1275 bool bRemoved = false;
1276 //Check if the URL to the extension is still the same
1277 ::ucbhelper::Content contentExtension;
1278
1279 if (!create_ucb_content(
1280 &contentExtension, url,
1281 Reference<XCommandEnvironment>(), false))
1282 {
1283 bRemoved = true;
1284 }
1285
1286 //The folder is in the extension database, but it can still be deleted.
1287 //look for the xxx.tmpremoved file
1288 //There can also be the case that a different extension was installed
1289 //in a "temp" folder with name that is already used.
1290 if (!bRemoved && bShared)
1291 {
1292 ::ucbhelper::Content contentRemoved;
1293
1294 if (create_ucb_content(
1295 &contentRemoved,
1296 m_activePackages_expanded + OUSTR("/") +
1297 i->second.temporaryName + OUSTR("removed"),
1298 Reference<XCommandEnvironment>(), false))
1299 {
1300 bRemoved = true;
1301 }
1302 }
1303
1304 if (!bRemoved)
1305 {
1306 //There may be another extensions at the same place
1307 dp_misc::DescriptionInfoset infoset =
1308 dp_misc::getDescriptionInfoset(url);
1309 OSL_ENSURE(infoset.hasDescription(),
1310 "Extension Manager: bundled and shared extensions "
1311 "must have an identifier and a version");
1312 if (infoset.hasDescription() &&
1313 infoset.getIdentifier() &&
1314 (! i->first.equals(*(infoset.getIdentifier()))
1315 || ! i->second.version.equals(infoset.getVersion())))
1316 {
1317 bRemoved = true;
1318 }
1319
1320 }
1321 if (bRemoved)
1322 {
1323 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1324 url, i->second.mediaType, true, i->first, xCmdEnv );
1325 OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
1326 xPackage->revokePackage(xAbortChannel, xCmdEnv);
1327 removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
1328 xAbortChannel, xCmdEnv);
1329 bModified |= true;
1330 }
1331 }
1332 catch( uno::Exception & )
1333 {
1334 OSL_ASSERT(0);
1335 }
1336 }
1337 return bModified;
1338 }
1339
1340
synchronizeAddedExtensions(Reference<task::XAbortChannel> const & xAbortChannel,Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)1341 bool PackageManagerImpl::synchronizeAddedExtensions(
1342 Reference<task::XAbortChannel> const & xAbortChannel,
1343 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1344 {
1345 bool bModified = false;
1346 OSL_ASSERT(!m_context.equals(OUSTR("user")));
1347
1348 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1349 //check if the folder exist at all. The shared extension folder
1350 //may not exist for a normal user.
1351 if (!create_ucb_content(
1352 NULL, m_activePackages_expanded, Reference<css::ucb::XCommandEnvironment>(), false))
1353 return bModified;
1354 ::ucbhelper::Content tempFolder(
1355 m_activePackages_expanded, xCmdEnv );
1356
1357 Reference<sdbc::XResultSet> xResultSet(
1358 tempFolder.createCursor(
1359 Sequence<OUString>( &StrTitle::get(), 1 ),
1360 ::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
1361
1362 while (xResultSet->next())
1363 {
1364 try
1365 {
1366 OUString title(
1367 Reference<sdbc::XRow>(
1368 xResultSet, UNO_QUERY_THROW )->getString(
1369 1 /* Title */ ) );
1370 //The temporary folders of user and shared have an '_' at then end.
1371 //But the name in ActivePackages.temporaryName is saved without.
1372 OUString title2 = title;
1373 bool bShared = m_context.equals(OUSTR("shared"));
1374 if (bShared)
1375 {
1376 OSL_ASSERT(title2[title2.getLength() -1] == '_');
1377 title2 = title2.copy(0, title2.getLength() -1);
1378 }
1379 OUString titleEncoded = ::rtl::Uri::encode(
1380 title2, rtl_UriCharClassPchar,
1381 rtl_UriEncodeIgnoreEscapes,
1382 RTL_TEXTENCODING_UTF8);
1383
1384 //It is sufficient to check for the folder name, because when the administrator
1385 //installed the extension it was already checked if there is one with the
1386 //same identifier.
1387 const MatchTempDir match(titleEncoded);
1388 if (::std::find_if( id2temp.begin(), id2temp.end(), match ) ==
1389 id2temp.end())
1390 {
1391
1392 // The folder was not found in the data base, so it must be
1393 // an added extension
1394 OUString url(m_activePackages_expanded + OUSTR("/") + titleEncoded);
1395 OUString sExtFolder;
1396 if (bShared) //that is, shared
1397 {
1398 //Check if the extension was not "deleted" already which is indicated
1399 //by a xxx.tmpremoved file
1400 ::ucbhelper::Content contentRemoved;
1401 if (create_ucb_content(&contentRemoved, url + OUSTR("removed"),
1402 Reference<XCommandEnvironment>(), false))
1403 continue;
1404 sExtFolder = getExtensionFolder(
1405 m_activePackages_expanded +
1406 OUString(OUSTR("/")) + titleEncoded + OUSTR("_"), xCmdEnv);
1407 url = makeURLAppendSysPathSegment(m_activePackages_expanded, title);
1408 url = makeURLAppendSysPathSegment(url, sExtFolder);
1409 }
1410 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1411 url, OUString(), false, OUString(), xCmdEnv );
1412 if (xPackage.is())
1413 {
1414 //Prepare the database entry
1415 ActivePackages::Data dbData;
1416
1417 dbData.temporaryName = titleEncoded;
1418 if (bShared)
1419 dbData.fileName = sExtFolder;
1420 else
1421 dbData.fileName = title;
1422 dbData.mediaType = xPackage->getPackageType()->getMediaType();
1423 dbData.version = xPackage->getVersion();
1424 OSL_ENSURE(dbData.version.getLength() > 0,
1425 "Extension Manager: bundled and shared extensions must have "
1426 "an identifier and a version");
1427
1428 OUString id = dp_misc::getIdentifier( xPackage );
1429
1430 //We provide a special command environment that will prevent
1431 //showing a license if simple-licens/@accept-by = "admin"
1432 //It will also prevent showing the license for bundled extensions
1433 //which is not supported.
1434 OSL_ASSERT(!m_context.equals(OUSTR("user")));
1435
1436 // shall the license be suppressed?
1437 DescriptionInfoset info =
1438 dp_misc::getDescriptionInfoset(url);
1439 ::boost::optional<dp_misc::SimpleLicenseAttributes>
1440 attr = info.getSimpleLicenseAttributes();
1441 ExtensionProperties props(url,xCmdEnv);
1442 bool bNoLicense = false;
1443 if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
1444 bNoLicense = true;
1445
1446 Reference<ucb::XCommandEnvironment> licCmdEnv(
1447 new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
1448 bNoLicense, m_context));
1449 sal_Int32 failedPrereq = xPackage->checkPrerequisites(
1450 xAbortChannel, licCmdEnv, false);
1451 //Remember that this failed. For example, the user
1452 //could have declined the license. Then the next time the
1453 //extension folder is investigated we do not want to
1454 //try to install the extension again.
1455 dbData.failedPrerequisites = OUString::valueOf(failedPrereq);
1456 insertToActivationLayerDB(id, dbData);
1457 bModified |= true;
1458 }
1459 }
1460 }
1461 catch (uno::Exception &)
1462 {
1463 // Looks like exceptions being caught here is not an
1464 // uncommon case.
1465 OSL_TRACE("caught exception in PackageManagerImpl::synchronizeAddedExtensions");
1466 }
1467 }
1468 return bModified;
1469 }
1470
synchronize(Reference<task::XAbortChannel> const & xAbortChannel,Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)1471 sal_Bool PackageManagerImpl::synchronize(
1472 Reference<task::XAbortChannel> const & xAbortChannel,
1473 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1474 {
1475 check();
1476 bool bModified = false;
1477 if (m_context.equals(OUSTR("user")))
1478 return bModified;
1479 bModified |=
1480 synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
1481 bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
1482
1483 return bModified;
1484 }
1485
getExtensionsWithUnacceptedLicenses(Reference<ucb::XCommandEnvironment> const & xCmdEnv)1486 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
1487 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1488 {
1489 ::std::vector<Reference<deployment::XPackage> > vec;
1490
1491 try
1492 {
1493 const ::osl::MutexGuard guard( getMutex() );
1494 // clean up activation layer, scan for zombie temp dirs:
1495 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1496
1497 ActivePackages::Entries::const_iterator i = id2temp.begin();
1498 bool bShared = m_context.equals(OUSTR("shared"));
1499
1500 for (; i != id2temp.end(); i++ )
1501 {
1502 //Get the database entry
1503 ActivePackages::Data const & dbData = i->second;
1504 sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
1505 //If the installation failed for other reason then the license then we
1506 //ignore it.
1507 if (failedPrereq ^= deployment::Prerequisites::LICENSE)
1508 continue;
1509
1510 //Prepare the URL to the extension
1511 OUString url = makeURL(m_activePackages, i->second.temporaryName);
1512 if (bShared)
1513 url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName);
1514
1515 Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
1516 url, OUString(), false, OUString(), xCmdEnv );
1517
1518 if (p.is())
1519 vec.push_back(p);
1520
1521 }
1522 return ::comphelper::containerToSequence(vec);
1523 }
1524 catch (deployment::DeploymentException &)
1525 {
1526 throw;
1527 }
1528 catch (RuntimeException&)
1529 {
1530 throw;
1531 }
1532 catch (...)
1533 {
1534 Any exc = ::cppu::getCaughtException();
1535 deployment::DeploymentException de(
1536 OUSTR("PackageManagerImpl::getExtensionsWithUnacceptedLicenses"),
1537 static_cast<OWeakObject*>(this), exc);
1538 exc <<= de;
1539 ::cppu::throwException(exc);
1540 }
1541
1542 return ::comphelper::containerToSequence(vec);
1543 }
1544
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)1545 sal_Int32 PackageManagerImpl::checkPrerequisites(
1546 css::uno::Reference<css::deployment::XPackage> const & extension,
1547 css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
1548 css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
1549 {
1550 try
1551 {
1552 if (!extension.is())
1553 return 0;
1554 if (!m_context.equals(extension->getRepositoryName()))
1555 throw lang::IllegalArgumentException(
1556 OUSTR("PackageManagerImpl::checkPrerequisites: extension is not"
1557 " from this repository."), 0, 0);
1558
1559 ActivePackages::Data dbData;
1560 OUString id = dp_misc::getIdentifier(extension);
1561 if (m_activePackagesDB->get( &dbData, id, OUString()))
1562 {
1563 //If the license was already displayed, then do not show it again
1564 Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
1565 sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
1566 if ( !(prereq & deployment::Prerequisites::LICENSE))
1567 _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
1568
1569 sal_Int32 failedPrereq = extension->checkPrerequisites(
1570 xAbortChannel, _xCmdEnv, false);
1571 dbData.failedPrerequisites = OUString::valueOf(failedPrereq);
1572 insertToActivationLayerDB(id, dbData);
1573 }
1574 else
1575 {
1576 throw lang::IllegalArgumentException(
1577 OUSTR("PackageManagerImpl::checkPrerequisites: unknown extension"),
1578 0, 0);
1579
1580 }
1581 return 0;
1582 }
1583 catch (deployment::DeploymentException& ) {
1584 throw;
1585 } catch (ucb::CommandFailedException & ) {
1586 throw;
1587 } catch (ucb::CommandAbortedException & ) {
1588 throw;
1589 } catch (lang::IllegalArgumentException &) {
1590 throw;
1591 } catch (uno::RuntimeException &) {
1592 throw;
1593 } catch (...) {
1594 uno::Any excOccurred = ::cppu::getCaughtException();
1595 deployment::DeploymentException exc(
1596 OUSTR("PackageManagerImpl::checkPrerequisites: exception "),
1597 static_cast<OWeakObject*>(this), excOccurred);
1598 throw exc;
1599 }
1600 }
1601
1602 //##############################################################################
1603
1604 //______________________________________________________________________________
~CmdEnvWrapperImpl()1605 PackageManagerImpl::CmdEnvWrapperImpl::~CmdEnvWrapperImpl()
1606 {
1607 }
1608
1609 //______________________________________________________________________________
CmdEnvWrapperImpl(Reference<XCommandEnvironment> const & xUserCmdEnv,Reference<XProgressHandler> const & xLogFile)1610 PackageManagerImpl::CmdEnvWrapperImpl::CmdEnvWrapperImpl(
1611 Reference<XCommandEnvironment> const & xUserCmdEnv,
1612 Reference<XProgressHandler> const & xLogFile )
1613 : m_xLogFile( xLogFile )
1614 {
1615 if (xUserCmdEnv.is()) {
1616 m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
1617 m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
1618 }
1619 }
1620
1621 // XCommandEnvironment
1622 //______________________________________________________________________________
1623 Reference<task::XInteractionHandler>
getInteractionHandler()1624 PackageManagerImpl::CmdEnvWrapperImpl::getInteractionHandler()
1625 {
1626 return m_xUserInteractionHandler;
1627 }
1628
1629 //______________________________________________________________________________
1630 Reference<XProgressHandler>
getProgressHandler()1631 PackageManagerImpl::CmdEnvWrapperImpl::getProgressHandler()
1632 {
1633 return this;
1634 }
1635
1636 // XProgressHandler
1637 //______________________________________________________________________________
push(Any const & Status)1638 void PackageManagerImpl::CmdEnvWrapperImpl::push( Any const & Status )
1639 {
1640 if (m_xLogFile.is())
1641 m_xLogFile->push( Status );
1642 if (m_xUserProgress.is())
1643 m_xUserProgress->push( Status );
1644 }
1645
1646 //______________________________________________________________________________
update(Any const & Status)1647 void PackageManagerImpl::CmdEnvWrapperImpl::update( Any const & Status )
1648 {
1649 if (m_xLogFile.is())
1650 m_xLogFile->update( Status );
1651 if (m_xUserProgress.is())
1652 m_xUserProgress->update( Status );
1653 }
1654
1655 //______________________________________________________________________________
pop()1656 void PackageManagerImpl::CmdEnvWrapperImpl::pop()
1657 {
1658 if (m_xLogFile.is())
1659 m_xLogFile->pop();
1660 if (m_xUserProgress.is())
1661 m_xUserProgress->pop();
1662 }
1663
1664 } // namespace dp_manager
1665