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