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