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