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 <cppuhelper/implbase1.hxx>
32 
33 #include "comphelper/servicedecl.hxx"
34 #include "cppuhelper/exc_hlp.hxx"
35 #include "rtl/bootstrap.hxx"
36 #include "com/sun/star/deployment/ExtensionManager.hpp"
37 #include "com/sun/star/deployment/XExtensionManager.hpp"
38 #include "com/sun/star/deployment/thePackageManagerFactory.hpp"
39 #include "com/sun/star/deployment/XPackageManager.hpp"
40 #include "com/sun/star/deployment/XPackageManagerFactory.hpp"
41 #include "com/sun/star/deployment/XPackage.hpp"
42 #include "com/sun/star/deployment/InstallException.hpp"
43 #include "com/sun/star/deployment/VersionException.hpp"
44 #include "com/sun/star/deployment/LicenseException.hpp"
45 #include "com/sun/star/lang/XServiceInfo.hpp"
46 #include "com/sun/star/registry/XRegistryKey.hpp"
47 #include "com/sun/star/beans/Optional.hpp"
48 #include "com/sun/star/task/XInteractionApprove.hpp"
49 #include "com/sun/star/beans/Ambiguous.hpp"
50 #include "com/sun/star/uno/XComponentContext.hpp"
51 #include "com/sun/star/io/XInputStream.hpp"
52 #include "com/sun/star/util/XModifyBroadcaster.hpp"
53 #include "comphelper/sequence.hxx"
54 #include "xmlscript/xml_helper.hxx"
55 #include "osl/diagnose.h"
56 #include "dp_interact.h"
57 #include "dp_resource.h"
58 #include "dp_ucb.h"
59 #include "dp_identifier.hxx"
60 #include "dp_descriptioninfoset.hxx"
61 #include "dp_extensionmanager.hxx"
62 #include "dp_commandenvironments.hxx"
63 #include "dp_properties.hxx"
64 #include "boost/bind.hpp"
65 
66 #include <list>
67 #include <hash_map>
68 #include <algorithm>
69 
70 namespace deploy = com::sun::star::deployment;
71 namespace lang  = com::sun::star::lang;
72 namespace registry = com::sun::star::registry;
73 namespace task = com::sun::star::task;
74 namespace ucb = com::sun::star::ucb;
75 namespace uno = com::sun::star::uno;
76 namespace beans = com::sun::star::beans;
77 namespace util = com::sun::star::util;
78 namespace css = com::sun::star;
79 
80 
81 //#define OUSTR(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))
82 
83 using ::com::sun::star::uno::Reference;
84 using ::rtl::OUString;
85 
86 namespace {
87 
88 struct CompIdentifiers
89 {
90     bool operator() (::std::vector<Reference<deploy::XPackage> > const & a,
91                      ::std::vector<Reference<deploy::XPackage> > const & b)
92         {
93 
94             if (getName(a).compareTo(getName(b)) < 0)
95                 return true;
96             return false;
97         }
98 
99     OUString getName(::std::vector<Reference<deploy::XPackage> > const & a);
100 };
101 
102 OUString CompIdentifiers::getName(::std::vector<Reference<deploy::XPackage> > const & a)
103 {
104     OSL_ASSERT(a.size() == 3);
105     //get the first non-null reference
106     Reference<deploy::XPackage>  extension;
107     ::std::vector<Reference<deploy::XPackage> >::const_iterator it = a.begin();
108     for (; it != a.end(); it++)
109     {
110         if (it->is())
111         {
112             extension = *it;
113             break;
114         }
115     }
116     OSL_ASSERT(extension.is());
117     return extension->getDisplayName();
118 }
119 
120 void writeLastModified(OUString & url, Reference<ucb::XCommandEnvironment> const & xCmdEnv)
121 {
122     //Write the lastmodified file
123     try {
124         ::rtl::Bootstrap::expandMacros(url);
125         ::ucbhelper::Content ucbStamp(url, xCmdEnv );
126         dp_misc::erase_path( url, xCmdEnv );
127         ::rtl::OString stamp("1" );
128         Reference<css::io::XInputStream> xData(
129             ::xmlscript::createInputStream(
130                 ::rtl::ByteSequence(
131                     reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
132                     stamp.getLength() ) ) );
133         ucbStamp.writeStream( xData, true /* replace existing */ );
134     }
135     catch(...)
136     {
137         uno::Any exc(::cppu::getCaughtException());
138         throw deploy::DeploymentException(
139             OUSTR("Failed to update") + url, 0, exc);
140     }
141 }
142 
143 class ExtensionRemoveGuard
144 {
145     css::uno::Reference<css::deployment::XPackage> m_extension;
146     css::uno::Reference<css::deployment::XPackageManager> m_xPackageManager;
147 
148 public:
149     ExtensionRemoveGuard(
150         css::uno::Reference<css::deployment::XPackage> const & extension,
151         css::uno::Reference<css::deployment::XPackageManager> const & xPackageManager):
152         m_extension(extension), m_xPackageManager(xPackageManager) {}
153     ~ExtensionRemoveGuard();
154 
155     void reset(css::uno::Reference<css::deployment::XPackage> const & extension) {
156         m_extension = extension;
157     }
158 };
159 
160 ExtensionRemoveGuard::~ExtensionRemoveGuard()
161 {
162     try {
163         if (m_xPackageManager.is() && m_extension.is())
164             m_xPackageManager->removePackage(
165                 dp_misc::getIdentifier(m_extension), ::rtl::OUString(),
166                 css::uno::Reference<css::task::XAbortChannel>(),
167                 css::uno::Reference<css::ucb::XCommandEnvironment>());
168     } catch (...) {
169         OSL_ASSERT(0);
170     }
171 }
172 
173 } //end namespace
174 
175 namespace dp_manager {
176 
177 
178 
179 //------------------------------------------------------------------------------
180 
181 //ToDo: bundled extension
182 ExtensionManager::ExtensionManager( Reference< uno::XComponentContext > const& xContext) :
183     ::cppu::WeakComponentImplHelper1< css::deployment::XExtensionManager >(getMutex()),
184     m_xContext( xContext )
185 {
186     m_xPackageManagerFactory = deploy::thePackageManagerFactory::get(m_xContext);
187     OSL_ASSERT(m_xPackageManagerFactory.is());
188 
189     m_repositoryNames.push_back(OUSTR("user"));
190     m_repositoryNames.push_back(OUSTR("shared"));
191     m_repositoryNames.push_back(OUSTR("bundled"));
192 }
193 
194 //------------------------------------------------------------------------------
195 
196 ExtensionManager::~ExtensionManager()
197 {
198 }
199 
200 Reference<deploy::XPackageManager> ExtensionManager::getUserRepository()
201 {
202     return m_xPackageManagerFactory->getPackageManager(OUSTR("user"));
203 }
204 Reference<deploy::XPackageManager>  ExtensionManager::getSharedRepository()
205 {
206     return m_xPackageManagerFactory->getPackageManager(OUSTR("shared"));
207 }
208 Reference<deploy::XPackageManager>  ExtensionManager::getBundledRepository()
209 {
210     return m_xPackageManagerFactory->getPackageManager(OUSTR("bundled"));
211 }
212 Reference<deploy::XPackageManager>  ExtensionManager::getTmpRepository()
213 {
214     return m_xPackageManagerFactory->getPackageManager(OUSTR("tmp"));
215 }
216 
217 Reference<task::XAbortChannel> ExtensionManager::createAbortChannel()
218     throw (uno::RuntimeException)
219 {
220     return new dp_misc::AbortChannel;
221 }
222 
223 css::uno::Reference<css::deployment::XPackageManager>
224 ExtensionManager::getPackageManager(::rtl::OUString const & repository)
225     throw (css::lang::IllegalArgumentException)
226 {
227     Reference<deploy::XPackageManager> xPackageManager;
228     if (repository.equals(OUSTR("user")))
229         xPackageManager = getUserRepository();
230     else if (repository.equals(OUSTR("shared")))
231         xPackageManager = getSharedRepository();
232     else if (repository.equals(OUSTR("bundled")))
233         xPackageManager = getBundledRepository();
234     else
235         throw lang::IllegalArgumentException(
236             OUSTR("No valid repository name provided."),
237             static_cast<cppu::OWeakObject*>(this), 0);
238     return xPackageManager;
239 }
240 
241 
242 /*
243   Enters the XPackage objects into a map. They must be all from the
244   same repository. The value type of the map is a vector, where each vector
245   represents an extension with a particular identifier. The first member
246   is represents the user extension, the second the shared extension and the
247   third the bundled extension.
248  */
249 void ExtensionManager::addExtensionsToMap(
250     id2extensions & mapExt,
251     uno::Sequence<Reference<deploy::XPackage> > const & seqExt,
252     OUString const & repository)
253 {
254     //Determine the index in the vector where these extensions are to be
255     //added.
256     ::std::list<OUString>::const_iterator citNames =
257         m_repositoryNames.begin();
258     int index = 0;
259     for (;citNames != m_repositoryNames.end(); citNames++, index++)
260     {
261         if (citNames->equals(repository))
262             break;
263     }
264 
265     for (int i = 0; i < seqExt.getLength(); i++)
266     {
267         Reference<deploy::XPackage> const & xExtension = seqExt[i];
268         OUString id = dp_misc::getIdentifier(xExtension);
269         id2extensions::iterator ivec =  mapExt.find(id);
270         if (ivec == mapExt.end())
271         {
272             ::std::vector<Reference<deploy::XPackage> > vec(3);
273             vec[index] = xExtension;
274             mapExt[id] = vec;
275         }
276         else
277         {
278             ivec->second[index] = xExtension;
279         }
280     }
281 }
282 
283 /*
284    returns a list containing extensions with the same identifier from
285    all repositories (user, shared, bundled) If one repository does not
286    have this extension, then the list contains an empty Referenc. The list
287    is ordered according to the priority of the repostories:
288    1. user
289    2. shared
290    3. bundled
291 
292    The number of elements is always three, unless the number of repository
293    changes.
294  */
295 ::std::list<Reference<deploy::XPackage> >
296     ExtensionManager::getExtensionsWithSameId(
297         OUString const & identifier, OUString const & fileName,
298         Reference< ucb::XCommandEnvironment> const & /*xCmdEnv*/)
299 
300 {
301     ::std::list<Reference<deploy::XPackage> > extensionList;
302     try
303     {   //will throw an exception if the extension does not exist
304         extensionList.push_back(getUserRepository()->getDeployedPackage(
305             identifier, fileName, Reference<ucb::XCommandEnvironment>()));
306     } catch(lang::IllegalArgumentException &)
307     {
308         extensionList.push_back(Reference<deploy::XPackage>());
309     }
310     try
311     {
312         extensionList.push_back(getSharedRepository()->getDeployedPackage(
313             identifier, fileName, Reference<ucb::XCommandEnvironment>()));
314     } catch (lang::IllegalArgumentException &)
315     {
316         extensionList.push_back(Reference<deploy::XPackage>());
317     }
318     try
319     {
320        extensionList.push_back(getBundledRepository()->getDeployedPackage(
321            identifier, fileName, Reference<ucb::XCommandEnvironment>()));
322     } catch (lang::IllegalArgumentException &)
323     {
324         extensionList.push_back(Reference<deploy::XPackage>());
325     }
326     OSL_ASSERT(extensionList.size() == 3);
327     return extensionList;
328 }
329 
330 uno::Sequence<Reference<deploy::XPackage> >
331 ExtensionManager::getExtensionsWithSameIdentifier(
332         OUString const & identifier,
333         OUString const & fileName,
334         Reference< ucb::XCommandEnvironment> const & xCmdEnv )
335         throw (
336             deploy::DeploymentException,
337             ucb::CommandFailedException,
338             lang::IllegalArgumentException,
339             uno::RuntimeException)
340 {
341     try
342     {
343         ::std::list<Reference<deploy::XPackage> > listExtensions =
344             getExtensionsWithSameId(
345                 identifier, fileName, xCmdEnv);
346         sal_Bool bHasExtension = false;
347 
348         //throw an IllegalArgumentException if there is no extension at all.
349         typedef  ::std::list<Reference<deploy::XPackage> >::const_iterator CIT;
350         for (CIT i = listExtensions.begin(); i != listExtensions.end(); i++)
351             bHasExtension |= i->is();
352         if (!bHasExtension)
353             throw lang::IllegalArgumentException(
354                 OUSTR("Could not find extension: ") + identifier + OUSTR(", ") + fileName,
355                 static_cast<cppu::OWeakObject*>(this), -1);
356 
357         return comphelper::containerToSequence<
358             Reference<deploy::XPackage>,
359             ::std::list<Reference<deploy::XPackage> >
360             > (listExtensions);
361     }
362     catch (deploy::DeploymentException & )
363     {
364         throw;
365     }
366     catch ( ucb::CommandFailedException & )
367     {
368         throw;
369     }
370     catch (lang::IllegalArgumentException &)
371     {
372         throw;
373     }
374     catch (...)
375     {
376         uno::Any exc = ::cppu::getCaughtException();
377         throw deploy::DeploymentException(
378             OUSTR("Extension Manager: exception during getExtensionsWithSameIdentifier"),
379             static_cast<OWeakObject*>(this), exc);
380     }
381 }
382 
383 
384 
385 bool ExtensionManager::isUserDisabled(
386     OUString const & identifier, OUString const & fileName)
387 {
388 	::std::list<Reference<deploy::XPackage> > listExtensions;
389 
390 	try {
391 		listExtensions = getExtensionsWithSameId(identifier, fileName);
392 	} catch (lang::IllegalArgumentException & ) {
393 	}
394     OSL_ASSERT(listExtensions.size() == 3);
395 
396     return isUserDisabled( ::comphelper::containerToSequence<
397                            Reference<deploy::XPackage>,
398                            ::std::list<Reference<deploy::XPackage> >
399                            > (listExtensions));
400 }
401 
402 bool ExtensionManager::isUserDisabled(
403     uno::Sequence<Reference<deploy::XPackage> > const & seqExtSameId)
404 {
405     OSL_ASSERT(seqExtSameId.getLength() == 3);
406     Reference<deploy::XPackage> const & userExtension = seqExtSameId[0];
407     if (userExtension.is())
408     {
409         beans::Optional<beans::Ambiguous<sal_Bool> > reg =
410             userExtension->isRegistered(Reference<task::XAbortChannel>(),
411                                         Reference<ucb::XCommandEnvironment>());
412         //If the value is ambiguous is than we assume that the extension
413         //is enabled, but something went wrong during enabling. We do not
414         //automatically disable user extensions.
415         if (reg.IsPresent &&
416             ! reg.Value.IsAmbiguous && ! reg.Value.Value)
417             return true;
418     }
419     return false;
420 }
421 
422 /*
423     This method determines the active extension (XPackage.registerPackage) with a
424     particular identifier.
425 
426     The parameter bUserDisabled determines if the user extension is disabled.
427 
428     When the user repository contains an extension with the given identifier and
429     it is not disabled by the user, then it is always registered.  Otherwise an
430     extension is only registered when there is no registered extension in one of
431     the repositories with a higher priority. That is, if the extension is from
432     the shared repository and an active extension with the same identifer is in
433     the user repository, then the extension is not registered. Similarly a
434     bundled extension is not registered if there is an active extension with the
435     same identifier in the shared or user repository.
436 */
437 void ExtensionManager::activateExtension(
438     OUString const & identifier, OUString const & fileName,
439     bool bUserDisabled,
440     bool bStartup,
441     Reference<task::XAbortChannel> const & xAbortChannel,
442     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
443 {
444     ::std::list<Reference<deploy::XPackage> > listExtensions;
445 	try {
446         listExtensions = getExtensionsWithSameId(identifier, fileName);
447 	} catch (lang::IllegalArgumentException &) {
448 	}
449     OSL_ASSERT(listExtensions.size() == 3);
450 
451     activateExtension(
452         ::comphelper::containerToSequence<
453         Reference<deploy::XPackage>,
454         ::std::list<Reference<deploy::XPackage> >
455         > (listExtensions),
456         bUserDisabled, bStartup, xAbortChannel, xCmdEnv);
457 
458     fireModified();
459 }
460 
461 void ExtensionManager::activateExtension(
462     uno::Sequence<Reference<deploy::XPackage> > const & seqExt,
463     bool bUserDisabled,
464     bool bStartup,
465     Reference<task::XAbortChannel> const & xAbortChannel,
466     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
467 {
468     bool bActive = false;
469     sal_Int32 len = seqExt.getLength();
470     for (sal_Int32 i = 0; i < len; i++)
471     {
472         Reference<deploy::XPackage> const & aExt =  seqExt[i];
473         if (aExt.is())
474         {
475             //get the registration value of the current iteration
476             beans::Optional<beans::Ambiguous<sal_Bool> > optReg =
477                 aExt->isRegistered(xAbortChannel, xCmdEnv);
478             //If nothing can be registered then break
479             if (!optReg.IsPresent)
480                 break;
481 
482             //Check if this is a disabled user extension,
483             if (i == 0 && bUserDisabled)
484             {
485                    aExt->revokePackage(xAbortChannel, xCmdEnv);
486                    continue;
487             }
488 
489             //If we have already determined an active extension then we must
490             //make sure to unregister all extensions with the same id in
491             //repositories with a lower priority
492             if (bActive)
493             {
494                 aExt->revokePackage(xAbortChannel, xCmdEnv);
495             }
496             else
497             {
498                 //This is the first extension in the ordered list, which becomes
499                 //the active extension
500                 bActive = true;
501                 //Register if not already done.
502                 //reregister if the value is ambiguous, which indicates that
503                 //something went wrong during last registration.
504                 aExt->registerPackage(bStartup, xAbortChannel, xCmdEnv);
505             }
506         }
507     }
508 }
509 
510 Reference<deploy::XPackage> ExtensionManager::backupExtension(
511     OUString const & identifier, OUString const & fileName,
512     Reference<deploy::XPackageManager> const & xPackageManager,
513     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
514 {
515     Reference<deploy::XPackage> xBackup;
516     Reference<ucb::XCommandEnvironment> tmpCmdEnv(
517         new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler()));
518     Reference<deploy::XPackage> xOldExtension;
519     xOldExtension = xPackageManager->getDeployedPackage(
520             identifier, fileName, tmpCmdEnv);
521 
522     if (xOldExtension.is())
523     {
524         xBackup = getTmpRepository()->addPackage(
525             xOldExtension->getURL(), uno::Sequence<beans::NamedValue>(),
526             OUString(), Reference<task::XAbortChannel>(), tmpCmdEnv);
527 
528         OSL_ENSURE(xBackup.is(), "Failed to backup extension");
529     }
530     return xBackup;
531 }
532 
533 //The supported package types are actually determined by the registry. However
534 //creating a registry
535 //(desktop/source/deployment/registry/dp_registry.cxx:PackageRegistryImpl) will
536 //create all the backends, so that the registry can obtain from them the package
537 //types. Creating the registry will also set up the registry folder containing
538 //all the subfolders for the respective backends.
539 //Because all repositories support the same backends, we can just delegate this
540 //call to one of the repositories.
541 uno::Sequence< Reference<deploy::XPackageTypeInfo> >
542 ExtensionManager::getSupportedPackageTypes()
543     throw (uno::RuntimeException)
544 {
545     return getUserRepository()->getSupportedPackageTypes();
546 }
547 //Do some necessary checks and user interaction. This function does not
548 //aquire the extension manager mutex and that mutex must not be aquired
549 //when this function is called. doChecksForAddExtension does  synchronous
550 //user interactions which may require aquiring the solar mutex.
551 //Returns true if the extension can be installed.
552 bool ExtensionManager::doChecksForAddExtension(
553     Reference<deploy::XPackageManager> const & xPackageMgr,
554     uno::Sequence<beans::NamedValue> const & properties,
555     css::uno::Reference<css::deployment::XPackage> const & xTmpExtension,
556     Reference<task::XAbortChannel> const & xAbortChannel,
557     Reference<ucb::XCommandEnvironment> const & xCmdEnv,
558     Reference<deploy::XPackage> & out_existingExtension )
559     throw (deploy::DeploymentException,
560            ucb::CommandFailedException,
561            ucb::CommandAbortedException,
562            lang::IllegalArgumentException,
563            uno::RuntimeException)
564 {
565     try
566     {
567         Reference<deploy::XPackage> xOldExtension;
568         const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension);
569         const OUString sFileName = xTmpExtension->getName();
570         const OUString sDisplayName = xTmpExtension->getDisplayName();
571         const OUString sVersion = xTmpExtension->getVersion();
572 
573         try
574         {
575             xOldExtension = xPackageMgr->getDeployedPackage(
576                 sIdentifier, sFileName, xCmdEnv);
577             out_existingExtension = xOldExtension;
578         }
579         catch (lang::IllegalArgumentException &)
580         {
581         }
582         bool bCanInstall = false;
583 
584         //This part is not guarded against other threads removing, adding, disabling ...
585         //etc. the same extension.
586         //checkInstall is safe because it notifies the user if the extension is not yet
587         //installed in the same repository. Because addExtension has its own guard
588         //(m_addMutex), another thread cannot add the extension in the meantime.
589         //checkUpdate is called if the same extension exists in the same
590         //repository. The user is asked if they want to replace it.  Another
591         //thread
592         //could already remove the extension. So asking the user was not
593         //necessary. No harm is done. The other thread may also ask the user
594         //if he wants to remove the extension. This depends on the
595         //XCommandEnvironment which it passes to removeExtension.
596         if (xOldExtension.is())
597         {
598             //throws a CommandFailedException if the user cancels
599             //the action.
600             checkUpdate(sVersion, sDisplayName,xOldExtension, xCmdEnv);
601         }
602         else
603         {
604             //throws a CommandFailedException if the user cancels
605             //the action.
606             checkInstall(sDisplayName, xCmdEnv);
607         }
608         //Prevent showing the license if requested.
609         Reference<ucb::XCommandEnvironment> _xCmdEnv(xCmdEnv);
610         ExtensionProperties props(OUString(), properties, Reference<ucb::XCommandEnvironment>());
611 
612         dp_misc::DescriptionInfoset info(dp_misc::getDescriptionInfoset(xTmpExtension->getURL()));
613         const ::boost::optional<dp_misc::SimpleLicenseAttributes> licenseAttributes =
614             info.getSimpleLicenseAttributes();
615 
616         if (licenseAttributes && licenseAttributes->suppressIfRequired
617             && props.isSuppressedLicense())
618             _xCmdEnv = Reference<ucb::XCommandEnvironment>(
619                 new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler()));
620 
621         bCanInstall = xTmpExtension->checkPrerequisites(
622             xAbortChannel, _xCmdEnv, xOldExtension.is() || props.isExtensionUpdate()) == 0 ? true : false;
623 
624         return bCanInstall;
625     }
626     catch (deploy::DeploymentException& ) {
627         throw;
628     } catch (ucb::CommandFailedException & ) {
629         throw;
630     } catch (ucb::CommandAbortedException & ) {
631         throw;
632     } catch (lang::IllegalArgumentException &) {
633         throw;
634     } catch (uno::RuntimeException &) {
635         throw;
636     } catch (uno::Exception &) {
637         uno::Any excOccurred = ::cppu::getCaughtException();
638         deploy::DeploymentException exc(
639             OUSTR("Extension Manager: exception in doChecksForAddExtension"),
640             static_cast<OWeakObject*>(this), excOccurred);
641         throw exc;
642     } catch (...) {
643         throw uno::RuntimeException(
644             OUSTR("Extension Manager: unexpected exception in doChecksForAddExtension"),
645             static_cast<OWeakObject*>(this));
646     }
647 }
648 
649 // Only add to shared and user repository
650 Reference<deploy::XPackage> ExtensionManager::addExtension(
651     OUString const & url, uno::Sequence<beans::NamedValue> const & properties,
652     OUString const & repository,
653         Reference<task::XAbortChannel> const & xAbortChannel,
654         Reference<ucb::XCommandEnvironment> const & xCmdEnv )
655         throw (deploy::DeploymentException,
656                ucb::CommandFailedException,
657                ucb::CommandAbortedException,
658                lang::IllegalArgumentException,
659                uno::RuntimeException)
660 {
661     Reference<deploy::XPackage> xNewExtension;
662     //Determine the repository to use
663     Reference<deploy::XPackageManager> xPackageManager;
664     if (repository.equals(OUSTR("user")))
665         xPackageManager = getUserRepository();
666     else if (repository.equals(OUSTR("shared")))
667         xPackageManager = getSharedRepository();
668     else
669         throw lang::IllegalArgumentException(
670             OUSTR("No valid repository name provided."),
671             static_cast<cppu::OWeakObject*>(this), 0);
672     //We must make sure that the xTmpExtension is not create twice, because this
673     //would remove the first one.
674     ::osl::MutexGuard addGuard(m_addMutex);
675 
676     Reference<deploy::XPackage> xTmpExtension =
677         getTempExtension(url, xAbortChannel, xCmdEnv);
678     //Make sure the extension is removed from the tmp repository in case
679     //of an exception
680     ExtensionRemoveGuard tmpExtensionRemoveGuard(xTmpExtension, getTmpRepository());
681     const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension);
682     const OUString sFileName = xTmpExtension->getName();
683     Reference<deploy::XPackage> xOldExtension;
684     Reference<deploy::XPackage> xExtensionBackup;
685 
686     uno::Any excOccurred2;
687     bool bUserDisabled = false;
688     bool bCanInstall = doChecksForAddExtension(
689         xPackageManager,
690         properties,
691         xTmpExtension,
692         xAbortChannel,
693         xCmdEnv,
694         xOldExtension );
695 
696     {
697         // In this garded section (getMutex) we must not use the argument xCmdEnv
698         // because it may bring up dialogs (XInteractionHandler::handle) this
699         //may potententially deadlock. See issue
700         //http://qa.openoffice.org/issues/show_bug.cgi?id=114933
701         //By not providing xCmdEnv the underlying APIs will throw an exception if
702         //the XInteractionRequest cannot be handled
703         ::osl::MutexGuard guard(getMutex());
704 
705         if (bCanInstall)
706         {
707             try
708             {
709                 bUserDisabled = isUserDisabled(sIdentifier, sFileName);
710                 if (xOldExtension.is())
711                 {
712                     try
713                     {
714                         xOldExtension->revokePackage(
715                             xAbortChannel, Reference<ucb::XCommandEnvironment>());
716                         //save the old user extension in case the user aborts
717                         //store the extension in the tmp repository, this will overwrite
718                         //xTmpPackage (same identifier). Do not let the user abort or
719                         //interact
720                         //importing the old extension in the tmp repository will remove
721                         //the xTmpExtension
722                         //no command environment supplied, only this class shall interact
723                         //with the user!
724                         xExtensionBackup = getTmpRepository()->importExtension(
725                             xOldExtension, Reference<task::XAbortChannel>(),
726                             Reference<ucb::XCommandEnvironment>());
727                         tmpExtensionRemoveGuard.reset(xExtensionBackup);
728                         //xTmpExtension will later be used to check the dependencies
729                         //again. However, only xExtensionBackup will be later removed
730                         //from the tmp repository
731                         xTmpExtension = xExtensionBackup;
732                         OSL_ASSERT(xTmpExtension.is());
733                     }
734                     catch (lang::DisposedException &)
735                     {
736                         //Another thread might have removed the extension meanwhile
737                     }
738                 }
739                 //check again dependencies but prevent user interaction,
740                 //We can disregard the license, because the user must have already
741                 //accepted it, whe we called checkPrerequisites the first time
742                 SilentCheckPrerequisitesCommandEnv * pSilentCommandEnv =
743                     new SilentCheckPrerequisitesCommandEnv();
744                 Reference<ucb::XCommandEnvironment> silentCommandEnv(pSilentCommandEnv);
745 
746                 sal_Int32 failedPrereq = xTmpExtension->checkPrerequisites(
747                     xAbortChannel, silentCommandEnv, true);
748                 if (failedPrereq == 0)
749                 {
750                     xNewExtension = xPackageManager->addPackage(
751                         url, properties, OUString(), xAbortChannel,
752                         Reference<ucb::XCommandEnvironment>());
753                     //If we add a user extension and there is already one which was
754                     //disabled by a user, then the newly installed one is enabled. If we
755                     //add to another repository then the user extension remains
756                     //disabled.
757                     bool bUserDisabled2 = bUserDisabled;
758                     if (repository.equals(OUSTR("user")))
759                         bUserDisabled2 = false;
760 
761                     ::rtl::OUString const name(xNewExtension->getName());
762                     activateExtension(
763                         dp_misc::getIdentifier(xNewExtension),
764                         name, bUserDisabled2, false, xAbortChannel,
765                         Reference<ucb::XCommandEnvironment>());
766                 }
767                 else
768                 {
769                     if (pSilentCommandEnv->m_Exception.hasValue())
770                         ::cppu::throwException(pSilentCommandEnv->m_Exception);
771                     else if ( pSilentCommandEnv->m_UnknownException.hasValue())
772                         ::cppu::throwException(pSilentCommandEnv->m_UnknownException);
773                     else
774                         throw deploy::DeploymentException (
775                             OUSTR("Extension Manager: exception during addExtension, ckeckPrerequisites failed"),
776                             static_cast<OWeakObject*>(this), uno::Any());
777                 }
778             }
779             catch (deploy::DeploymentException& ) {
780                 excOccurred2 = ::cppu::getCaughtException();
781             } catch (ucb::CommandFailedException & ) {
782                 excOccurred2 = ::cppu::getCaughtException();
783             } catch (ucb::CommandAbortedException & ) {
784                 excOccurred2 = ::cppu::getCaughtException();
785             } catch (lang::IllegalArgumentException &) {
786                 excOccurred2 = ::cppu::getCaughtException();
787             } catch (uno::RuntimeException &) {
788                 excOccurred2 = ::cppu::getCaughtException();
789             } catch (...) {
790                 excOccurred2 = ::cppu::getCaughtException();
791                 deploy::DeploymentException exc(
792                     OUSTR("Extension Manager: exception during addExtension, url: ")
793                     + url, static_cast<OWeakObject*>(this), excOccurred2);
794                 excOccurred2 <<= exc;
795             }
796         }
797 
798         if (excOccurred2.hasValue())
799         {
800             //It does not matter what exception is thrown. We try to
801             //recover the original status.
802             //If the user aborted installation then a ucb::CommandAbortedException
803             //is thrown.
804             //Use a private AbortChannel so the user cannot interrupt.
805             try
806             {
807                 if (xExtensionBackup.is())
808                 {
809                     Reference<deploy::XPackage> xRestored =
810                         xPackageManager->importExtension(
811                             xExtensionBackup, Reference<task::XAbortChannel>(),
812                             Reference<ucb::XCommandEnvironment>());
813                 }
814                 activateExtension(
815                     sIdentifier, sFileName, bUserDisabled, false,
816                     Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>());
817             }
818             catch (...)
819             {
820             }
821             ::cppu::throwException(excOccurred2);
822         }
823     } // leaving the garded section (getMutex())
824 
825     try
826     {
827         fireModified();
828 
829     }catch (deploy::DeploymentException& ) {
830         throw;
831     } catch (ucb::CommandFailedException & ) {
832         throw;
833     } catch (ucb::CommandAbortedException & ) {
834         throw;
835     } catch (lang::IllegalArgumentException &) {
836         throw;
837     } catch (uno::RuntimeException &) {
838         throw;
839     } catch (uno::Exception &) {
840         uno::Any excOccurred = ::cppu::getCaughtException();
841         deploy::DeploymentException exc(
842             OUSTR("Extension Manager: exception in doChecksForAddExtension"),
843             static_cast<OWeakObject*>(this), excOccurred);
844         throw exc;
845     } catch (...) {
846         throw uno::RuntimeException(
847             OUSTR("Extension Manager: unexpected exception in doChecksForAddExtension"),
848             static_cast<OWeakObject*>(this));
849     }
850 
851     return xNewExtension;
852 }
853 
854 void ExtensionManager::removeExtension(
855     OUString const & identifier, OUString const & fileName,
856     OUString const & repository,
857     Reference<task::XAbortChannel> const & xAbortChannel,
858     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
859     throw (deploy::DeploymentException,
860            ucb::CommandFailedException,
861            ucb::CommandAbortedException,
862            lang::IllegalArgumentException,
863            uno::RuntimeException)
864 {
865     uno::Any excOccurred1;
866     Reference<deploy::XPackage> xExtensionBackup;
867     Reference<deploy::XPackageManager> xPackageManager;
868     bool bUserDisabled = false;
869     ::osl::MutexGuard guard(getMutex());
870     try
871     {
872 //Determine the repository to use
873         if (repository.equals(OUSTR("user")))
874             xPackageManager = getUserRepository();
875         else if (repository.equals(OUSTR("shared")))
876             xPackageManager = getSharedRepository();
877         else
878             throw lang::IllegalArgumentException(
879                 OUSTR("No valid repository name provided."),
880                 static_cast<cppu::OWeakObject*>(this), 0);
881 
882         bUserDisabled = isUserDisabled(identifier, fileName);
883         //Backup the extension, in case the user cancels the action
884         xExtensionBackup = backupExtension(
885             identifier, fileName, xPackageManager, xCmdEnv);
886 
887         //revoke the extension if it is active
888         Reference<deploy::XPackage> xOldExtension =
889             xPackageManager->getDeployedPackage(
890                 identifier, fileName, xCmdEnv);
891         xOldExtension->revokePackage(xAbortChannel, xCmdEnv);
892 
893         xPackageManager->removePackage(
894             identifier, fileName, xAbortChannel, xCmdEnv);
895         activateExtension(identifier, fileName, bUserDisabled, false,
896                           xAbortChannel, xCmdEnv);
897         fireModified();
898     }
899     catch (deploy::DeploymentException& ) {
900         excOccurred1 = ::cppu::getCaughtException();
901     } catch (ucb::CommandFailedException & ) {
902         excOccurred1 = ::cppu::getCaughtException();
903     } catch (ucb::CommandAbortedException & ) {
904         excOccurred1 = ::cppu::getCaughtException();
905     } catch (lang::IllegalArgumentException &) {
906         excOccurred1 = ::cppu::getCaughtException();
907     } catch (uno::RuntimeException &) {
908         excOccurred1 = ::cppu::getCaughtException();
909     } catch (...) {
910         excOccurred1 = ::cppu::getCaughtException();
911         deploy::DeploymentException exc(
912             OUSTR("Extension Manager: exception during removeEtension"),
913             static_cast<OWeakObject*>(this), excOccurred1);
914         excOccurred1 <<= exc;
915     }
916 
917     if (excOccurred1.hasValue())
918     {
919         //User aborted installation, restore the previous situation.
920         //Use a private AbortChannel so the user cannot interrupt.
921         try
922         {
923             Reference<ucb::XCommandEnvironment> tmpCmdEnv(
924                 new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler()));
925             if (xExtensionBackup.is())
926             {
927                 Reference<deploy::XPackage> xRestored =
928                     xPackageManager->importExtension(
929                         xExtensionBackup, Reference<task::XAbortChannel>(),
930                         tmpCmdEnv);
931                 activateExtension(
932                     identifier, fileName, bUserDisabled, false,
933                     Reference<task::XAbortChannel>(),
934                     tmpCmdEnv);
935 
936                 getTmpRepository()->removePackage(
937                     dp_misc::getIdentifier(xExtensionBackup),
938                     xExtensionBackup->getName(), xAbortChannel, xCmdEnv);
939                 fireModified();
940             }
941         }
942         catch (...)
943         {
944         }
945         ::cppu::throwException(excOccurred1);
946     }
947 
948     if (xExtensionBackup.is())
949         getTmpRepository()->removePackage(
950             dp_misc::getIdentifier(xExtensionBackup),
951             xExtensionBackup->getName(), xAbortChannel, xCmdEnv);
952 }
953 
954 // Only enable extensions from shared and user repository
955 void ExtensionManager::enableExtension(
956     Reference<deploy::XPackage> const & extension,
957     Reference<task::XAbortChannel> const & xAbortChannel,
958     Reference<ucb::XCommandEnvironment> const & xCmdEnv)
959     throw (deploy::DeploymentException,
960         ucb::CommandFailedException,
961         ucb::CommandAbortedException,
962         lang::IllegalArgumentException,
963         uno::RuntimeException)
964 {
965     ::osl::MutexGuard guard(getMutex());
966     bool bUserDisabled = false;
967     uno::Any excOccurred;
968     try
969     {
970         if (!extension.is())
971             return;
972         OUString repository = extension->getRepositoryName();
973         if (!repository.equals(OUSTR("user")))
974             throw lang::IllegalArgumentException(
975                 OUSTR("No valid repository name provided."),
976                 static_cast<cppu::OWeakObject*>(this), 0);
977 
978         bUserDisabled = isUserDisabled(dp_misc::getIdentifier(extension),
979                                        extension->getName());
980 
981         activateExtension(dp_misc::getIdentifier(extension),
982                           extension->getName(), false, false,
983                           xAbortChannel, xCmdEnv);
984     }
985     catch (deploy::DeploymentException& ) {
986         excOccurred = ::cppu::getCaughtException();
987     } catch (ucb::CommandFailedException & ) {
988         excOccurred = ::cppu::getCaughtException();
989     } catch (ucb::CommandAbortedException & ) {
990         excOccurred = ::cppu::getCaughtException();
991     } catch (lang::IllegalArgumentException &) {
992         excOccurred = ::cppu::getCaughtException();
993     } catch (uno::RuntimeException &) {
994         excOccurred = ::cppu::getCaughtException();
995     } catch (...) {
996         excOccurred = ::cppu::getCaughtException();
997         deploy::DeploymentException exc(
998             OUSTR("Extension Manager: exception during enableExtension"),
999             static_cast<OWeakObject*>(this), excOccurred);
1000         excOccurred <<= exc;
1001     }
1002 
1003     if (excOccurred.hasValue())
1004     {
1005         try
1006         {
1007             activateExtension(dp_misc::getIdentifier(extension),
1008                               extension->getName(), bUserDisabled, false,
1009                               xAbortChannel, xCmdEnv);
1010         }
1011         catch (...)
1012         {
1013         }
1014         ::cppu::throwException(excOccurred);
1015     }
1016 }
1017 
1018 /**
1019  */
1020 sal_Int32 ExtensionManager::checkPrerequisitesAndEnable(
1021     Reference<deploy::XPackage> const & extension,
1022     Reference<task::XAbortChannel> const & xAbortChannel,
1023     Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1024     throw (deploy::DeploymentException,
1025         ucb::CommandFailedException,
1026         ucb::CommandAbortedException,
1027         lang::IllegalArgumentException,
1028         uno::RuntimeException)
1029 {
1030     try
1031     {
1032         if (!extension.is())
1033             return 0;
1034         ::osl::MutexGuard guard(getMutex());
1035         sal_Int32 ret = 0;
1036         Reference<deploy::XPackageManager> mgr =
1037             getPackageManager(extension->getRepositoryName());
1038         ret = mgr->checkPrerequisites(extension, xAbortChannel, xCmdEnv);
1039         if (ret)
1040         {
1041             //There are some unfulfilled prerequisites, try to revoke
1042             extension->revokePackage(xAbortChannel, xCmdEnv);
1043         }
1044         const OUString id(dp_misc::getIdentifier(extension));
1045         activateExtension(id, extension->getName(),
1046                           isUserDisabled(id, extension->getName()), false,
1047                           xAbortChannel, xCmdEnv);
1048         return ret;
1049     }
1050     catch (deploy::DeploymentException& ) {
1051         throw;
1052     } catch (ucb::CommandFailedException & ) {
1053         throw;
1054     } catch (ucb::CommandAbortedException & ) {
1055         throw;
1056     } catch (lang::IllegalArgumentException &) {
1057         throw;
1058     } catch (uno::RuntimeException &) {
1059         throw;
1060     } catch (...) {
1061         uno::Any excOccurred = ::cppu::getCaughtException();
1062         deploy::DeploymentException exc(
1063             OUSTR("Extension Manager: exception during disableExtension"),
1064             static_cast<OWeakObject*>(this), excOccurred);
1065         throw exc;
1066     }
1067 }
1068 
1069 
1070 void ExtensionManager::disableExtension(
1071     Reference<deploy::XPackage> const & extension,
1072     Reference<task::XAbortChannel> const & xAbortChannel,
1073     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1074     throw (deploy::DeploymentException,
1075            ucb::CommandFailedException,
1076            ucb::CommandAbortedException,
1077            lang::IllegalArgumentException,
1078            uno::RuntimeException)
1079 {
1080     ::osl::MutexGuard guard(getMutex());
1081     uno::Any excOccurred;
1082     bool bUserDisabled = false;
1083     try
1084     {
1085         if (!extension.is())
1086             return;
1087         const OUString repository( extension->getRepositoryName());
1088         if (!repository.equals(OUSTR("user")))
1089             throw lang::IllegalArgumentException(
1090                 OUSTR("No valid repository name provided."),
1091                 static_cast<cppu::OWeakObject*>(this), 0);
1092 
1093         const OUString id(dp_misc::getIdentifier(extension));
1094         bUserDisabled = isUserDisabled(id, extension->getName());
1095 
1096         activateExtension(id, extension->getName(), true, false,
1097                           xAbortChannel, xCmdEnv);
1098     }
1099     catch (deploy::DeploymentException& ) {
1100         excOccurred = ::cppu::getCaughtException();
1101     } catch (ucb::CommandFailedException & ) {
1102         excOccurred = ::cppu::getCaughtException();
1103     } catch (ucb::CommandAbortedException & ) {
1104         excOccurred = ::cppu::getCaughtException();
1105     } catch (lang::IllegalArgumentException &) {
1106         excOccurred = ::cppu::getCaughtException();
1107     } catch (uno::RuntimeException &) {
1108         excOccurred = ::cppu::getCaughtException();
1109     } catch (...) {
1110         excOccurred = ::cppu::getCaughtException();
1111         deploy::DeploymentException exc(
1112             OUSTR("Extension Manager: exception during disableExtension"),
1113             static_cast<OWeakObject*>(this), excOccurred);
1114         excOccurred <<= exc;
1115     }
1116 
1117     if (excOccurred.hasValue())
1118     {
1119         try
1120         {
1121             activateExtension(dp_misc::getIdentifier(extension),
1122                               extension->getName(), bUserDisabled, false,
1123                               xAbortChannel, xCmdEnv);
1124         }
1125         catch (...)
1126         {
1127         }
1128         ::cppu::throwException(excOccurred);
1129     }
1130 }
1131 
1132 uno::Sequence< Reference<deploy::XPackage> >
1133     ExtensionManager::getDeployedExtensions(
1134     OUString const & repository,
1135     Reference<task::XAbortChannel> const &xAbort,
1136     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1137     throw (deploy::DeploymentException,
1138         ucb::CommandFailedException,
1139         ucb::CommandAbortedException,
1140         lang::IllegalArgumentException,
1141         uno::RuntimeException)
1142 {
1143     return getPackageManager(repository)->getDeployedPackages(
1144         xAbort, xCmdEnv);
1145 }
1146 
1147 Reference<deploy::XPackage>
1148     ExtensionManager::getDeployedExtension(
1149     OUString const & repository,
1150     OUString const & identifier,
1151     OUString const & filename,
1152     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1153     throw (deploy::DeploymentException,
1154         ucb::CommandFailedException,
1155         lang::IllegalArgumentException,
1156         uno::RuntimeException)
1157 {
1158     return getPackageManager(repository)->getDeployedPackage(
1159         identifier, filename, xCmdEnv);
1160 }
1161 
1162 uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > >
1163     ExtensionManager::getAllExtensions(
1164     Reference<task::XAbortChannel> const & xAbort,
1165     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1166     throw (deploy::DeploymentException,
1167         ucb::CommandFailedException,
1168         ucb::CommandAbortedException,
1169         lang::IllegalArgumentException,
1170         uno::RuntimeException)
1171 {
1172     try
1173     {
1174         id2extensions mapExt;
1175 
1176         uno::Sequence<Reference<deploy::XPackage> > userExt =
1177             getUserRepository()->getDeployedPackages(xAbort, xCmdEnv);
1178         addExtensionsToMap(mapExt, userExt, OUSTR("user"));
1179         uno::Sequence<Reference<deploy::XPackage> > sharedExt =
1180             getSharedRepository()->getDeployedPackages(xAbort, xCmdEnv);
1181         addExtensionsToMap(mapExt, sharedExt, OUSTR("shared"));
1182         uno::Sequence<Reference<deploy::XPackage> > bundledExt =
1183             getBundledRepository()->getDeployedPackages(xAbort, xCmdEnv);
1184         addExtensionsToMap(mapExt, bundledExt, OUSTR("bundled"));
1185 
1186         //copy the values of the map to a vector for sorting
1187         ::std::vector< ::std::vector<Reference<deploy::XPackage> > >
1188               vecExtensions;
1189         id2extensions::const_iterator mapIt = mapExt.begin();
1190         for (;mapIt != mapExt.end(); mapIt++)
1191             vecExtensions.push_back(mapIt->second);
1192 
1193         //sort the element according to the identifier
1194         ::std::sort(vecExtensions.begin(), vecExtensions.end(), CompIdentifiers());
1195 
1196         ::std::vector< ::std::vector<Reference<deploy::XPackage> > >::const_iterator
1197               citVecVec = vecExtensions.begin();
1198         sal_Int32 j = 0;
1199         uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > > seqSeq(vecExtensions.size());
1200         for (;citVecVec != vecExtensions.end(); citVecVec++, j++)
1201         {
1202             seqSeq[j] = comphelper::containerToSequence(*citVecVec);
1203         }
1204         return seqSeq;
1205 
1206     } catch (deploy::DeploymentException& ) {
1207         throw;
1208     } catch (ucb::CommandFailedException & ) {
1209         throw;
1210     } catch (ucb::CommandAbortedException & ) {
1211         throw;
1212     } catch (lang::IllegalArgumentException &) {
1213         throw;
1214     } catch (uno::RuntimeException &) {
1215         throw;
1216     } catch (...) {
1217         uno::Any exc = ::cppu::getCaughtException();
1218         throw deploy::DeploymentException(
1219             OUSTR("Extension Manager: exception during enableExtension"),
1220             static_cast<OWeakObject*>(this), exc);
1221    }
1222 }
1223 
1224 //only to be called from unopkg!!!
1225 void ExtensionManager::reinstallDeployedExtensions(
1226     OUString const & repository,
1227     Reference<task::XAbortChannel> const & xAbortChannel,
1228     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1229     throw (deploy::DeploymentException,
1230         ucb::CommandFailedException, ucb::CommandAbortedException,
1231         lang::IllegalArgumentException, uno::RuntimeException)
1232 {
1233     try
1234     {
1235         Reference<deploy::XPackageManager>
1236             xPackageManager = getPackageManager(repository);
1237 
1238         ::osl::MutexGuard guard(getMutex());
1239         xPackageManager->reinstallDeployedPackages(xAbortChannel, xCmdEnv);
1240         //We must sync here, otherwise we will get exceptions when extensions
1241         //are removed.
1242         dp_misc::syncRepositories(xCmdEnv);
1243         const uno::Sequence< Reference<deploy::XPackage> > extensions(
1244             xPackageManager->getDeployedPackages(xAbortChannel, xCmdEnv));
1245 
1246         for ( sal_Int32 pos = 0; pos < extensions.getLength(); ++pos )
1247         {
1248             try
1249             {
1250                 const OUString id =  dp_misc::getIdentifier(extensions[ pos ]);
1251                 const OUString fileName = extensions[ pos ]->getName();
1252                 OSL_ASSERT(id.getLength());
1253                 activateExtension(id, fileName, false, true, xAbortChannel, xCmdEnv );
1254             }
1255             catch (lang::DisposedException &)
1256             {
1257             }
1258         }
1259     } catch (deploy::DeploymentException& ) {
1260         throw;
1261     } catch (ucb::CommandFailedException & ) {
1262         throw;
1263     } catch (ucb::CommandAbortedException & ) {
1264         throw;
1265     } catch (lang::IllegalArgumentException &) {
1266         throw;
1267     } catch (uno::RuntimeException &) {
1268         throw;
1269     } catch (...) {
1270         uno::Any exc = ::cppu::getCaughtException();
1271         throw deploy::DeploymentException(
1272             OUSTR("Extension Manager: exception during enableExtension"),
1273             static_cast<OWeakObject*>(this), exc);
1274     }
1275 }
1276 
1277 /** Works on the bundled repository. That is using the variables
1278     BUNDLED_EXTENSIONS and BUNDLED_EXTENSIONS_USER.
1279  */
1280 void ExtensionManager::synchronizeBundledPrereg(
1281     Reference<task::XAbortChannel> const & xAbortChannel,
1282     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1283     throw (deploy::DeploymentException,
1284            uno::RuntimeException)
1285 {
1286     try
1287     {
1288         String sSynchronizingBundled(StrSyncRepository::get());
1289         sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled"));
1290         dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled);
1291 
1292         Reference<deploy::XPackageManagerFactory> xPackageManagerFactory(
1293             deploy::thePackageManagerFactory::get(m_xContext));
1294 
1295         Reference<deploy::XPackageManager> xMgr =
1296             xPackageManagerFactory->getPackageManager(OUSTR("bundled_prereg"));
1297         xMgr->synchronize(xAbortChannel, xCmdEnv);
1298         progressBundled.update(OUSTR("\n\n"));
1299 
1300         uno::Sequence<Reference<deploy::XPackage> > extensions = xMgr->getDeployedPackages(
1301             xAbortChannel, xCmdEnv);
1302         try
1303         {
1304             for (sal_Int32 i = 0; i < extensions.getLength(); i++)
1305             {
1306                 extensions[i]->registerPackage(true, xAbortChannel, xCmdEnv);
1307             }
1308         }
1309         catch (...)
1310         {
1311             OSL_ASSERT(0);
1312         }
1313         OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM(
1314                                      "$BUNDLED_EXTENSIONS_PREREG/lastsynchronized"));
1315         writeLastModified(lastSyncBundled, xCmdEnv);
1316 
1317     } catch (deploy::DeploymentException& ) {
1318         throw;
1319     } catch (ucb::CommandFailedException & ) {
1320         throw;
1321     } catch (ucb::CommandAbortedException & ) {
1322         throw;
1323     } catch (lang::IllegalArgumentException &) {
1324         throw;
1325     } catch (uno::RuntimeException &) {
1326         throw;
1327     } catch (...) {
1328         uno::Any exc = ::cppu::getCaughtException();
1329         throw deploy::DeploymentException(
1330             OUSTR("Extension Manager: exception in synchronize"),
1331             static_cast<OWeakObject*>(this), exc);
1332     }
1333 }
1334 
1335 sal_Bool ExtensionManager::synchronize(
1336     Reference<task::XAbortChannel> const & xAbortChannel,
1337     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1338     throw (deploy::DeploymentException,
1339            ucb::CommandFailedException,
1340            ucb::CommandAbortedException,
1341            lang::IllegalArgumentException,
1342            uno::RuntimeException)
1343 {
1344     try
1345     {
1346         sal_Bool bModified = sal_False;
1347 
1348         ::osl::MutexGuard guard(getMutex());
1349         String sSynchronizingShared(StrSyncRepository::get());
1350         sSynchronizingShared.SearchAndReplaceAllAscii( "%NAME", OUSTR("shared"));
1351         dp_misc::ProgressLevel progressShared(xCmdEnv, sSynchronizingShared);
1352         bModified = getSharedRepository()->synchronize(xAbortChannel, xCmdEnv);
1353         progressShared.update(OUSTR("\n\n"));
1354 
1355         String sSynchronizingBundled(StrSyncRepository::get());
1356         sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled"));
1357         dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled);
1358         bModified |= getBundledRepository()->synchronize(xAbortChannel, xCmdEnv);
1359         progressBundled.update(OUSTR("\n\n"));
1360 
1361         //Always determine the active extension. This is necessary for the
1362         //first-start optimization. The setup creates the registration data for the
1363         //bundled extensions (brand_layer/share/prereg/bundled), which is copied to the user
1364         //installation (user_installation/extension/bundled) when a user starts OOo
1365         //for the first time after running setup. All bundled extensions are registered
1366         //at that moment. However, extensions with the same identifier can be in the
1367         //shared or user repository, in which case the respective bundled extensions must
1368         //be revoked.
1369         try
1370         {
1371             const uno::Sequence<uno::Sequence<Reference<deploy::XPackage> > >
1372                 seqSeqExt = getAllExtensions(xAbortChannel, xCmdEnv);
1373             for (sal_Int32 i = 0; i < seqSeqExt.getLength(); i++)
1374             {
1375                 uno::Sequence<Reference<deploy::XPackage> > const & seqExt =
1376                     seqSeqExt[i];
1377                 activateExtension(seqExt, isUserDisabled(seqExt), true,
1378                                   xAbortChannel, xCmdEnv);
1379             }
1380         }
1381         catch (...)
1382         {
1383             //We catch the exception, so we can write the lastmodified file
1384             //so we will no repeat this everytime OOo starts.
1385             OSL_ENSURE(0, "Extensions Manager: synchronize");
1386         }
1387         OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM(
1388                                      "$BUNDLED_EXTENSIONS_USER/lastsynchronized"));
1389         writeLastModified(lastSyncBundled, xCmdEnv);
1390         OUString lastSyncShared(RTL_CONSTASCII_USTRINGPARAM(
1391                                     "$SHARED_EXTENSIONS_USER/lastsynchronized"));
1392         writeLastModified(lastSyncShared, xCmdEnv);
1393         return bModified;
1394     } catch (deploy::DeploymentException& ) {
1395         throw;
1396     } catch (ucb::CommandFailedException & ) {
1397         throw;
1398     } catch (ucb::CommandAbortedException & ) {
1399         throw;
1400     } catch (lang::IllegalArgumentException &) {
1401         throw;
1402     } catch (uno::RuntimeException &) {
1403         throw;
1404     } catch (...) {
1405         uno::Any exc = ::cppu::getCaughtException();
1406         throw deploy::DeploymentException(
1407             OUSTR("Extension Manager: exception in synchronize"),
1408             static_cast<OWeakObject*>(this), exc);
1409     }
1410 }
1411 
1412 // Notify the user when a new extension is to be installed. This is only the
1413 // case when one uses the system integration to install an extension (double
1414 // clicking on .oxt file etc.)). The function must only be called if there is no
1415 // extension with the same identifier already deployed. Then the checkUpdate
1416 // function will inform the user that the extension is about to be installed In
1417 // case the user cancels the installation a CommandFailed exception is
1418 // thrown.
1419 void ExtensionManager::checkInstall(
1420 	OUString const & displayName,
1421     Reference<ucb::XCommandEnvironment> const & cmdEnv)
1422 {
1423         uno::Any request(
1424 			deploy::InstallException(
1425 				OUSTR("Extension ") + displayName +
1426                 OUSTR(" is about to be installed."),
1427 				static_cast<OWeakObject *>(this), displayName));
1428 	    bool approve = false, abort = false;
1429         if (! dp_misc::interactContinuation(
1430                 request, task::XInteractionApprove::static_type(),
1431                 cmdEnv, &approve, &abort ))
1432 		{
1433             OSL_ASSERT( !approve && !abort );
1434             throw deploy::DeploymentException(
1435                 dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName,
1436                 static_cast<OWeakObject *>(this), request );
1437         }
1438         if (abort || !approve)
1439             throw ucb::CommandFailedException(
1440                 dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName,
1441                 static_cast<OWeakObject *>(this), request );
1442 }
1443 
1444 /* The function will make the user interaction in case there is an extension
1445 installed with the same id. This function may only be called if there is already
1446 an extension.
1447 */
1448 void ExtensionManager::checkUpdate(
1449     OUString const & newVersion,
1450     OUString const & newDisplayName,
1451     Reference<deploy::XPackage> const & oldExtension,
1452     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1453 {
1454     // package already deployed, interact --force:
1455     uno::Any request(
1456         (deploy::VersionException(
1457             dp_misc::getResourceString(
1458                 RID_STR_PACKAGE_ALREADY_ADDED ) + newDisplayName,
1459             static_cast<OWeakObject *>(this), newVersion, newDisplayName,
1460             oldExtension ) ) );
1461     bool replace = false, abort = false;
1462     if (! dp_misc::interactContinuation(
1463             request, task::XInteractionApprove::static_type(),
1464             xCmdEnv, &replace, &abort )) {
1465         OSL_ASSERT( !replace && !abort );
1466         throw deploy::DeploymentException(
1467             dp_misc::getResourceString(
1468                 RID_STR_ERROR_WHILE_ADDING) + newDisplayName,
1469             static_cast<OWeakObject *>(this), request );
1470     }
1471     if (abort || !replace)
1472         throw ucb::CommandFailedException(
1473             dp_misc::getResourceString(
1474                 RID_STR_PACKAGE_ALREADY_ADDED) + newDisplayName,
1475             static_cast<OWeakObject *>(this), request );
1476 }
1477 
1478 Reference<deploy::XPackage> ExtensionManager::getTempExtension(
1479     OUString const & url,
1480     Reference<task::XAbortChannel> const & xAbortChannel,
1481     Reference<ucb::XCommandEnvironment> const & /*xCmdEnv*/)
1482 
1483 {
1484     Reference<ucb::XCommandEnvironment> tmpCmdEnvA(new TmpRepositoryCommandEnv());
1485     Reference<deploy::XPackage> xTmpPackage = getTmpRepository()->addPackage(
1486         url, uno::Sequence<beans::NamedValue>(),OUString(), xAbortChannel, tmpCmdEnvA);
1487     if (!xTmpPackage.is())
1488     {
1489         throw deploy::DeploymentException(
1490             OUSTR("Extension Manager: Failed to create temporary XPackage for url: ") + url,
1491             static_cast<OWeakObject*>(this), uno::Any());
1492 
1493     }
1494     return xTmpPackage;
1495 }
1496 
1497 uno::Sequence<Reference<deploy::XPackage> > SAL_CALL
1498 ExtensionManager::getExtensionsWithUnacceptedLicenses(
1499         OUString const & repository,
1500         Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1501         throw (deploy::DeploymentException,
1502                uno::RuntimeException)
1503 {
1504     Reference<deploy::XPackageManager>
1505         xPackageManager = getPackageManager(repository);
1506     ::osl::MutexGuard guard(getMutex());
1507     return xPackageManager->getExtensionsWithUnacceptedLicenses(xCmdEnv);
1508 }
1509 
1510 sal_Bool ExtensionManager::isReadOnlyRepository(::rtl::OUString const & repository)
1511         throw (uno::RuntimeException)
1512 {
1513     return getPackageManager(repository)->isReadOnly();
1514 }
1515 //------------------------------------------------------------------------------
1516 //------------------------------------------------------------------------------
1517 //------------------------------------------------------------------------------
1518 
1519 namespace sdecl = comphelper::service_decl;
1520 sdecl::class_<ExtensionManager> servicePIP;
1521 extern sdecl::ServiceDecl const serviceDecl(
1522     servicePIP,
1523     // a private one:
1524     "com.sun.star.comp.deployment.ExtensionManager",
1525     "com.sun.star.comp.deployment.ExtensionManager");
1526 
1527 //------------------------------------------------------------------------------
1528 bool singleton_entries(
1529     uno::Reference< registry::XRegistryKey > const & xRegistryKey )
1530 {
1531     try {
1532         uno::Reference< registry::XRegistryKey > xKey(
1533             xRegistryKey->createKey(
1534                 serviceDecl.getImplementationName() +
1535                 // xxx todo: use future generated function to get singleton name
1536                 OUSTR("/UNO/SINGLETONS/"
1537                       "com.sun.star.deployment.ExtensionManager") ) );
1538         xKey->setStringValue( serviceDecl.getSupportedServiceNames()[0] );
1539         return true;
1540     }
1541     catch (registry::InvalidRegistryException & exc) {
1542         (void) exc; // avoid warnings
1543         OSL_ENSURE( 0, ::rtl::OUStringToOString(
1544                         exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1545         return false;
1546     }
1547 }
1548 
1549 // XModifyBroadcaster
1550 //______________________________________________________________________________
1551 void ExtensionManager::addModifyListener(
1552     Reference<util::XModifyListener> const & xListener )
1553     throw (uno::RuntimeException)
1554 {
1555      check();
1556      rBHelper.addListener( ::getCppuType( &xListener ), xListener );
1557 }
1558 
1559 //______________________________________________________________________________
1560 void ExtensionManager::removeModifyListener(
1561     Reference<util::XModifyListener> const & xListener )
1562     throw (uno::RuntimeException)
1563 {
1564     check();
1565     rBHelper.removeListener( ::getCppuType( &xListener ), xListener );
1566 }
1567 
1568 void ExtensionManager::check()
1569 {
1570     ::osl::MutexGuard guard( getMutex() );
1571     if (rBHelper.bInDispose || rBHelper.bDisposed) {
1572         throw lang::DisposedException(
1573             OUSTR("ExtensionManager instance has already been disposed!"),
1574             static_cast<OWeakObject *>(this) );
1575     }
1576 }
1577 
1578 void ExtensionManager::fireModified()
1579 {
1580     ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer(
1581         util::XModifyListener::static_type() );
1582     if (pContainer != 0) {
1583         pContainer->forEach<util::XModifyListener>(
1584             boost::bind(&util::XModifyListener::modified, _1,
1585                         lang::EventObject(static_cast<OWeakObject *>(this))) );
1586     }
1587 }
1588 
1589 } // namespace dp_manager
1590 
1591 
1592