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