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