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 "dp_package.hrc"
28 #include "dp_backend.h"
29 #include "dp_ucb.h"
30 #include "dp_interact.h"
31 #include "dp_dependencies.hxx"
32 #include "dp_platform.hxx"
33 #include "dp_descriptioninfoset.hxx"
34 #include "dp_identifier.hxx"
35 #include "rtl/uri.hxx"
36 #include "cppuhelper/exc_hlp.hxx"
37 #include "cppuhelper/implbase1.hxx"
38 #include "ucbhelper/content.hxx"
39 #include "svl/inettype.hxx"
40 #include "comphelper/anytostring.hxx"
41 #include "comphelper/makesequence.hxx"
42 #include "comphelper/sequence.hxx"
43 #include "com/sun/star/lang/WrappedTargetException.hpp"
44 #include "com/sun/star/lang/XServiceInfo.hpp"
45 #include "com/sun/star/beans/UnknownPropertyException.hpp"
46 #include "com/sun/star/graphic/XGraphic.hpp"
47 #include "com/sun/star/graphic/XGraphicProvider.hpp"
48 #include "com/sun/star/io/XOutputStream.hpp"
49 #include "com/sun/star/io/XInputStream.hpp"
50 #include "com/sun/star/task/InteractionClassification.hpp"
51 #include "com/sun/star/task/XInteractionApprove.hpp"
52 #include "com/sun/star/ucb/XInteractionReplaceExistingData.hpp"
53 #include "com/sun/star/ucb/NameClashResolveRequest.hpp"
54 #include "com/sun/star/ucb/XContentAccess.hpp"
55 #include "com/sun/star/ucb/NameClash.hpp"
56 #include "com/sun/star/ucb/UnsupportedCommandException.hpp"
57 #include "com/sun/star/sdbc/XResultSet.hpp"
58 #include "com/sun/star/sdbc/XRow.hpp"
59 #include "com/sun/star/packages/manifest/XManifestReader.hpp"
60 #include "com/sun/star/packages/manifest/XManifestWriter.hpp"
61 #include "com/sun/star/deployment/DependencyException.hpp"
62 #include "com/sun/star/deployment/LicenseException.hpp"
63 #include "com/sun/star/deployment/PlatformException.hpp"
64 #include "com/sun/star/deployment/Prerequisites.hpp"
65 #include "com/sun/star/xml/dom/XDocumentBuilder.hpp"
66 #include "com/sun/star/xml/xpath/XXPathAPI.hpp"
67 #include "com/sun/star/deployment/XPackageManager.hpp"
68 #include "boost/optional.hpp"
69 #include <vector>
70 #include <stdio.h>
71
72 #include "dp_extbackenddb.hxx"
73 using namespace ::dp_misc;
74 using namespace ::com::sun::star;
75 using namespace ::com::sun::star::uno;
76
77 namespace css = ::com::sun::star;
78
79 using ::rtl::OUString;
80
81 namespace dp_registry {
82 namespace backend {
83 namespace bundle {
84 namespace {
85
86 typedef cppu::ImplInheritanceHelper1<PackageRegistryBackend,
87 lang::XServiceInfo> ImplBaseT;
88
89 //==============================================================================
90 class BackendImpl : public ImplBaseT
91 {
92 class PackageImpl : public ::dp_registry::backend::Package
93 {
94 BackendImpl * getMyBackend() const;
95 /** constains the old tooltip description for the Extension Manager GUI in OOo v.2.x
96 We keep it for backward compatibility.
97 */
98 OUString m_oldDescription;
99 OUString m_url_expanded;
100 const bool m_legacyBundle;
101 Sequence< Reference<deployment::XPackage> > m_bundle;
102 Sequence< Reference<deployment::XPackage> > * m_pBundle;
103
104 ExtensionBackendDb::Data m_dbData;
105
106 Reference<deployment::XPackage> bindBundleItem(
107 OUString const & url, OUString const & mediaType,
108 sal_Bool bRemoved, //that is, useing data base information
109 OUString const & identifier,
110 Reference<ucb::XCommandEnvironment> const & xCmdEnv,
111 bool notifyDetectionError = true );
112
113 typedef ::std::vector< Reference<deployment::XPackage> > t_packagevec;
114 void scanBundle(
115 t_packagevec & bundle,
116 ::rtl::Reference<AbortChannel> const & abortChannel,
117 Reference<ucb::XCommandEnvironment> const & xCmdEnv );
118 void scanLegacyBundle(
119 t_packagevec & bundle,
120 OUString const & url,
121 ::rtl::Reference<AbortChannel> const & abortChannel,
122 Reference<ucb::XCommandEnvironment> const & xCmdEnv,
123 bool skip_registration = false );
124 ::std::vector<Reference<deployment::XPackage> > getPackagesFromDb(
125 Reference<ucb::XCommandEnvironment> const & xCmdEnv);
126 bool checkPlatform(
127 Reference<ucb::XCommandEnvironment > const & environment);
128
129 bool checkDependencies(
130 Reference<ucb::XCommandEnvironment > const &
131 environment,
132 DescriptionInfoset const & description);
133 // throws css::uno::RuntimeException,
134 // css::deployment::DeploymentException
135
136 ::sal_Bool checkLicense(
137 Reference< ucb::XCommandEnvironment > const & xCmdEnv,
138 DescriptionInfoset const & description, bool bNoLicenseChecking)
139 throw (deployment::DeploymentException,
140 ucb::CommandFailedException,
141 ucb::CommandAbortedException,
142 RuntimeException);
143 // @throws DeploymentException
144 OUString getTextFromURL(
145 const Reference< ucb::XCommandEnvironment >& xCmdEnv,
146 const OUString& licenseUrl);
147
148 DescriptionInfoset getDescriptionInfoset();
149
150 // Package
151 virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
152 ::osl::ResettableMutexGuard & guard,
153 ::rtl::Reference<AbortChannel> const & abortChannel,
154 Reference<ucb::XCommandEnvironment> const & xCmdEnv );
155 virtual void processPackage_(
156 ::osl::ResettableMutexGuard & guard,
157 bool registerPackage,
158 bool startup,
159 ::rtl::Reference<AbortChannel> const & abortChannel,
160 Reference<ucb::XCommandEnvironment> const & xCmdEnv );
161
162 virtual void SAL_CALL disposing();
163
164
165
166 public:
167 PackageImpl(
168 ::rtl::Reference<PackageRegistryBackend> const & myBackend,
169 OUString const & url,
170 OUString const & name,
171 Reference<deployment::XPackageTypeInfo> const & xPackageType,
172 bool legacyBundle,
173 bool bRemoved,
174 OUString const & identifier);
175
176 // XPackage
177 virtual sal_Bool SAL_CALL isBundle() throw (RuntimeException);
178
179 virtual Sequence< Reference<deployment::XPackage> > SAL_CALL getBundle(
180 Reference<task::XAbortChannel> const & xAbortChannel,
181 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
182 throw (deployment::DeploymentException,
183 ucb::CommandFailedException,
184 ucb::CommandAbortedException,
185 lang::IllegalArgumentException, RuntimeException);
186 virtual OUString SAL_CALL getDescription()
187 throw (deployment::ExtensionRemovedException, RuntimeException);
188
189 virtual OUString SAL_CALL getLicenseText()
190 throw (deployment::ExtensionRemovedException, RuntimeException);
191
192 virtual void SAL_CALL exportTo(
193 OUString const & destFolderURL, OUString const & newTitle,
194 sal_Int32 nameClashAction,
195 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
196 throw (deployment::ExtensionRemovedException,
197 ucb::CommandFailedException,
198 ucb::CommandAbortedException,
199 RuntimeException);
200
201 virtual ::sal_Int32 SAL_CALL checkPrerequisites(
202 const Reference< task::XAbortChannel >& xAbortChannel,
203 const Reference< ucb::XCommandEnvironment >& xCmdEnv,
204 ::sal_Bool noLicenseChecking)
205 throw (deployment::ExtensionRemovedException,
206 deployment::DeploymentException,
207 ucb::CommandFailedException,
208 ucb::CommandAbortedException,
209 RuntimeException);
210
211 virtual ::sal_Bool SAL_CALL checkDependencies(
212 const Reference< ucb::XCommandEnvironment >& xCmdEnv )
213 throw (deployment::DeploymentException,
214 deployment::ExtensionRemovedException,
215 ucb::CommandFailedException,
216 RuntimeException);
217
218 virtual beans::Optional<OUString> SAL_CALL getIdentifier()
219 throw (RuntimeException);
220
221 virtual OUString SAL_CALL getVersion()
222 throw (deployment::ExtensionRemovedException, RuntimeException);
223
224 virtual Sequence<OUString> SAL_CALL getUpdateInformationURLs()
225 throw (deployment::ExtensionRemovedException, RuntimeException);
226
227 virtual beans::StringPair SAL_CALL getPublisherInfo()
228 throw (deployment::ExtensionRemovedException, RuntimeException);
229
230 virtual OUString SAL_CALL getDisplayName()
231 throw (deployment::ExtensionRemovedException, RuntimeException);
232
233 virtual Reference< graphic::XGraphic > SAL_CALL
234 getIcon( ::sal_Bool bHighContrast )
235 throw (deployment::ExtensionRemovedException,
236 RuntimeException);
237 };
238 friend class PackageImpl;
239
240 Reference<deployment::XPackageRegistry> m_xRootRegistry;
241 const Reference<deployment::XPackageTypeInfo> m_xBundleTypeInfo;
242 const Reference<deployment::XPackageTypeInfo> m_xLegacyBundleTypeInfo;
243 Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
244
245 std::auto_ptr<ExtensionBackendDb> m_backendDb;
246
247 void addDataToDb(OUString const & url, ExtensionBackendDb::Data const & data);
248 ExtensionBackendDb::Data readDataFromDb(OUString const & url);
249 void revokeEntryFromDb(OUString const & url);
250
251 // PackageRegistryBackend
252 virtual Reference<deployment::XPackage> bindPackage_(
253 OUString const & url, OUString const & mediaType,
254 sal_Bool bRemoved, OUString const & identifier,
255 Reference<ucb::XCommandEnvironment> const & xCmdEnv );
256
257 virtual void SAL_CALL disposing();
258
259 public:
260 BackendImpl(
261 Sequence<Any> const & args,
262 Reference<XComponentContext> const & xComponentContext,
263 Reference<deployment::XPackageRegistry> const & xRootRegistry );
264
265 // XServiceInfo
266 virtual OUString SAL_CALL getImplementationName() throw (RuntimeException);
267 virtual sal_Bool SAL_CALL supportsService( OUString const& name )
268 throw (RuntimeException);
269 virtual Sequence<OUString> SAL_CALL getSupportedServiceNames()
270 throw (RuntimeException);
271
272 // XPackageRegistry
273 virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
274 getSupportedPackageTypes() throw (RuntimeException);
275 virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
276 throw (deployment::DeploymentException,
277 uno::RuntimeException);
278
279 using ImplBaseT::disposing;
280 };
281
282 //Used to find a XPackage with a particular URL
283 class XPackage_eq : public std::unary_function<Reference<deployment::XPackage>, bool>
284 {
285 OUString m_URL;
286 public:
XPackage_eq(const OUString & s)287 explicit XPackage_eq(const OUString & s) : m_URL(s) {}
operator ()(const Reference<deployment::XPackage> & p) const288 bool operator() (const Reference<deployment::XPackage> & p) const
289 {
290 return m_URL.equals(p->getURL());
291 }
292 };
293
294 //______________________________________________________________________________
BackendImpl(Sequence<Any> const & args,Reference<XComponentContext> const & xComponentContext,Reference<deployment::XPackageRegistry> const & xRootRegistry)295 BackendImpl::BackendImpl(
296 Sequence<Any> const & args,
297 Reference<XComponentContext> const & xComponentContext,
298 Reference<deployment::XPackageRegistry> const & xRootRegistry )
299 : ImplBaseT( args, xComponentContext ),
300 m_xRootRegistry( xRootRegistry ),
301 m_xBundleTypeInfo( new Package::TypeInfo(
302 OUSTR("application/vnd.sun.star.package-bundle"),
303 OUSTR("*.oxt;*.uno.pkg"),
304 getResourceString(RID_STR_PACKAGE_BUNDLE),
305 RID_IMG_DEF_PACKAGE_BUNDLE,
306 RID_IMG_DEF_PACKAGE_BUNDLE_HC ) ),
307 m_xLegacyBundleTypeInfo( new Package::TypeInfo(
308 OUSTR("application/"
309 "vnd.sun.star.legacy-package-bundle"),
310 OUSTR("*.zip"),
311 m_xBundleTypeInfo->getShortDescription(),
312 RID_IMG_DEF_PACKAGE_BUNDLE,
313 RID_IMG_DEF_PACKAGE_BUNDLE_HC ) ),
314 m_typeInfos(2)
315 {
316 m_typeInfos[ 0 ] = m_xBundleTypeInfo;
317 m_typeInfos[ 1 ] = m_xLegacyBundleTypeInfo;
318
319 if (!transientMode())
320 {
321 OUString dbFile = makeURL(getCachePath(), getImplementationName());
322 dbFile = makeURL(dbFile, OUSTR("backenddb.xml"));
323 m_backendDb.reset(
324 new ExtensionBackendDb(getComponentContext(), dbFile));
325 }
326 }
327
328 //______________________________________________________________________________
disposing()329 void BackendImpl::disposing()
330 {
331 m_xRootRegistry.clear();
332 PackageRegistryBackend::disposing();
333 }
334
335 // XServiceInfo
getImplementationName()336 OUString BackendImpl::getImplementationName() throw (RuntimeException)
337 {
338 return OUSTR("com.sun.star.comp.deployment.bundle.PackageRegistryBackend");
339 }
340
supportsService(OUString const & name)341 sal_Bool BackendImpl::supportsService( OUString const& name )
342 throw (RuntimeException)
343 {
344 return getSupportedServiceNames()[0].equals(name);
345 }
346
getSupportedServiceNames()347 Sequence<OUString> BackendImpl::getSupportedServiceNames()
348 throw (RuntimeException)
349 {
350 return comphelper::makeSequence(
351 OUString::createFromAscii(BACKEND_SERVICE_NAME) );
352 }
353
354 // XPackageRegistry
355 //______________________________________________________________________________
356 Sequence< Reference<deployment::XPackageTypeInfo> >
getSupportedPackageTypes()357 BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
358 {
359 return m_typeInfos;
360 }
361
packageRemoved(OUString const & url,OUString const &)362 void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
363 throw (deployment::DeploymentException,
364 uno::RuntimeException)
365 {
366 //Notify the backend responsible for processing the different media
367 //types that this extension was removed.
368 ExtensionBackendDb::Data data = readDataFromDb(url);
369 for (ExtensionBackendDb::Data::ITC_ITEMS i = data.items.begin(); i != data.items.end(); i++)
370 {
371 m_xRootRegistry->packageRemoved(i->first, i->second);
372 }
373
374 if (m_backendDb.get())
375 m_backendDb->removeEntry(url);
376 }
377
378
379 // PackageRegistryBackend
380 //______________________________________________________________________________
bindPackage_(OUString const & url,OUString const & mediaType_,sal_Bool bRemoved,OUString const & identifier,Reference<ucb::XCommandEnvironment> const & xCmdEnv)381 Reference<deployment::XPackage> BackendImpl::bindPackage_(
382 OUString const & url, OUString const & mediaType_,
383 sal_Bool bRemoved, OUString const & identifier,
384 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
385 {
386 OUString mediaType( mediaType_ );
387 if (mediaType.getLength() == 0)
388 {
389 // detect media-type:
390 ::ucbhelper::Content ucbContent;
391 if (create_ucb_content( &ucbContent, url, xCmdEnv ))
392 {
393 if (ucbContent.isFolder())
394 {
395 //Every .oxt, uno.pkg file must contain a META-INF folder
396 ::ucbhelper::Content metaInfContent;
397 if (create_ucb_content(
398 &metaInfContent, makeURL( url, OUSTR("META-INF") ),
399 xCmdEnv, false /* no throw */ ))
400 {
401 mediaType = OUSTR("application/vnd.sun.star.package-bundle");
402 }
403 //No support of legacy bundles, because every folder could be one.
404 }
405 else
406 {
407 const OUString title( ucbContent.getPropertyValue(
408 StrTitle::get() ).get<OUString>() );
409 if (title.endsWithIgnoreAsciiCaseAsciiL(
410 RTL_CONSTASCII_STRINGPARAM(".oxt") ) ||
411 title.endsWithIgnoreAsciiCaseAsciiL(
412 RTL_CONSTASCII_STRINGPARAM(".uno.pkg") ))
413 mediaType = OUSTR("application/vnd.sun.star.package-bundle");
414 else if (title.endsWithIgnoreAsciiCaseAsciiL(
415 RTL_CONSTASCII_STRINGPARAM(".zip") ))
416 mediaType =
417 OUSTR("application/vnd.sun.star.legacy-package-bundle");
418 }
419 }
420 if (mediaType.getLength() == 0)
421 throw lang::IllegalArgumentException(
422 StrCannotDetectMediaType::get() + url,
423 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
424 }
425
426 String type, subType;
427 INetContentTypeParameterList params;
428 if (INetContentTypes::parse( mediaType, type, subType, ¶ms ))
429 {
430 if (type.EqualsIgnoreCaseAscii("application"))
431 {
432
433 //In case a XPackage is created for a removed extension, we cannot
434 //obtain the name
435 OUString name;
436 if (!bRemoved)
437 {
438 ::ucbhelper::Content ucbContent( url, xCmdEnv );
439 name = ucbContent.getPropertyValue(
440 StrTitle::get() ).get<OUString>();
441 }
442 if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.package-bundle")) {
443 return new PackageImpl(
444 this, url, name, m_xBundleTypeInfo, false, bRemoved,
445 identifier);
446 }
447 else if (subType.EqualsIgnoreCaseAscii(
448 "vnd.sun.star.legacy-package-bundle")) {
449 return new PackageImpl(
450 this, url, name, m_xLegacyBundleTypeInfo, true, bRemoved,
451 identifier);
452 }
453 }
454 }
455 throw lang::IllegalArgumentException(
456 StrUnsupportedMediaType::get() + mediaType,
457 static_cast<OWeakObject *>(this),
458 static_cast<sal_Int16>(-1) );
459 }
460
addDataToDb(OUString const & url,ExtensionBackendDb::Data const & data)461 void BackendImpl::addDataToDb(
462 OUString const & url, ExtensionBackendDb::Data const & data)
463 {
464 if (m_backendDb.get())
465 m_backendDb->addEntry(url, data);
466 }
467
readDataFromDb(OUString const & url)468 ExtensionBackendDb::Data BackendImpl::readDataFromDb(
469 OUString const & url)
470 {
471 ExtensionBackendDb::Data data;
472 if (m_backendDb.get())
473 data = m_backendDb->getEntry(url);
474 return data;
475 }
476
revokeEntryFromDb(OUString const & url)477 void BackendImpl::revokeEntryFromDb(OUString const & url)
478 {
479 if (m_backendDb.get())
480 m_backendDb->revokeEntry(url);
481 }
482
483
484 //##############################################################################
485
PackageImpl(::rtl::Reference<PackageRegistryBackend> const & myBackend,OUString const & url,OUString const & name,Reference<deployment::XPackageTypeInfo> const & xPackageType,bool legacyBundle,bool bRemoved,OUString const & identifier)486 BackendImpl::PackageImpl::PackageImpl(
487 ::rtl::Reference<PackageRegistryBackend> const & myBackend,
488 OUString const & url,
489 OUString const & name,
490 Reference<deployment::XPackageTypeInfo> const & xPackageType,
491 bool legacyBundle, bool bRemoved, OUString const & identifier)
492 : Package( myBackend, url, name, name /* display-name */,
493 xPackageType, bRemoved, identifier),
494 m_url_expanded( expandUnoRcUrl( url ) ),
495 m_legacyBundle( legacyBundle ),
496 m_pBundle( 0 )
497 {
498 if (bRemoved)
499 m_dbData = getMyBackend()->readDataFromDb(url);
500 }
501
getMyBackend() const502 BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
503 {
504 BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
505 if (NULL == pBackend)
506 {
507 //May throw a DisposedException
508 check();
509 //We should never get here...
510 throw RuntimeException(
511 OUSTR("Failed to get the BackendImpl"),
512 static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
513 }
514 return pBackend;
515 }
516 //______________________________________________________________________________
disposing()517 void BackendImpl::PackageImpl::disposing()
518 {
519 sal_Int32 len = m_bundle.getLength();
520 Reference<deployment::XPackage> const * p = m_bundle.getConstArray();
521 for ( sal_Int32 pos = 0; pos < len; ++pos )
522 try_dispose( p[ pos ] );
523 m_bundle.realloc( 0 );
524
525 Package::disposing();
526 }
527
528 // Package
529 //______________________________________________________________________________
530 beans::Optional< beans::Ambiguous<sal_Bool> >
isRegistered_(::osl::ResettableMutexGuard &,::rtl::Reference<AbortChannel> const & abortChannel,Reference<ucb::XCommandEnvironment> const & xCmdEnv)531 BackendImpl::PackageImpl::isRegistered_(
532 ::osl::ResettableMutexGuard &,
533 ::rtl::Reference<AbortChannel> const & abortChannel,
534 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
535 {
536 //In case the object was created for a removed extension (m_bRemoved = true)
537 //but the extension is not registered, then bundle will be empty. Then
538 //the return value will be Optional<...>.IsPresent= false. Althoug this is
539 //not true, this does not matter. Then registerPackage or revokePackage
540 //would never be called for the items. But since the extension is removed
541 //and not registered anyway, this does not matter.
542 const Sequence< Reference<deployment::XPackage> > bundle(
543 getBundle( abortChannel.get(), xCmdEnv ) );
544
545 bool reg = false;
546 bool present = false;
547 bool ambig = false;
548 for ( sal_Int32 pos = bundle.getLength(); pos--; )
549 {
550 Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
551 Reference<task::XAbortChannel> xSubAbortChannel(
552 xPackage->createAbortChannel() );
553 AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
554 beans::Optional< beans::Ambiguous<sal_Bool> > option(
555 xPackage->isRegistered( xSubAbortChannel, xCmdEnv ) );
556
557 //present = true if at least one bundle item has this value.
558 //reg = true if all bundle items have an option value (option.IsPresent == 1)
559 //and all have value of true (option.Value.Value == true)
560 //If not, then the bundle has the status of not registered and ambiguous.
561 if (option.IsPresent)
562 {
563 beans::Ambiguous<sal_Bool> const & status = option.Value;
564 if (present)
565 {
566 //we never come here in the first iteration
567 if (reg != (status.Value != sal_False)) {
568
569 ambig = true;
570 reg = false;
571 break;
572 }
573 }
574 else
575 {
576 //we always come here in the first iteration
577 reg = status.Value;
578 present = true;
579 }
580 }
581 }
582 return beans::Optional< beans::Ambiguous<sal_Bool> >(
583 present, beans::Ambiguous<sal_Bool>(reg, ambig) );
584 }
585
getTextFromURL(const css::uno::Reference<css::ucb::XCommandEnvironment> & xCmdEnv,const OUString & licenseUrl)586 OUString BackendImpl::PackageImpl::getTextFromURL(
587 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv,
588 const OUString& licenseUrl)
589 {
590 try
591 {
592 ::ucbhelper::Content descContent(licenseUrl, xCmdEnv);
593 ::rtl::ByteSequence seq = dp_misc::readFile(descContent);
594 return OUString( reinterpret_cast<sal_Char const *>(
595 seq.getConstArray()), seq.getLength(), RTL_TEXTENCODING_UTF8);
596 }
597 catch (css::uno::Exception&)
598 {
599 Any exc( ::cppu::getCaughtException() );
600 throw css::deployment::DeploymentException(
601 OUSTR("Could not read file ") + licenseUrl, 0, exc);
602 }
603
604 }
605
getDescriptionInfoset()606 DescriptionInfoset BackendImpl::PackageImpl::getDescriptionInfoset()
607 {
608 return dp_misc::getDescriptionInfoset(m_url_expanded);
609 }
610
checkPlatform(css::uno::Reference<css::ucb::XCommandEnvironment> const & environment)611 bool BackendImpl::PackageImpl::checkPlatform(
612 css::uno::Reference< css::ucb::XCommandEnvironment > const & environment)
613 {
614 bool ret = false;
615 DescriptionInfoset info(getDescriptionInfoset());
616 Sequence<OUString> platforms(info.getSupportedPlaforms());
617 if (hasValidPlatform(platforms))
618 {
619 ret = true;
620 }
621 else
622 {
623 ret = false;
624 rtl::OUString msg(
625 RTL_CONSTASCII_USTRINGPARAM("unsupported platform"));
626 Any e(
627 css::deployment::PlatformException(
628 msg, static_cast<OWeakObject *>(this), this));
629 if (!interactContinuation(
630 e, cppu::UnoType< css::task::XInteractionApprove >::get(),
631 environment, NULL, NULL))
632 {
633 throw css::deployment::DeploymentException(
634 msg, static_cast<OWeakObject *>(this), e);
635 }
636 }
637 return ret;
638 }
639
640
checkDependencies(css::uno::Reference<css::ucb::XCommandEnvironment> const & environment,DescriptionInfoset const & description)641 bool BackendImpl::PackageImpl::checkDependencies(
642 css::uno::Reference< css::ucb::XCommandEnvironment > const & environment,
643 DescriptionInfoset const & description)
644 {
645 css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > >
646 unsatisfied(dp_misc::Dependencies::check(description));
647
648 if (unsatisfied.getLength() == 0) {
649 return true;
650 } else {
651 rtl::OUString msg(
652 RTL_CONSTASCII_USTRINGPARAM("unsatisfied dependencies"));
653 Any e(
654 css::deployment::DependencyException(
655 msg, static_cast<OWeakObject *>(this), unsatisfied));
656 if (!interactContinuation(
657 e, cppu::UnoType< css::task::XInteractionApprove >::get(),
658 environment, NULL, NULL))
659 {
660 throw css::deployment::DeploymentException(
661 msg, static_cast<OWeakObject *>(this), e);
662 }
663 return false;
664 }
665 }
666
checkLicense(css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv,DescriptionInfoset const & info,bool alreadyInstalled)667 ::sal_Bool BackendImpl::PackageImpl::checkLicense(
668 css::uno::Reference< css::ucb::XCommandEnvironment > const & xCmdEnv,
669 DescriptionInfoset const & info, bool alreadyInstalled)
670 throw (css::deployment::DeploymentException,
671 css::ucb::CommandFailedException,
672 css::ucb::CommandAbortedException,
673 css::uno::RuntimeException)
674 {
675 try
676 {
677 ::boost::optional<SimpleLicenseAttributes> simplLicAttr
678 = info.getSimpleLicenseAttributes();
679 if (! simplLicAttr)
680 return true;
681 OUString sLic = info.getLocalizedLicenseURL();
682 //If we do not get a localized licence then there is an error in the description.xml
683 //This should be handled by using a validating parser. Therefore we assume that no
684 //license is available.
685 if (sLic.getLength() == 0)
686 throw css::deployment::DeploymentException(
687 OUSTR("Could not obtain path to license. Possible error in description.xml"), 0, Any());
688 OUString sHref = m_url_expanded + OUSTR("/") + sLic;
689 OUString sLicense = getTextFromURL(xCmdEnv, sHref);
690 ////determine who has to agree to the license
691 //check correct value for attribute
692 if ( ! (simplLicAttr->acceptBy.equals(OUSTR("user")) || simplLicAttr->acceptBy.equals(OUSTR("admin"))))
693 throw css::deployment::DeploymentException(
694 OUSTR("Could not obtain attribute simple-lincense@accept-by or it has no valid value"), 0, Any());
695
696
697 //Only use interaction if there is no version of this extension already installed
698 //and the suppress-on-update flag is not set for the new extension
699 // alreadyInstalled | bSuppressOnUpdate | show license
700 //----------------------------------------
701 // 0 | 0 | 1
702 // 0 | 1 | 1
703 // 1 | 0 | 1
704 // 1 | 1 | 0
705
706 if ( !(alreadyInstalled && simplLicAttr->suppressOnUpdate))
707 {
708 css::deployment::LicenseException licExc(
709 OUString(), 0, getDisplayName(), sLicense,
710 simplLicAttr->acceptBy);
711 bool approve = false;
712 bool abort = false;
713 if (! interactContinuation(
714 Any(licExc), task::XInteractionApprove::static_type(), xCmdEnv, &approve, &abort ))
715 throw css::deployment::DeploymentException(
716 OUSTR("Could not interact with user."), 0, Any());
717
718 if (approve == true)
719 return true;
720 else
721 return false;
722 //throw css::deployment::DeploymentException(
723 // OUSTR("Extension Manager: User declined the license."),
724 // static_cast<OWeakObject*>(this),
725 // Any( css::deployment::LicenseException(OUSTR("User declined the license."), 0, m_name, sLicense)));
726 }
727 return true;
728 } catch (css::ucb::CommandFailedException&) {
729 throw;
730 } catch (css::ucb::CommandAbortedException&) {
731 throw;
732 } catch (css::deployment::DeploymentException&) {
733 throw;
734 } catch (css::uno::RuntimeException&) {
735 throw;
736 } catch (css::uno::Exception&) {
737 Any anyExc = cppu::getCaughtException();
738 throw css::deployment::DeploymentException(OUSTR("Unexpected exception"), 0, anyExc);
739 }
740 }
741
checkPrerequisites(const css::uno::Reference<css::task::XAbortChannel> &,const css::uno::Reference<css::ucb::XCommandEnvironment> & xCmdEnv,sal_Bool alreadyInstalled)742 ::sal_Int32 BackendImpl::PackageImpl::checkPrerequisites(
743 const css::uno::Reference< css::task::XAbortChannel >&,
744 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv,
745 sal_Bool alreadyInstalled)
746 throw (css::deployment::DeploymentException,
747 css::deployment::ExtensionRemovedException,
748 css::ucb::CommandFailedException,
749 css::ucb::CommandAbortedException,
750 css::uno::RuntimeException)
751 {
752 if (m_bRemoved)
753 throw deployment::ExtensionRemovedException();
754 DescriptionInfoset info = getDescriptionInfoset();
755 if (!info.hasDescription())
756 return 0;
757
758 //always return LICENSE as long as the user did not accept the license
759 //so that XExtensonManager::checkPrerequisitesAndEnable will again
760 //check the license
761 if (!checkPlatform(xCmdEnv))
762 return deployment::Prerequisites::PLATFORM |
763 deployment::Prerequisites::LICENSE;
764 else if(!checkDependencies(xCmdEnv, info))
765 return deployment::Prerequisites::DEPENDENCIES |
766 deployment::Prerequisites::LICENSE;
767 else if(!checkLicense(xCmdEnv, info, alreadyInstalled))
768 return deployment::Prerequisites::LICENSE;
769 else
770 return 0;
771 }
772
checkDependencies(const css::uno::Reference<css::ucb::XCommandEnvironment> & xCmdEnv)773 ::sal_Bool BackendImpl::PackageImpl::checkDependencies(
774 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv )
775 throw (deployment::DeploymentException,
776 deployment::ExtensionRemovedException,
777 ucb::CommandFailedException,
778 RuntimeException)
779 {
780 if (m_bRemoved)
781 throw deployment::ExtensionRemovedException();
782 DescriptionInfoset info = getDescriptionInfoset();
783 if (!info.hasDescription())
784 return sal_True;
785
786 return checkDependencies(xCmdEnv, info);
787 }
788
getIdentifier()789 beans::Optional<OUString> BackendImpl::PackageImpl::getIdentifier()
790 throw (RuntimeException)
791 {
792 OUString identifier;
793 if (m_bRemoved)
794 identifier = m_identifier;
795 else
796 identifier = dp_misc::generateIdentifier(
797 getDescriptionInfoset().getIdentifier(), m_name);
798
799 return beans::Optional<OUString>(
800 true, identifier);
801 }
802
getVersion()803 OUString BackendImpl::PackageImpl::getVersion()
804 throw (deployment::ExtensionRemovedException, RuntimeException)
805 {
806 if (m_bRemoved)
807 throw deployment::ExtensionRemovedException();
808 return getDescriptionInfoset().getVersion();
809 }
810
getUpdateInformationURLs()811 Sequence<OUString> BackendImpl::PackageImpl::getUpdateInformationURLs()
812 throw (deployment::ExtensionRemovedException, RuntimeException)
813 {
814 if (m_bRemoved)
815 throw deployment::ExtensionRemovedException();
816 return getDescriptionInfoset().getUpdateInformationUrls();
817 }
818
getPublisherInfo()819 beans::StringPair BackendImpl::PackageImpl::getPublisherInfo()
820 throw (deployment::ExtensionRemovedException, RuntimeException)
821 {
822 if (m_bRemoved)
823 throw deployment::ExtensionRemovedException();
824 ::std::pair< OUString, OUString > aInfo = getDescriptionInfoset().getLocalizedPublisherNameAndURL();
825 beans::StringPair aStrPair( aInfo.first, aInfo.second );
826 return aStrPair;
827 }
828
829 //______________________________________________________________________________
getIcon(sal_Bool bHighContrast)830 uno::Reference< graphic::XGraphic > BackendImpl::PackageImpl::getIcon( sal_Bool bHighContrast )
831 throw (deployment::ExtensionRemovedException, RuntimeException )
832 {
833 if (m_bRemoved)
834 throw deployment::ExtensionRemovedException();
835
836 uno::Reference< graphic::XGraphic > xGraphic;
837
838 OUString aIconURL = getDescriptionInfoset().getIconURL( bHighContrast );
839 if ( aIconURL.getLength() )
840 {
841 OUString aFullIconURL = m_url_expanded + OUSTR("/") + aIconURL;
842
843 uno::Reference< XComponentContext > xContext( getMyBackend()->getComponentContext() );
844 uno::Reference< graphic::XGraphicProvider > xGraphProvider(
845 xContext->getServiceManager()->createInstanceWithContext( OUSTR( "com.sun.star.graphic.GraphicProvider" ), xContext ),
846 uno::UNO_QUERY );
847
848 if ( xGraphProvider.is() )
849 {
850 uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
851 aMediaProps[0].Name = OUSTR( "URL" );
852 aMediaProps[0].Value <<= aFullIconURL;
853
854 xGraphic = xGraphProvider->queryGraphic( aMediaProps );
855 }
856 }
857
858 return xGraphic;
859 }
860
861 //______________________________________________________________________________
processPackage_(::osl::ResettableMutexGuard &,bool doRegisterPackage,bool startup,::rtl::Reference<AbortChannel> const & abortChannel,Reference<ucb::XCommandEnvironment> const & xCmdEnv)862 void BackendImpl::PackageImpl::processPackage_(
863 ::osl::ResettableMutexGuard &,
864 bool doRegisterPackage,
865 bool startup,
866 ::rtl::Reference<AbortChannel> const & abortChannel,
867 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
868 {
869 const Sequence< Reference<deployment::XPackage> > bundle(
870 getBundle( abortChannel.get(), xCmdEnv ) );
871
872 if (doRegisterPackage)
873 {
874 ExtensionBackendDb::Data data;
875 const sal_Int32 len = bundle.getLength();
876 for ( sal_Int32 pos = 0; pos < len; ++pos )
877 {
878 checkAborted(abortChannel);
879 Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
880 Reference<task::XAbortChannel> xSubAbortChannel(
881 xPackage->createAbortChannel() );
882 AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
883 try {
884 xPackage->registerPackage( startup, xSubAbortChannel, xCmdEnv );
885 }
886 catch (Exception &)
887 {
888 //We even try a rollback if the user cancelled the action (CommandAbortedException)
889 //in order to prevent invalid database entries.
890 Any exc( ::cppu::getCaughtException() );
891 // try to handle exception, notify:
892 bool approve = false, abort = false;
893 if (! interactContinuation(
894 Any( lang::WrappedTargetException(
895 OUSTR("bundle item registration error!"),
896 static_cast<OWeakObject *>(this), exc ) ),
897 task::XInteractionApprove::static_type(), xCmdEnv,
898 &approve, &abort )) {
899 OSL_ASSERT( !approve && !abort );
900 if (m_legacyBundle) // default for legacy packages: ignore
901 continue;
902 // no selection at all, so rethrow;
903 // no C++ rethrow after getCaughtException(),
904 // see cppuhelper/exc_hlp.hxx:
905 ::cppu::throwException(exc);
906 }
907 if (approve && !abort) // ignore error, just continue
908 continue;
909
910 {
911 ProgressLevel progress(
912 xCmdEnv, OUSTR("rollback...") );
913 // try rollback
914 for ( ; pos--; )
915 {
916 try {
917 bundle[ pos ]->revokePackage(
918 xSubAbortChannel, xCmdEnv );
919 }
920 catch (Exception &)
921 {
922 OSL_ENSURE( 0, ::rtl::OUStringToOString(
923 ::comphelper::anyToString(
924 ::cppu::getCaughtException() ),
925 RTL_TEXTENCODING_UTF8 ).getStr() );
926 // ignore any errors of rollback
927 }
928 }
929 progress.update( OUSTR("rollback finished.") );
930 }
931
932 deployment::DeploymentException dpExc;
933 if (exc >>= dpExc) {
934 throw ucb::CommandFailedException(
935 dpExc.Message, dpExc.Context, dpExc.Cause );
936 }
937 else {
938 // rethrow CommandFailedException
939 ::cppu::throwException(exc);
940 }
941 }
942 data.items.push_back(
943 ::std::make_pair(xPackage->getURL(),
944 xPackage->getPackageType()->getMediaType()));
945 }
946 getMyBackend()->addDataToDb(getURL(), data);
947 }
948 else
949 {
950 // revoke in reverse order:
951 for ( sal_Int32 pos = bundle.getLength(); pos--; )
952 {
953 checkAborted(abortChannel);
954 Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
955 Reference<task::XAbortChannel> xSubAbortChannel(
956 xPackage->createAbortChannel() );
957 AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
958 try {
959 bundle[ pos ]->revokePackage( xSubAbortChannel, xCmdEnv );
960 }
961 catch (RuntimeException &) {
962 throw;
963 }
964 catch (ucb::CommandAbortedException &) {
965 throw;
966 }
967 catch (Exception &) {
968 // CommandFailedException, DeploymentException:
969 Any exc( ::cppu::getCaughtException() );
970 // try to handle exception, notify:
971 bool approve = false, abort = false;
972 if (! interactContinuation(
973 Any( lang::WrappedTargetException(
974 OUSTR("bundle item revocation error!"),
975 static_cast<OWeakObject *>(this), exc ) ),
976 task::XInteractionApprove::static_type(), xCmdEnv,
977 &approve, &abort )) {
978 OSL_ASSERT( !approve && !abort );
979 if (m_legacyBundle) // default for legacy packages: ignore
980 continue;
981 // no selection at all, so rethrow
982 // no C++ rethrow after getCaughtException(),
983 // see cppuhelper/exc_hlp.hxx:
984 ::cppu::throwException(exc);
985 }
986 // ignore errors when revoking, although abort may have been
987 // selected
988 }
989 }
990 getMyBackend()->revokeEntryFromDb(getURL());
991 }
992 }
993
994 //______________________________________________________________________________
getDescription()995 OUString BackendImpl::PackageImpl::getDescription()
996 throw (deployment::ExtensionRemovedException, RuntimeException)
997 {
998 if (m_bRemoved)
999 throw deployment::ExtensionRemovedException();
1000
1001 const OUString sRelativeURL(getDescriptionInfoset().getLocalizedDescriptionURL());
1002 OUString sDescription;
1003 if (sRelativeURL.getLength())
1004 {
1005 OUString sURL = m_url_expanded + OUSTR("/") + sRelativeURL;
1006
1007 try
1008 {
1009 sDescription = getTextFromURL( css::uno::Reference< css::ucb::XCommandEnvironment >(), sURL );
1010 }
1011 catch ( css::deployment::DeploymentException& )
1012 {
1013 OSL_ENSURE( 0, ::rtl::OUStringToOString( ::comphelper::anyToString( ::cppu::getCaughtException() ), RTL_TEXTENCODING_UTF8 ).getStr() );
1014 }
1015 }
1016
1017 if (sDescription.getLength())
1018 return sDescription;
1019 return m_oldDescription;
1020 }
1021
1022 //______________________________________________________________________________
getLicenseText()1023 OUString BackendImpl::PackageImpl::getLicenseText()
1024 throw (deployment::ExtensionRemovedException, RuntimeException)
1025 {
1026 if (m_bRemoved)
1027 throw deployment::ExtensionRemovedException();
1028
1029 OUString sLicense;
1030 DescriptionInfoset aInfo = getDescriptionInfoset();
1031
1032 ::boost::optional< SimpleLicenseAttributes > aSimplLicAttr = aInfo.getSimpleLicenseAttributes();
1033 if ( aSimplLicAttr )
1034 {
1035 OUString aLicenseURL = aInfo.getLocalizedLicenseURL();
1036
1037 if ( aLicenseURL.getLength() )
1038 {
1039 OUString aFullURL = m_url_expanded + OUSTR("/") + aLicenseURL;
1040 sLicense = getTextFromURL( Reference< ucb::XCommandEnvironment >(), aFullURL);
1041 }
1042 }
1043
1044 return sLicense;
1045 }
1046
1047 //______________________________________________________________________________
exportTo(OUString const & destFolderURL,OUString const & newTitle,sal_Int32 nameClashAction,Reference<ucb::XCommandEnvironment> const & xCmdEnv)1048 void BackendImpl::PackageImpl::exportTo(
1049 OUString const & destFolderURL, OUString const & newTitle,
1050 sal_Int32 nameClashAction, Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1051 throw (ucb::CommandFailedException,
1052 deployment::ExtensionRemovedException,
1053 ucb::CommandAbortedException, RuntimeException)
1054 {
1055 if (m_bRemoved)
1056 throw deployment::ExtensionRemovedException();
1057
1058 ::ucbhelper::Content sourceContent( m_url_expanded, xCmdEnv );
1059 OUString title(newTitle);
1060 if (title.getLength() == 0)
1061 sourceContent.getPropertyValue( StrTitle::get() ) >>= title;
1062 OUString destURL( makeURL( destFolderURL, ::rtl::Uri::encode(
1063 title, rtl_UriCharClassPchar,
1064 rtl_UriEncodeIgnoreEscapes,
1065 RTL_TEXTENCODING_UTF8 ) ) );
1066
1067 if (nameClashAction == ucb::NameClash::ASK)
1068 {
1069 if (create_ucb_content(
1070 0, destURL, xCmdEnv, false /* no throw */ )) {
1071 bool replace = false, abort = false;
1072 if (! interactContinuation(
1073 Any( ucb::NameClashResolveRequest(
1074 OUSTR("file already exists: ") + title,
1075 static_cast<OWeakObject *>(this),
1076 task::InteractionClassification_QUERY,
1077 destFolderURL, title, OUString() ) ),
1078 ucb::XInteractionReplaceExistingData::static_type(), xCmdEnv,
1079 &replace, &abort ) || !replace) {
1080 return;
1081 }
1082 }
1083 }
1084 else if (nameClashAction != ucb::NameClash::OVERWRITE) {
1085 throw ucb::CommandFailedException(
1086 OUSTR("unsupported nameClashAction!"),
1087 static_cast<OWeakObject *>(this), Any() );
1088 }
1089 erase_path( destURL, xCmdEnv );
1090
1091 ::rtl::OUStringBuffer buf;
1092 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") );
1093 buf.append( ::rtl::Uri::encode( destURL,
1094 rtl_UriCharClassRegName,
1095 rtl_UriEncodeIgnoreEscapes,
1096 RTL_TEXTENCODING_UTF8 ) );
1097 buf.append( static_cast<sal_Unicode>('/') );
1098 OUString destFolder( buf.makeStringAndClear() );
1099
1100 ::ucbhelper::Content destFolderContent( destFolder, xCmdEnv );
1101 {
1102 // transfer every item of folder into zip:
1103 Reference<sdbc::XResultSet> xResultSet(
1104 sourceContent.createCursor(
1105 Sequence<OUString>(),
1106 ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
1107 ProgressLevel progress( xCmdEnv, OUString() );
1108 while (xResultSet->next())
1109 {
1110 ::ucbhelper::Content subContent(
1111 Reference<ucb::XContentAccess>(
1112 xResultSet, UNO_QUERY_THROW )->queryContent(), xCmdEnv );
1113 if (! destFolderContent.transferContent(
1114 subContent, ::ucbhelper::InsertOperation_COPY,
1115 OUString(), ucb::NameClash::OVERWRITE ))
1116 throw RuntimeException( OUSTR("UCB transferContent() failed!"),
1117 static_cast<OWeakObject *>(this) );
1118 progress.update( Any() ); // animating progress bar
1119 }
1120 }
1121
1122 // assure META-INF folder:
1123 ::ucbhelper::Content metainfFolderContent;
1124 create_folder( &metainfFolderContent,
1125 makeURL( destFolderContent.getURL(), OUSTR("META-INF") ),
1126 xCmdEnv );
1127
1128 if (m_legacyBundle)
1129 {
1130 // easy to migrate legacy bundles to new format:
1131 // just export them once using a .oxt name!
1132 // set detected media-types of any bundle item:
1133
1134 // collect all manifest entries:
1135 Sequence< Reference<deployment::XPackage> > bundle;
1136 try {
1137 bundle = getBundle( Reference<task::XAbortChannel>(), xCmdEnv );
1138 }
1139 // xxx todo: think about exception specs:
1140 catch (deployment::DeploymentException &) {
1141 OSL_ENSURE( 0, ::rtl::OUStringToOString(
1142 ::comphelper::anyToString(
1143 ::cppu::getCaughtException() ),
1144 RTL_TEXTENCODING_UTF8 ).getStr() );
1145 }
1146 catch (lang::IllegalArgumentException & exc) {
1147 (void) exc;
1148 OSL_ENSURE( 0, ::rtl::OUStringToOString(
1149 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1150 }
1151
1152 ::std::vector< Sequence<beans::PropertyValue> > manifest;
1153 manifest.reserve( bundle.getLength() );
1154 sal_Int32 baseURLlen = m_url_expanded.getLength();
1155 Reference<deployment::XPackage> const *pbundle = bundle.getConstArray();
1156 const OUString strMediaType = OUSTR("MediaType");
1157 const OUString strFullPath = OUSTR("FullPath");
1158 const OUString strIsFolder = OUSTR("IsFolder");
1159 for ( sal_Int32 pos = bundle.getLength(); pos--; )
1160 {
1161 Reference<deployment::XPackage> const & xPackage = pbundle[ pos ];
1162 OUString url_( expandUnoRcUrl( xPackage->getURL() ) );
1163 OSL_ASSERT( url_.getLength() >= baseURLlen );
1164 OUString fullPath;
1165 if (url_.getLength() > baseURLlen)
1166 fullPath = url_.copy( baseURLlen + 1 );
1167 ::ucbhelper::Content ucbContent( url_, xCmdEnv );
1168 if (ucbContent.getPropertyValue(strIsFolder).get<bool>())
1169 fullPath += OUSTR("/");
1170 Sequence<beans::PropertyValue> attribs( 2 );
1171 beans::PropertyValue * pattribs = attribs.getArray();
1172 pattribs[ 0 ].Name = strFullPath;
1173 pattribs[ 0 ].Value <<= fullPath;
1174 pattribs[ 1 ].Name = strMediaType;
1175 const Reference<deployment::XPackageTypeInfo> xPackageType(
1176 xPackage->getPackageType() );
1177 OUString mediaType;
1178 OSL_ASSERT( xPackageType.is() );
1179 if (xPackageType.is())
1180 mediaType = xPackageType->getMediaType();
1181 else
1182 mediaType = OUSTR("unknown");
1183 pattribs[ 1 ].Value <<= mediaType;
1184 manifest.push_back( attribs );
1185 }
1186
1187 // write into pipe:
1188 Reference<XComponentContext> xContext(
1189 getMyBackend()->getComponentContext() );
1190 Reference<packages::manifest::XManifestWriter> xManifestWriter(
1191 xContext->getServiceManager()->createInstanceWithContext(
1192 OUSTR("com.sun.star.packages.manifest.ManifestWriter"),
1193 xContext ), UNO_QUERY_THROW );
1194 Reference<io::XOutputStream> xPipe(
1195 xContext->getServiceManager()->createInstanceWithContext(
1196 OUSTR("com.sun.star.io.Pipe"), xContext ), UNO_QUERY_THROW );
1197 xManifestWriter->writeManifestSequence(
1198 xPipe, comphelper::containerToSequence(manifest) );
1199
1200 // write buffered pipe data to content:
1201 ::ucbhelper::Content manifestContent(
1202 makeURL( metainfFolderContent.getURL(), OUSTR("manifest.xml") ),
1203 xCmdEnv );
1204 manifestContent.writeStream(
1205 Reference<io::XInputStream>( xPipe, UNO_QUERY_THROW ),
1206 true /* replace existing */ );
1207 }
1208 else
1209 {
1210 // overwrite manifest.xml:
1211 ::ucbhelper::Content manifestContent;
1212 if ( ! create_ucb_content(
1213 &manifestContent,
1214 makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ),
1215 xCmdEnv, false ) )
1216 {
1217 OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" );
1218 return;
1219 }
1220
1221 if (! metainfFolderContent.transferContent(
1222 manifestContent, ::ucbhelper::InsertOperation_COPY,
1223 OUString(), ucb::NameClash::OVERWRITE ))
1224 throw RuntimeException( OUSTR("UCB transferContent() failed!"),
1225 static_cast<OWeakObject *>(this) );
1226 }
1227
1228 // xxx todo: maybe obsolete in the future
1229 try {
1230 destFolderContent.executeCommand( OUSTR("flush"), Any() );
1231 }
1232 catch (ucb::UnsupportedCommandException &) {
1233 }
1234 }
1235
1236 //______________________________________________________________________________
isBundle()1237 sal_Bool BackendImpl::PackageImpl::isBundle() throw (RuntimeException)
1238 {
1239 return true;
1240 }
1241
1242 //______________________________________________________________________________
getBundle(Reference<task::XAbortChannel> const & xAbortChannel,Reference<ucb::XCommandEnvironment> const & xCmdEnv)1243 Sequence< Reference<deployment::XPackage> > BackendImpl::PackageImpl::getBundle(
1244 Reference<task::XAbortChannel> const & xAbortChannel,
1245 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1246 throw (deployment::DeploymentException,
1247 ucb::CommandFailedException, ucb::CommandAbortedException,
1248 lang::IllegalArgumentException, RuntimeException)
1249 {
1250 Sequence< Reference<deployment::XPackage> > * pBundle = m_pBundle;
1251 if (pBundle == 0)
1252 {
1253 t_packagevec bundle;
1254 if (m_bRemoved)
1255 {
1256 bundle = getPackagesFromDb(xCmdEnv);
1257 }
1258 else
1259 {
1260 try {
1261 if (m_legacyBundle)
1262 {
1263 // .zip legacy packages allow script.xlb, dialog.xlb in bundle
1264 // root folder:
1265 OUString mediaType;
1266 // probe for script.xlb:
1267 if (create_ucb_content(
1268 0, makeURL( m_url_expanded, OUSTR("script.xlb") ),
1269 xCmdEnv, false /* no throw */ )) {
1270 mediaType = OUSTR("application/vnd.sun.star.basic-library");
1271 }
1272 // probe for dialog.xlb:
1273 else if (create_ucb_content(
1274 0, makeURL( m_url_expanded, OUSTR("dialog.xlb") ),
1275 xCmdEnv, false /* no throw */ ))
1276 mediaType = OUSTR("application/vnd.sun.star."
1277 "dialog-library");
1278
1279 if (mediaType.getLength() > 0) {
1280 const Reference<deployment::XPackage> xPackage(
1281 bindBundleItem( getURL(), mediaType, false, OUString(),
1282 xCmdEnv ) );
1283 if (xPackage.is())
1284 bundle.push_back( xPackage );
1285 // continue scanning:
1286 }
1287 scanLegacyBundle( bundle, getURL(),
1288 AbortChannel::get(xAbortChannel), xCmdEnv );
1289 }
1290 else
1291 {
1292 // .oxt:
1293 scanBundle( bundle, AbortChannel::get(xAbortChannel), xCmdEnv );
1294 }
1295
1296 }
1297 catch (RuntimeException &) {
1298 throw;
1299 }
1300 catch (ucb::CommandFailedException &) {
1301 throw;
1302 }
1303 catch (ucb::CommandAbortedException &) {
1304 throw;
1305 }
1306 catch (deployment::DeploymentException &) {
1307 throw;
1308 }
1309 catch (Exception &) {
1310 Any exc( ::cppu::getCaughtException() );
1311 throw deployment::DeploymentException(
1312 OUSTR("error scanning bundle: ") + getURL(),
1313 static_cast<OWeakObject *>(this), exc );
1314 }
1315 }
1316
1317 // sort: schema before config data, typelibs before components:
1318 Sequence< Reference<deployment::XPackage> > ret( bundle.size() );
1319 Reference<deployment::XPackage> * pret = ret.getArray();
1320 sal_Int32 lower_end = 0;
1321 sal_Int32 upper_end = ret.getLength();
1322 t_packagevec::const_iterator iPos( bundle.begin() );
1323 t_packagevec::const_iterator const iEnd( bundle.end() );
1324 for ( ; iPos != iEnd; ++iPos )
1325 {
1326 const Reference<deployment::XPackageTypeInfo> xPackageType(
1327 (*iPos)->getPackageType() );
1328 OSL_ASSERT( xPackageType.is() );
1329 if (xPackageType.is()) {
1330 const OUString mediaType( xPackageType->getMediaType() );
1331 String type, subType;
1332 INetContentTypeParameterList params;
1333 if (INetContentTypes::parse(
1334 mediaType, type, subType, ¶ms ) &&
1335 type.EqualsIgnoreCaseAscii("application") &&
1336 (subType.EqualsIgnoreCaseAscii(
1337 "vnd.sun.star.uno-component") ||
1338 subType.EqualsIgnoreCaseAscii(
1339 "vnd.sun.star.configuration-data")))
1340 {
1341 --upper_end;
1342 pret[ upper_end ] = *iPos;
1343 continue;
1344 }
1345 }
1346 pret[ lower_end ] = *iPos;
1347 ++lower_end;
1348 }
1349 OSL_ASSERT( lower_end == upper_end );
1350
1351 const ::osl::MutexGuard guard( getMutex() );
1352 pBundle = m_pBundle;
1353 if (pBundle == 0) {
1354 m_bundle = ret;
1355 pBundle = &m_bundle;
1356 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1357 m_pBundle = pBundle;
1358 }
1359 }
1360 else {
1361 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1362 }
1363 return *pBundle;
1364 }
1365
isBundle_(OUString const & mediaType)1366 inline bool isBundle_( OUString const & mediaType )
1367 {
1368 // xxx todo: additional parsing?
1369 return mediaType.getLength() > 0 &&
1370 (mediaType.matchIgnoreAsciiCaseAsciiL(
1371 RTL_CONSTASCII_STRINGPARAM(
1372 "application/vnd.sun.star.package-bundle") ) ||
1373 mediaType.matchIgnoreAsciiCaseAsciiL(
1374 RTL_CONSTASCII_STRINGPARAM(
1375 "application/vnd.sun.star.legacy-package-bundle") ));
1376 }
1377
1378 //______________________________________________________________________________
bindBundleItem(OUString const & url,OUString const & mediaType,sal_Bool bRemoved,OUString const & identifier,Reference<ucb::XCommandEnvironment> const & xCmdEnv,bool notifyDetectionError)1379 Reference<deployment::XPackage> BackendImpl::PackageImpl::bindBundleItem(
1380 OUString const & url, OUString const & mediaType,
1381 sal_Bool bRemoved, OUString const & identifier,
1382 Reference<ucb::XCommandEnvironment> const & xCmdEnv,
1383 bool notifyDetectionError )
1384 {
1385 // ignore any nested bundles:
1386 if (isBundle_(mediaType))
1387 return Reference<deployment::XPackage>();
1388
1389 Reference<deployment::XPackage>xPackage;
1390 try {
1391 xPackage.set( getMyBackend()->m_xRootRegistry->bindPackage(
1392 url, mediaType, bRemoved, identifier, xCmdEnv ) );
1393 OSL_ASSERT( xPackage.is() );
1394 }
1395 catch (RuntimeException &) {
1396 throw;
1397 }
1398 catch (ucb::CommandFailedException &) {
1399 // ignore already handled error
1400 }
1401 catch (Exception &) {
1402 const Any exc( ::cppu::getCaughtException() );
1403 if (notifyDetectionError ||
1404 !exc.isExtractableTo(
1405 ::getCppuType( reinterpret_cast<
1406 lang::IllegalArgumentException const *>(0) ) ))
1407 {
1408 interactContinuation(
1409 Any( lang::WrappedTargetException(
1410 OUSTR("bundle item error!"),
1411 static_cast<OWeakObject *>(this), exc ) ),
1412 task::XInteractionApprove::static_type(), xCmdEnv, 0, 0 );
1413 }
1414 }
1415
1416 if (xPackage.is()) {
1417 const Reference<deployment::XPackageTypeInfo> xPackageType(
1418 xPackage->getPackageType() );
1419 OSL_ASSERT( xPackageType.is() );
1420 // ignore any nested bundles:
1421 if (xPackageType.is() && isBundle_( xPackageType->getMediaType() ))
1422 xPackage.clear();
1423 }
1424 return xPackage;
1425 }
1426
1427 //______________________________________________________________________________
scanBundle(t_packagevec & bundle,::rtl::Reference<AbortChannel> const & abortChannel,Reference<ucb::XCommandEnvironment> const & xCmdEnv)1428 void BackendImpl::PackageImpl::scanBundle(
1429 t_packagevec & bundle,
1430 ::rtl::Reference<AbortChannel> const & abortChannel,
1431 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1432 {
1433 OSL_ASSERT( !m_legacyBundle );
1434
1435 ::ucbhelper::Content manifestContent;
1436 if (! create_ucb_content(
1437 &manifestContent,
1438 makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ),
1439 xCmdEnv, false /* no throw */ ))
1440 {
1441 OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" );
1442 return;
1443 }
1444
1445
1446 const lang::Locale officeLocale = getOfficeLocale();
1447 OUString descrFile;
1448 lang::Locale descrFileLocale;
1449
1450 const Reference<XComponentContext> xContext(
1451 getMyBackend()->getComponentContext() );
1452 Reference<packages::manifest::XManifestReader> xManifestReader(
1453 xContext->getServiceManager()->createInstanceWithContext(
1454 OUSTR("com.sun.star.packages.manifest.ManifestReader"),
1455 xContext ), UNO_QUERY_THROW );
1456 const Sequence< Sequence<beans::PropertyValue> > manifestSeq(
1457 xManifestReader->readManifestSequence( manifestContent.openStream() ) );
1458 const OUString packageRootURL( getURL() );
1459 for ( sal_Int32 pos = manifestSeq.getLength(); pos--; )
1460 {
1461 OUString fullPath, mediaType;
1462 Sequence<beans::PropertyValue> const & attribs = manifestSeq[ pos ];
1463 for ( sal_Int32 i = attribs.getLength(); i--; )
1464 {
1465 if (fullPath.getLength() > 0 && mediaType.getLength() > 0)
1466 break;
1467 if (attribs[i].Name.equalsAsciiL(
1468 RTL_CONSTASCII_STRINGPARAM("FullPath") ))
1469 attribs[i].Value >>= fullPath;
1470 else if (attribs[i].Name.equalsAsciiL(
1471 RTL_CONSTASCII_STRINGPARAM("MediaType") ))
1472 attribs[i].Value >>= mediaType;
1473 }
1474
1475 if (fullPath.getLength() == 0 || mediaType.getLength() == 0 ||
1476 mediaType.equalsAsciiL( // opt: exclude common text/xml
1477 RTL_CONSTASCII_STRINGPARAM("text/xml") ))
1478 continue;
1479
1480 String type, subType;
1481 INetContentTypeParameterList params;
1482 if (! INetContentTypes::parse( mediaType, type, subType, ¶ms ))
1483 continue;
1484
1485 INetContentTypeParameter const * param = params.find(
1486 ByteString("platform") );
1487 if (param != 0 && !platform_fits( param->m_sValue ))
1488 continue;
1489 const OUString url( makeURL( packageRootURL, fullPath ) );
1490
1491 // check for bundle description:
1492 if (type.EqualsIgnoreCaseAscii("application") &&
1493 subType.EqualsIgnoreCaseAscii(
1494 "vnd.sun.star.package-bundle-description"))
1495 {
1496 // check locale:
1497 param = params.find( ByteString("locale") );
1498 if (param == 0) {
1499 if (descrFile.getLength() == 0)
1500 descrFile = url;
1501 }
1502 else {
1503 // match best locale:
1504 lang::Locale locale( toLocale(param->m_sValue) );
1505 if (locale.Language == officeLocale.Language)
1506 {
1507 if (descrFileLocale.Country == officeLocale.Country
1508 && locale.Country != officeLocale.Country)
1509 continue;
1510 if (descrFileLocale.Variant == officeLocale.Variant
1511 && locale.Variant != officeLocale.Variant)
1512 continue;
1513 descrFile = url;
1514 descrFileLocale = locale;
1515 }
1516 }
1517 continue;
1518 }
1519
1520 checkAborted( abortChannel );
1521
1522 //We make sure that we only create one XPackage for a particular URL.
1523 //Sometime programmers insert the same URL several times in the manifest
1524 //which may lead to DisposedExceptions.
1525 if (bundle.end() == std::find_if(bundle.begin(), bundle.end(), XPackage_eq(url)))
1526 {
1527 const Reference<deployment::XPackage> xPackage(
1528 bindBundleItem( url, mediaType, false, OUString(), xCmdEnv ) );
1529 if (xPackage.is())
1530 bundle.push_back( xPackage );
1531 }
1532 else
1533 {
1534 fprintf(stderr, "manifest.xml contains a duplicate entry!\n");
1535 }
1536 }
1537
1538 if (descrFile.getLength() > 0)
1539 {
1540 ::ucbhelper::Content descrFileContent;
1541 if (create_ucb_content( &descrFileContent, descrFile,
1542 xCmdEnv, false /* no throw */ ))
1543 {
1544 // patch description:
1545 ::rtl::ByteSequence bytes( readFile( descrFileContent ) );
1546 ::rtl::OUStringBuffer buf;
1547 if ( bytes.getLength() )
1548 {
1549 buf.append( OUString( reinterpret_cast<sal_Char const *>(
1550 bytes.getConstArray() ),
1551 bytes.getLength(), RTL_TEXTENCODING_UTF8 ) );
1552 }
1553 else
1554 {
1555 buf.append( Package::getDescription() );
1556 }
1557 m_oldDescription = buf.makeStringAndClear();
1558 }
1559 }
1560 }
1561
1562 //______________________________________________________________________________
scanLegacyBundle(t_packagevec & bundle,OUString const & url,::rtl::Reference<AbortChannel> const & abortChannel,Reference<ucb::XCommandEnvironment> const & xCmdEnv,bool skip_registration)1563 void BackendImpl::PackageImpl::scanLegacyBundle(
1564 t_packagevec & bundle,
1565 OUString const & url,
1566 ::rtl::Reference<AbortChannel> const & abortChannel,
1567 Reference<ucb::XCommandEnvironment> const & xCmdEnv,
1568 bool skip_registration )
1569 {
1570 ::ucbhelper::Content ucbContent( url, xCmdEnv );
1571
1572 // check for platform pathes:
1573 const OUString title( ucbContent.getPropertyValue(
1574 StrTitle::get() ).get<OUString>() );
1575 if (title.endsWithIgnoreAsciiCaseAsciiL(
1576 RTL_CONSTASCII_STRINGPARAM(".plt") ) &&
1577 !platform_fits( title.copy( 0, title.getLength() - 4 ) )) {
1578 return;
1579 }
1580 if (title.endsWithIgnoreAsciiCaseAsciiL(
1581 RTL_CONSTASCII_STRINGPARAM("skip_registration") ))
1582 skip_registration = true;
1583
1584 OUString ar [] = { StrTitle::get(), OUSTR("IsFolder") };
1585 Reference<sdbc::XResultSet> xResultSet(
1586 ucbContent.createCursor(
1587 Sequence<OUString>( ar, ARLEN(ar) ),
1588 ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
1589 while (xResultSet->next())
1590 {
1591 checkAborted( abortChannel );
1592
1593 const Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW );
1594 const OUString title_enc( ::rtl::Uri::encode(
1595 xRow->getString( 1 /* Title */ ),
1596 rtl_UriCharClassPchar,
1597 rtl_UriEncodeIgnoreEscapes,
1598 RTL_TEXTENCODING_UTF8 ) );
1599 const OUString path( makeURL( url, title_enc ) );
1600
1601 OUString mediaType;
1602 const Reference<deployment::XPackage> xPackage(
1603 bindBundleItem( path, OUString() /* detect */, false, OUString(),
1604 xCmdEnv, false /* ignore detection errors */ ) );
1605 if (xPackage.is()) {
1606 const Reference<deployment::XPackageTypeInfo> xPackageType(
1607 xPackage->getPackageType() );
1608 OSL_ASSERT( xPackageType.is() );
1609 if (xPackageType.is())
1610 mediaType = xPackageType->getMediaType();
1611
1612 if (skip_registration &&
1613 // xxx todo: additional parsing?
1614 mediaType.matchIgnoreAsciiCaseAsciiL(
1615 RTL_CONSTASCII_STRINGPARAM(
1616 "application/vnd.sun.star.uno-component") ))
1617 continue;
1618
1619 bundle.push_back( xPackage );
1620 }
1621
1622 if (mediaType.getLength() == 0 ||
1623 // script.xlb, dialog.xlb can be met everywhere:
1624 mediaType.matchIgnoreAsciiCaseAsciiL(
1625 RTL_CONSTASCII_STRINGPARAM(
1626 "application/vnd.sun.star.basic-library") ) ||
1627 mediaType.matchIgnoreAsciiCaseAsciiL(
1628 RTL_CONSTASCII_STRINGPARAM(
1629 "application/vnd.sun.star.dialog-library") ))
1630 {
1631 if (xRow->getBoolean( 2 /* IsFolder */ )) { // recurse into folder:
1632 scanLegacyBundle(
1633 bundle, path, abortChannel, xCmdEnv, skip_registration );
1634 }
1635 }
1636 }
1637 }
1638
getDisplayName()1639 OUString BackendImpl::PackageImpl::getDisplayName()
1640 throw (deployment::ExtensionRemovedException, RuntimeException)
1641 {
1642 if (m_bRemoved)
1643 throw deployment::ExtensionRemovedException();
1644
1645 OUString sName = getDescriptionInfoset().getLocalizedDisplayName();
1646 if (sName.getLength() == 0)
1647 return m_displayName;
1648 else
1649 return sName;
1650 }
1651
1652 ::std::vector<Reference<deployment::XPackage> >
getPackagesFromDb(Reference<ucb::XCommandEnvironment> const & xCmdEnv)1653 BackendImpl::PackageImpl::getPackagesFromDb(
1654 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1655 {
1656 ::std::vector<Reference<deployment::XPackage> > retVector;
1657
1658 typedef ::std::vector< ::std::pair<OUString, OUString> >::const_iterator ITC;
1659 for (ITC i = m_dbData.items.begin(); i != m_dbData.items.end(); i++)
1660 {
1661 Reference<deployment::XPackage> xExtension =
1662 bindBundleItem(i->first, i->second, true, m_identifier, xCmdEnv);
1663 OSL_ASSERT(xExtension.is());
1664 retVector.push_back(xExtension);
1665 }
1666
1667 return retVector;
1668 }
1669
1670 } // anon namespace
1671
1672 //==============================================================================
create(Reference<deployment::XPackageRegistry> const & xRootRegistry,OUString const & context,OUString const & cachePath,bool readOnly,Reference<XComponentContext> const & xComponentContext)1673 Reference<deployment::XPackageRegistry> create(
1674 Reference<deployment::XPackageRegistry> const & xRootRegistry,
1675 OUString const & context, OUString const & cachePath, bool readOnly,
1676 Reference<XComponentContext> const & xComponentContext )
1677 {
1678 Sequence<Any> args(
1679 cachePath.getLength() == 0 ? 1 : 3 );
1680 args[ 0 ] <<= context;
1681 if (cachePath.getLength() > 0) {
1682 args[ 1 ] <<= cachePath;
1683 args[ 2 ] <<= readOnly;
1684 }
1685 return new BackendImpl( args, xComponentContext, xRootRegistry );
1686 }
1687
1688 } // namespace bundle
1689 } // namespace backend
1690 } // namespace dp_registry
1691
1692