LibreOffice Module desktop (master) 1
dp_script.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21#include <strings.hrc>
22#include "dp_lib_container.h"
23#include <dp_backend.h>
24#include <dp_misc.h>
25#include <dp_ucb.h>
26#include <ucbhelper/content.hxx>
28#include <svl/inettype.hxx>
29#include <com/sun/star/util/XUpdatable.hpp>
30#include <com/sun/star/script/XLibraryContainer3.hpp>
31#include <memory>
32#include <string_view>
33
36
37using namespace ::dp_misc;
38using namespace ::com::sun::star;
39using namespace ::com::sun::star::uno;
40using namespace ::com::sun::star::ucb;
41
43namespace {
44
45typedef ::cppu::ImplInheritanceHelper<
47
48class BackendImpl : public t_helper
49{
50 class PackageImpl : public ::dp_registry::backend::Package
51 {
52 BackendImpl * getMyBackend() const;
53
54 const OUString m_scriptURL;
55 const OUString m_dialogURL;
56 OUString m_dialogName;
57
58 // Package
59 virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
60 ::osl::ResettableMutexGuard & guard,
61 ::rtl::Reference<AbortChannel> const & abortChannel,
62 Reference<XCommandEnvironment> const & xCmdEnv ) override;
63 virtual void processPackage_(
64 ::osl::ResettableMutexGuard & guard,
65 bool registerPackage,
66 bool startup,
67 ::rtl::Reference<AbortChannel> const & abortChannel,
68 Reference<XCommandEnvironment> const & xCmdEnv ) override;
69
70 public:
71 PackageImpl(
72 ::rtl::Reference<BackendImpl> const & myBackend,
73 OUString const & url,
74 Reference<XCommandEnvironment> const &xCmdEnv,
75 OUString const & scriptURL, OUString const & dialogURL,
76 bool bRemoved, OUString const & identifier);
77 };
78 friend class PackageImpl;
79
80 // PackageRegistryBackend
81 virtual Reference<deployment::XPackage> bindPackage_(
82 OUString const & url, OUString const & mediaType,
83 bool bRemoved, OUString const & identifier,
84 Reference<XCommandEnvironment> const & xCmdEnv ) override;
85
86 void addDataToDb(OUString const & url);
87 bool hasActiveEntry(std::u16string_view url);
88 void revokeEntryFromDb(std::u16string_view url);
89
90 const Reference<deployment::XPackageTypeInfo> m_xBasicLibTypeInfo;
91 const Reference<deployment::XPackageTypeInfo> m_xDialogLibTypeInfo;
92 Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
93 std::unique_ptr<ScriptBackendDb> m_backendDb;
94public:
95 BackendImpl( Sequence<Any> const & args,
96 Reference<XComponentContext> const & xComponentContext );
97
98 // XServiceInfo
99 virtual OUString SAL_CALL getImplementationName() override;
100 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
101 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
102
103 // XUpdatable
104 virtual void SAL_CALL update() override;
105
106 // XPackageRegistry
107 virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
108 getSupportedPackageTypes() override;
109 virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType) override;
110
111};
112
113
114BackendImpl::PackageImpl::PackageImpl(
115 ::rtl::Reference<BackendImpl> const & myBackend,
116 OUString const & url,
117 Reference<XCommandEnvironment> const &xCmdEnv,
118 OUString const & scriptURL, OUString const & dialogURL, bool bRemoved,
119 OUString const & identifier)
120 : Package( myBackend, url,
121 OUString(), OUString(), // will be late-initialized
122 !scriptURL.isEmpty() ? myBackend->m_xBasicLibTypeInfo
123 : myBackend->m_xDialogLibTypeInfo, bRemoved, identifier),
124 m_scriptURL( scriptURL ),
125 m_dialogURL( dialogURL )
126{
127 // name, displayName:
128 if (!dialogURL.isEmpty()) {
129 m_dialogName = LibraryContainer::get_libname(
130 dialogURL, xCmdEnv, myBackend->getComponentContext() );
131 }
132 if (!scriptURL.isEmpty()) {
133 assert(m_name.pData);
134 m_name = LibraryContainer::get_libname(
135 scriptURL, xCmdEnv, myBackend->getComponentContext() );
136 }
137 else
139 m_displayName = m_name;
140}
141
142
143BackendImpl::BackendImpl(
144 Sequence<Any> const & args,
145 Reference<XComponentContext> const & xComponentContext )
146 : t_helper( args, xComponentContext ),
147 m_xBasicLibTypeInfo( new Package::TypeInfo(
148 "application/vnd.sun.star.basic-library",
149 OUString() /* no file filter */,
150 DpResId(RID_STR_BASIC_LIB)
151 ) ),
152 m_xDialogLibTypeInfo( new Package::TypeInfo(
153 "application/vnd.sun.star.dialog-library",
154 OUString() /* no file filter */,
155 DpResId(RID_STR_DIALOG_LIB)
156 ) ),
158{
159 OSL_ASSERT( ! transientMode() );
160
161 if (!transientMode())
162 {
163 OUString dbFile = makeURL(getCachePath(), "backenddb.xml");
164 m_backendDb.reset(
165 new ScriptBackendDb(getComponentContext(), dbFile));
166 }
167
168}
169
170// XServiceInfo
171OUString BackendImpl::getImplementationName()
172{
173 return "com.sun.star.comp.deployment.script.PackageRegistryBackend";
174}
175
176sal_Bool BackendImpl::supportsService( const OUString& ServiceName )
177{
178 return cppu::supportsService(this, ServiceName);
179}
180
181css::uno::Sequence< OUString > BackendImpl::getSupportedServiceNames()
182{
183 return { BACKEND_SERVICE_NAME };
184}
185
186void BackendImpl::addDataToDb(OUString const & url)
187{
188 if (m_backendDb)
189 m_backendDb->addEntry(url);
190}
191
192bool BackendImpl::hasActiveEntry(std::u16string_view url)
193{
194 if (m_backendDb)
195 return m_backendDb->hasActiveEntry(url);
196 return false;
197}
198
199// XUpdatable
200
202{
203 // Nothing to do here after fixing i70283!?
204}
205
206// XPackageRegistry
207
208Sequence< Reference<deployment::XPackageTypeInfo> >
209BackendImpl::getSupportedPackageTypes()
210{
211 return m_typeInfos;
212}
213void BackendImpl::revokeEntryFromDb(std::u16string_view url)
214{
215 if (m_backendDb)
216 m_backendDb->revokeEntry(url);
217}
218
219void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
220{
221 if (m_backendDb)
222 m_backendDb->removeEntry(url);
223}
224
225// PackageRegistryBackend
226
227Reference<deployment::XPackage> BackendImpl::bindPackage_(
228 OUString const & url, OUString const & mediaType_,
229 bool bRemoved, OUString const & identifier,
230 Reference<XCommandEnvironment> const & xCmdEnv )
231{
232 OUString mediaType( mediaType_ );
233 if (mediaType.isEmpty())
234 {
235 // detect media-type:
236 ::ucbhelper::Content ucbContent;
237 if (create_ucb_content( &ucbContent, url, xCmdEnv ) &&
238 ucbContent.isFolder())
239 {
240 // probe for script.xlb:
242 nullptr, makeURL( url, "script.xlb" ),
243 xCmdEnv, false /* no throw */ ))
244 mediaType = "application/vnd.sun.star.basic-library";
245 // probe for dialog.xlb:
246 else if (create_ucb_content(
247 nullptr, makeURL( url, "dialog.xlb" ),
248 xCmdEnv, false /* no throw */ ))
249 mediaType = "application/vnd.sun.star.dialog-library";
250 }
251 if (mediaType.isEmpty())
252 throw lang::IllegalArgumentException(
253 StrCannotDetectMediaType() + url,
254 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
255 }
256
257 OUString type, subType;
259 if (INetContentTypes::parse( mediaType, type, subType, &params ))
260 {
261 if (type.equalsIgnoreAsciiCase("application"))
262 {
263 OUString dialogURL( makeURL( url, "dialog.xlb" ) );
264 if (! create_ucb_content(
265 nullptr, dialogURL, xCmdEnv, false /* no throw */ )) {
266 dialogURL.clear();
267 }
268
269 if (subType.equalsIgnoreAsciiCase("vnd.sun.star.basic-library"))
270 {
271 OUString scriptURL( makeURL( url, "script.xlb"));
272 if (! create_ucb_content(
273 nullptr, scriptURL, xCmdEnv, false /* no throw */ )) {
274 scriptURL.clear();
275 }
276
277 return new PackageImpl(
278 this, url, xCmdEnv, scriptURL,
279 dialogURL, bRemoved, identifier);
280 }
281 else if (subType.equalsIgnoreAsciiCase(
282 "vnd.sun.star.dialog-library")) {
283 return new PackageImpl(
284 this, url, xCmdEnv,
285 OUString() /* no script lib */,
286 dialogURL,
287 bRemoved, identifier);
288 }
289 }
290 }
291 throw lang::IllegalArgumentException(
292 StrUnsupportedMediaType() + mediaType,
293 static_cast<OWeakObject *>(this),
294 static_cast<sal_Int16>(-1) );
295}
296
297
298// Package
299BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
300{
301 BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
302 if (nullptr == pBackend)
303 {
304 //May throw a DisposedException
305 check();
306 //We should never get here...
307 throw RuntimeException(
308 "Failed to get the BackendImpl",
309 static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
310 }
311 return pBackend;
312}
313
314beans::Optional< beans::Ambiguous<sal_Bool> >
315BackendImpl::PackageImpl::isRegistered_(
316 ::osl::ResettableMutexGuard & /* guard */,
317 ::rtl::Reference<AbortChannel> const & /* abortChannel */,
318 Reference<XCommandEnvironment> const & /* xCmdEnv */ )
319{
320 BackendImpl * that = getMyBackend();
321 Reference< deployment::XPackage > xThisPackage( this );
322
323 bool registered = that->hasActiveEntry(getURL());
324 return beans::Optional< beans::Ambiguous<sal_Bool> >(
325 true /* IsPresent */,
326 beans::Ambiguous<sal_Bool>( registered, false /* IsAmbiguous */ ) );
327}
328
329void
330lcl_maybeRemoveScript(
331 bool const bExists,
332 OUString const& rName,
333 std::u16string_view rScriptURL,
334 Reference<css::script::XLibraryContainer3> const& xScriptLibs)
335{
336 if (bExists && xScriptLibs.is() && xScriptLibs->hasByName(rName))
337 {
338 const OUString sScriptUrl = xScriptLibs->getOriginalLibraryLinkURL(rName);
339 if (sScriptUrl == rScriptURL)
340 xScriptLibs->removeLibrary(rName);
341 }
342}
343
344bool
345lcl_maybeAddScript(
346 bool const bExists,
347 OUString const& rName,
348 OUString const& rScriptURL,
349 Reference<css::script::XLibraryContainer3> const& xScriptLibs)
350{
351 if (!bExists || !xScriptLibs)
352 return false;
353
354 bool bCanAdd = true;
355 if (xScriptLibs->hasByName(rName))
356 {
357 const OUString sOriginalUrl = xScriptLibs->getOriginalLibraryLinkURL(rName);
358 //We assume here that library names in extensions are unique, which may not be the case
359 //ToDo: If the script exist in another extension, then both extensions must have the
360 //same id
361 if (sOriginalUrl.match("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")
362 || sOriginalUrl.match("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")
363 || sOriginalUrl.match("vnd.sun.star.expand:$BUNDLED_EXTENSIONS")
364 || sOriginalUrl.match("$(INST)/share/basic/Access2Base/"))
365 {
366 xScriptLibs->removeLibrary(rName);
367 bCanAdd = true;
368 }
369 else
370 {
371 bCanAdd = false;
372 }
373 }
374
375 if (bCanAdd)
376 {
377 xScriptLibs->createLibraryLink(rName, rScriptURL, false);
378 return xScriptLibs->hasByName(rName);
379 }
380
381 return false;
382}
383
384void BackendImpl::PackageImpl::processPackage_(
385 ::osl::ResettableMutexGuard & /* guard */,
386 bool doRegisterPackage,
387 bool startup,
388 ::rtl::Reference<AbortChannel> const & /* abortChannel */,
389 Reference<XCommandEnvironment> const & /* xCmdEnv */ )
390{
391 BackendImpl * that = getMyBackend();
392
393 Reference< deployment::XPackage > xThisPackage( this );
394 Reference<XComponentContext> const & xComponentContext = that->getComponentContext();
395
396 bool bScript = !m_scriptURL.isEmpty();
397 Reference<css::script::XLibraryContainer3> xScriptLibs;
398
399 bool bDialog = !m_dialogURL.isEmpty();
400 Reference<css::script::XLibraryContainer3> xDialogLibs;
401
402 bool bRunning = !startup && office_is_running();
403 if( bRunning )
404 {
405 if( bScript )
406 {
407 xScriptLibs.set(
408 xComponentContext->getServiceManager()->createInstanceWithContext(
409 "com.sun.star.script.ApplicationScriptLibraryContainer",
410 xComponentContext ), UNO_QUERY_THROW );
411 }
412
413 if( bDialog )
414 {
415 xDialogLibs.set(
416 xComponentContext->getServiceManager()->createInstanceWithContext(
417 "com.sun.star.script.ApplicationDialogLibraryContainer",
418 xComponentContext ), UNO_QUERY_THROW );
419 }
420 }
421 bool bRegistered = getMyBackend()->hasActiveEntry(getURL());
422 if( !doRegisterPackage )
423 {
424 //We cannot just call removeLibrary(name) because this could remove a
425 //script which was added by an extension in a different repository. For
426 //example, extension foo is contained in the bundled repository and then
427 //the user adds it to the user repository. The extension manager will
428 //then register the new script and revoke the script from the bundled
429 //extension. removeLibrary(name) would now remove the script from the
430 //user repository. That is, the script of the newly added user extension does
431 //not work anymore. Therefore we must check if the currently active
432 //script comes in fact from the currently processed extension.
433
434 if (bRegistered)
435 {
436 //we also prevent and live deployment at startup
437 if (!isRemoved() && !startup)
438 {
439 lcl_maybeRemoveScript(bScript, m_name, m_scriptURL, xScriptLibs);
440 lcl_maybeRemoveScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs);
441 }
442 getMyBackend()->revokeEntryFromDb(getURL());
443 return;
444 }
445 }
446 if (bRegistered)
447 return; // Already registered
448
449 // Update LibraryContainer
450 bool bScriptSuccess = false;
451 bool bDialogSuccess = false;
452 if (!startup)
453 {
454 //If there is a bundled extension, and the user installs the same extension
455 //then the script from the bundled extension must be removed. If this does not work
456 //then live deployment does not work for scripts.
457 bScriptSuccess = lcl_maybeAddScript(bScript, m_name, m_scriptURL, xScriptLibs);
458 bDialogSuccess = lcl_maybeAddScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs);
459 }
460 bool bSuccess = bScript || bDialog; // Something must have happened
461 if( bRunning )
462 if( (bScript && !bScriptSuccess) || (bDialog && !bDialogSuccess) )
463 bSuccess = false;
464
465 if (bSuccess)
466 getMyBackend()->addDataToDb(getURL());
467}
468
469} // anon namespace
470
471} // namespace dp_registry::backend::script
472
473extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
475 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args)
476{
477 return cppu::acquire(new dp_registry::backend::script::BackendImpl(args, context));
478}
479
480/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool parse(OUString const &rMediaType, OUString &rType, OUString &rSubType, INetContentTypeParameterList *pParameters=nullptr)
OUString DpResId(TranslateId aId)
Definition: dp_misc.cxx:555
OUString m_dialogName
Definition: dp_script.cxx:56
const OUString m_dialogURL
Definition: dp_script.cxx:55
Sequence< Reference< deployment::XPackageTypeInfo > > m_typeInfos
Definition: dp_script.cxx:92
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_deployment_script_PackageRegistryBackend_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &args)
Definition: dp_script.cxx:474
const Reference< deployment::XPackageTypeInfo > m_xDialogLibTypeInfo
Definition: dp_script.cxx:91
std::unique_ptr< ScriptBackendDb > m_backendDb
Definition: dp_script.cxx:93
const OUString m_scriptURL
Definition: dp_script.cxx:54
const Reference< deployment::XPackageTypeInfo > m_xBasicLibTypeInfo
Definition: dp_script.cxx:90
std::unordered_map< OString, INetContentTypeParameter > INetContentTypeParameterList
OUString m_name
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
OUString makeURL(std::u16string_view baseURL, OUString const &relPath_)
appends a relative path to a url.
Definition: dp_misc.cxx:253
bool office_is_running()
Definition: dp_misc.cxx:331
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool create_ucb_content(::ucbhelper::Content *ucb_content, OUString const &url, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv, bool throw_exc=true)
constexpr OUStringLiteral BACKEND_SERVICE_NAME
Definition: dp_backend.h:41
::cppu::WeakImplHelper< css::script::provider::XScriptProvider, css::script::browse::XBrowseNode, css::lang::XServiceInfo, css::lang::XInitialization, css::container::XNameContainer > t_helper
def check(model)
args
::boost::spirit::classic::rule< ScannerT > identifier
unsigned char sal_Bool
ResultType type
bool update()
Definition: updater.cxx:286