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