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