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