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         // Create the tmp repository to trigger its clean up (deletion
1187         // of old temporary data.)
1188         getTmpRepository();
1189 
1190         //copy the values of the map to a vector for sorting
1191         ::std::vector< ::std::vector<Reference<deploy::XPackage> > >
1192               vecExtensions;
1193         id2extensions::const_iterator mapIt = mapExt.begin();
1194         for (;mapIt != mapExt.end(); mapIt++)
1195             vecExtensions.push_back(mapIt->second);
1196 
1197         //sort the element according to the identifier
1198         ::std::sort(vecExtensions.begin(), vecExtensions.end(), CompIdentifiers());
1199 
1200         ::std::vector< ::std::vector<Reference<deploy::XPackage> > >::const_iterator
1201               citVecVec = vecExtensions.begin();
1202         sal_Int32 j = 0;
1203         uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > > seqSeq(vecExtensions.size());
1204         for (;citVecVec != vecExtensions.end(); citVecVec++, j++)
1205         {
1206             seqSeq[j] = comphelper::containerToSequence(*citVecVec);
1207         }
1208         return seqSeq;
1209 
1210     } catch (deploy::DeploymentException& ) {
1211         throw;
1212     } catch (ucb::CommandFailedException & ) {
1213         throw;
1214     } catch (ucb::CommandAbortedException & ) {
1215         throw;
1216     } catch (lang::IllegalArgumentException &) {
1217         throw;
1218     } catch (uno::RuntimeException &) {
1219         throw;
1220     } catch (...) {
1221         uno::Any exc = ::cppu::getCaughtException();
1222         throw deploy::DeploymentException(
1223             OUSTR("Extension Manager: exception during enableExtension"),
1224             static_cast<OWeakObject*>(this), exc);
1225    }
1226 }
1227 
1228 //only to be called from unopkg!!!
1229 void ExtensionManager::reinstallDeployedExtensions(
1230     OUString const & repository,
1231     Reference<task::XAbortChannel> const & xAbortChannel,
1232     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1233     throw (deploy::DeploymentException,
1234         ucb::CommandFailedException, ucb::CommandAbortedException,
1235         lang::IllegalArgumentException, uno::RuntimeException)
1236 {
1237     try
1238     {
1239         Reference<deploy::XPackageManager>
1240             xPackageManager = getPackageManager(repository);
1241 
1242         ::osl::MutexGuard guard(getMutex());
1243         xPackageManager->reinstallDeployedPackages(xAbortChannel, xCmdEnv);
1244         //We must sync here, otherwise we will get exceptions when extensions
1245         //are removed.
1246         dp_misc::syncRepositories(xCmdEnv);
1247         const uno::Sequence< Reference<deploy::XPackage> > extensions(
1248             xPackageManager->getDeployedPackages(xAbortChannel, xCmdEnv));
1249 
1250         for ( sal_Int32 pos = 0; pos < extensions.getLength(); ++pos )
1251         {
1252             try
1253             {
1254                 const OUString id =  dp_misc::getIdentifier(extensions[ pos ]);
1255                 const OUString fileName = extensions[ pos ]->getName();
1256                 OSL_ASSERT(id.getLength());
1257                 activateExtension(id, fileName, false, true, xAbortChannel, xCmdEnv );
1258             }
1259             catch (lang::DisposedException &)
1260             {
1261             }
1262         }
1263     } catch (deploy::DeploymentException& ) {
1264         throw;
1265     } catch (ucb::CommandFailedException & ) {
1266         throw;
1267     } catch (ucb::CommandAbortedException & ) {
1268         throw;
1269     } catch (lang::IllegalArgumentException &) {
1270         throw;
1271     } catch (uno::RuntimeException &) {
1272         throw;
1273     } catch (...) {
1274         uno::Any exc = ::cppu::getCaughtException();
1275         throw deploy::DeploymentException(
1276             OUSTR("Extension Manager: exception during enableExtension"),
1277             static_cast<OWeakObject*>(this), exc);
1278     }
1279 }
1280 
1281 /** Works on the bundled repository. That is using the variables
1282     BUNDLED_EXTENSIONS and BUNDLED_EXTENSIONS_USER.
1283  */
1284 void ExtensionManager::synchronizeBundledPrereg(
1285     Reference<task::XAbortChannel> const & xAbortChannel,
1286     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1287     throw (deploy::DeploymentException,
1288            uno::RuntimeException)
1289 {
1290     try
1291     {
1292         String sSynchronizingBundled(StrSyncRepository::get());
1293         sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled"));
1294         dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled);
1295 
1296         Reference<deploy::XPackageManagerFactory> xPackageManagerFactory(
1297             deploy::thePackageManagerFactory::get(m_xContext));
1298 
1299         Reference<deploy::XPackageManager> xMgr =
1300             xPackageManagerFactory->getPackageManager(OUSTR("bundled_prereg"));
1301         xMgr->synchronize(xAbortChannel, xCmdEnv);
1302         progressBundled.update(OUSTR("\n\n"));
1303 
1304         uno::Sequence<Reference<deploy::XPackage> > extensions = xMgr->getDeployedPackages(
1305             xAbortChannel, xCmdEnv);
1306         try
1307         {
1308             for (sal_Int32 i = 0; i < extensions.getLength(); i++)
1309             {
1310                 extensions[i]->registerPackage(true, xAbortChannel, xCmdEnv);
1311             }
1312         }
1313         catch (...)
1314         {
1315             OSL_ASSERT(0);
1316         }
1317         OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM(
1318                                      "$BUNDLED_EXTENSIONS_PREREG/lastsynchronized"));
1319         writeLastModified(lastSyncBundled, xCmdEnv);
1320 
1321     } catch (deploy::DeploymentException& ) {
1322         throw;
1323     } catch (ucb::CommandFailedException & ) {
1324         throw;
1325     } catch (ucb::CommandAbortedException & ) {
1326         throw;
1327     } catch (lang::IllegalArgumentException &) {
1328         throw;
1329     } catch (uno::RuntimeException &) {
1330         throw;
1331     } catch (...) {
1332         uno::Any exc = ::cppu::getCaughtException();
1333         throw deploy::DeploymentException(
1334             OUSTR("Extension Manager: exception in synchronize"),
1335             static_cast<OWeakObject*>(this), exc);
1336     }
1337 }
1338 
1339 sal_Bool ExtensionManager::synchronize(
1340     Reference<task::XAbortChannel> const & xAbortChannel,
1341     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1342     throw (deploy::DeploymentException,
1343            ucb::CommandFailedException,
1344            ucb::CommandAbortedException,
1345            lang::IllegalArgumentException,
1346            uno::RuntimeException)
1347 {
1348     try
1349     {
1350         sal_Bool bModified = sal_False;
1351 
1352         ::osl::MutexGuard guard(getMutex());
1353         String sSynchronizingShared(StrSyncRepository::get());
1354         sSynchronizingShared.SearchAndReplaceAllAscii( "%NAME", OUSTR("shared"));
1355         dp_misc::ProgressLevel progressShared(xCmdEnv, sSynchronizingShared);
1356         bModified = getSharedRepository()->synchronize(xAbortChannel, xCmdEnv);
1357         progressShared.update(OUSTR("\n\n"));
1358 
1359         String sSynchronizingBundled(StrSyncRepository::get());
1360         sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled"));
1361         dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled);
1362         bModified |= getBundledRepository()->synchronize(xAbortChannel, xCmdEnv);
1363         progressBundled.update(OUSTR("\n\n"));
1364 
1365         //Always determine the active extension. This is necessary for the
1366         //first-start optimization. The setup creates the registration data for the
1367         //bundled extensions (brand_layer/share/prereg/bundled), which is copied to the user
1368         //installation (user_installation/extension/bundled) when a user starts OOo
1369         //for the first time after running setup. All bundled extensions are registered
1370         //at that moment. However, extensions with the same identifier can be in the
1371         //shared or user repository, in which case the respective bundled extensions must
1372         //be revoked.
1373         try
1374         {
1375             const uno::Sequence<uno::Sequence<Reference<deploy::XPackage> > >
1376                 seqSeqExt = getAllExtensions(xAbortChannel, xCmdEnv);
1377             for (sal_Int32 i = 0; i < seqSeqExt.getLength(); i++)
1378             {
1379                 uno::Sequence<Reference<deploy::XPackage> > const & seqExt =
1380                     seqSeqExt[i];
1381                 activateExtension(seqExt, isUserDisabled(seqExt), true,
1382                                   xAbortChannel, xCmdEnv);
1383             }
1384         }
1385         catch (...)
1386         {
1387             //We catch the exception, so we can write the lastmodified file
1388             //so we will no repeat this everytime OOo starts.
1389             OSL_ENSURE(0, "Extensions Manager: synchronize");
1390         }
1391         OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM(
1392                                      "$BUNDLED_EXTENSIONS_USER/lastsynchronized"));
1393         writeLastModified(lastSyncBundled, xCmdEnv);
1394         OUString lastSyncShared(RTL_CONSTASCII_USTRINGPARAM(
1395                                     "$SHARED_EXTENSIONS_USER/lastsynchronized"));
1396         writeLastModified(lastSyncShared, xCmdEnv);
1397         return bModified;
1398     } catch (deploy::DeploymentException& ) {
1399         throw;
1400     } catch (ucb::CommandFailedException & ) {
1401         throw;
1402     } catch (ucb::CommandAbortedException & ) {
1403         throw;
1404     } catch (lang::IllegalArgumentException &) {
1405         throw;
1406     } catch (uno::RuntimeException &) {
1407         throw;
1408     } catch (...) {
1409         uno::Any exc = ::cppu::getCaughtException();
1410         throw deploy::DeploymentException(
1411             OUSTR("Extension Manager: exception in synchronize"),
1412             static_cast<OWeakObject*>(this), exc);
1413     }
1414 }
1415 
1416 // Notify the user when a new extension is to be installed. This is only the
1417 // case when one uses the system integration to install an extension (double
1418 // clicking on .oxt file etc.)). The function must only be called if there is no
1419 // extension with the same identifier already deployed. Then the checkUpdate
1420 // function will inform the user that the extension is about to be installed In
1421 // case the user cancels the installation a CommandFailed exception is
1422 // thrown.
1423 void ExtensionManager::checkInstall(
1424 	OUString const & displayName,
1425     Reference<ucb::XCommandEnvironment> const & cmdEnv)
1426 {
1427         uno::Any request(
1428 			deploy::InstallException(
1429 				OUSTR("Extension ") + displayName +
1430                 OUSTR(" is about to be installed."),
1431 				static_cast<OWeakObject *>(this), displayName));
1432 	    bool approve = false, abort = false;
1433         if (! dp_misc::interactContinuation(
1434                 request, task::XInteractionApprove::static_type(),
1435                 cmdEnv, &approve, &abort ))
1436 		{
1437             OSL_ASSERT( !approve && !abort );
1438             throw deploy::DeploymentException(
1439                 dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName,
1440                 static_cast<OWeakObject *>(this), request );
1441         }
1442         if (abort || !approve)
1443             throw ucb::CommandFailedException(
1444                 dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName,
1445                 static_cast<OWeakObject *>(this), request );
1446 }
1447 
1448 /* The function will make the user interaction in case there is an extension
1449 installed with the same id. This function may only be called if there is already
1450 an extension.
1451 */
1452 void ExtensionManager::checkUpdate(
1453     OUString const & newVersion,
1454     OUString const & newDisplayName,
1455     Reference<deploy::XPackage> const & oldExtension,
1456     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1457 {
1458     // package already deployed, interact --force:
1459     uno::Any request(
1460         (deploy::VersionException(
1461             dp_misc::getResourceString(
1462                 RID_STR_PACKAGE_ALREADY_ADDED ) + newDisplayName,
1463             static_cast<OWeakObject *>(this), newVersion, newDisplayName,
1464             oldExtension ) ) );
1465     bool replace = false, abort = false;
1466     if (! dp_misc::interactContinuation(
1467             request, task::XInteractionApprove::static_type(),
1468             xCmdEnv, &replace, &abort )) {
1469         OSL_ASSERT( !replace && !abort );
1470         throw deploy::DeploymentException(
1471             dp_misc::getResourceString(
1472                 RID_STR_ERROR_WHILE_ADDING) + newDisplayName,
1473             static_cast<OWeakObject *>(this), request );
1474     }
1475     if (abort || !replace)
1476         throw ucb::CommandFailedException(
1477             dp_misc::getResourceString(
1478                 RID_STR_PACKAGE_ALREADY_ADDED) + newDisplayName,
1479             static_cast<OWeakObject *>(this), request );
1480 }
1481 
1482 Reference<deploy::XPackage> ExtensionManager::getTempExtension(
1483     OUString const & url,
1484     Reference<task::XAbortChannel> const & xAbortChannel,
1485     Reference<ucb::XCommandEnvironment> const & /*xCmdEnv*/)
1486 
1487 {
1488     Reference<ucb::XCommandEnvironment> tmpCmdEnvA(new TmpRepositoryCommandEnv());
1489     Reference<deploy::XPackage> xTmpPackage = getTmpRepository()->addPackage(
1490         url, uno::Sequence<beans::NamedValue>(),OUString(), xAbortChannel, tmpCmdEnvA);
1491     if (!xTmpPackage.is())
1492     {
1493         throw deploy::DeploymentException(
1494             OUSTR("Extension Manager: Failed to create temporary XPackage for url: ") + url,
1495             static_cast<OWeakObject*>(this), uno::Any());
1496 
1497     }
1498     return xTmpPackage;
1499 }
1500 
1501 uno::Sequence<Reference<deploy::XPackage> > SAL_CALL
1502 ExtensionManager::getExtensionsWithUnacceptedLicenses(
1503         OUString const & repository,
1504         Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1505         throw (deploy::DeploymentException,
1506                uno::RuntimeException)
1507 {
1508     Reference<deploy::XPackageManager>
1509         xPackageManager = getPackageManager(repository);
1510     ::osl::MutexGuard guard(getMutex());
1511     return xPackageManager->getExtensionsWithUnacceptedLicenses(xCmdEnv);
1512 }
1513 
1514 sal_Bool ExtensionManager::isReadOnlyRepository(::rtl::OUString const & repository)
1515         throw (uno::RuntimeException)
1516 {
1517     return getPackageManager(repository)->isReadOnly();
1518 }
1519 //------------------------------------------------------------------------------
1520 //------------------------------------------------------------------------------
1521 //------------------------------------------------------------------------------
1522 
1523 namespace sdecl = comphelper::service_decl;
1524 sdecl::class_<ExtensionManager> servicePIP;
1525 extern sdecl::ServiceDecl const serviceDecl(
1526     servicePIP,
1527     // a private one:
1528     "com.sun.star.comp.deployment.ExtensionManager",
1529     "com.sun.star.comp.deployment.ExtensionManager");
1530 
1531 //------------------------------------------------------------------------------
1532 bool singleton_entries(
1533     uno::Reference< registry::XRegistryKey > const & xRegistryKey )
1534 {
1535     try {
1536         uno::Reference< registry::XRegistryKey > xKey(
1537             xRegistryKey->createKey(
1538                 serviceDecl.getImplementationName() +
1539                 // xxx todo: use future generated function to get singleton name
1540                 OUSTR("/UNO/SINGLETONS/"
1541                       "com.sun.star.deployment.ExtensionManager") ) );
1542         xKey->setStringValue( serviceDecl.getSupportedServiceNames()[0] );
1543         return true;
1544     }
1545     catch (registry::InvalidRegistryException & exc) {
1546         (void) exc; // avoid warnings
1547         OSL_ENSURE( 0, ::rtl::OUStringToOString(
1548                         exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1549         return false;
1550     }
1551 }
1552 
1553 // XModifyBroadcaster
1554 //______________________________________________________________________________
1555 void ExtensionManager::addModifyListener(
1556     Reference<util::XModifyListener> const & xListener )
1557     throw (uno::RuntimeException)
1558 {
1559      check();
1560      rBHelper.addListener( ::getCppuType( &xListener ), xListener );
1561 }
1562 
1563 //______________________________________________________________________________
1564 void ExtensionManager::removeModifyListener(
1565     Reference<util::XModifyListener> const & xListener )
1566     throw (uno::RuntimeException)
1567 {
1568     check();
1569     rBHelper.removeListener( ::getCppuType( &xListener ), xListener );
1570 }
1571 
1572 void ExtensionManager::check()
1573 {
1574     ::osl::MutexGuard guard( getMutex() );
1575     if (rBHelper.bInDispose || rBHelper.bDisposed) {
1576         throw lang::DisposedException(
1577             OUSTR("ExtensionManager instance has already been disposed!"),
1578             static_cast<OWeakObject *>(this) );
1579     }
1580 }
1581 
1582 void ExtensionManager::fireModified()
1583 {
1584     ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer(
1585         util::XModifyListener::static_type() );
1586     if (pContainer != 0) {
1587         pContainer->forEach<util::XModifyListener>(
1588             boost::bind(&util::XModifyListener::modified, _1,
1589                         lang::EventObject(static_cast<OWeakObject *>(this))) );
1590     }
1591 }
1592 
1593 } // namespace dp_manager
1594 
1595 
1596