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