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