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