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