Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / desktop / source / deployment / registry / script / dp_script.cxx
bloba6c56bd81969c698617d628f5d214b4f058536cd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <strings.hrc>
22 #include <dp_services.hxx>
23 #include "dp_lib_container.h"
24 #include <dp_backend.h>
25 #include <dp_ucb.h>
26 #include <rtl/uri.hxx>
27 #include <ucbhelper/content.hxx>
28 #include <cppuhelper/exc_hlp.hxx>
29 #include <cppuhelper/implbase.hxx>
30 #include <comphelper/servicedecl.hxx>
31 #include <svl/inettype.hxx>
32 #include <com/sun/star/util/XUpdatable.hpp>
33 #include <com/sun/star/script/XLibraryContainer3.hpp>
34 #include <com/sun/star/util/XMacroExpander.hpp>
35 #include <memory>
36 #include "dp_scriptbackenddb.hxx"
38 using namespace ::dp_misc;
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::ucb;
43 namespace dp_registry {
44 namespace backend {
45 namespace script {
46 namespace {
48 typedef ::cppu::ImplInheritanceHelper<
49 ::dp_registry::backend::PackageRegistryBackend, util::XUpdatable > t_helper;
51 class BackendImpl : public t_helper
53 class PackageImpl : public ::dp_registry::backend::Package
55 BackendImpl * getMyBackend() const;
57 const OUString m_scriptURL;
58 const OUString m_dialogURL;
59 OUString m_dialogName;
61 // Package
62 virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
63 ::osl::ResettableMutexGuard & guard,
64 ::rtl::Reference<AbortChannel> const & abortChannel,
65 Reference<XCommandEnvironment> const & xCmdEnv ) override;
66 virtual void processPackage_(
67 ::osl::ResettableMutexGuard & guard,
68 bool registerPackage,
69 bool startup,
70 ::rtl::Reference<AbortChannel> const & abortChannel,
71 Reference<XCommandEnvironment> const & xCmdEnv ) override;
73 public:
74 PackageImpl(
75 ::rtl::Reference<BackendImpl> const & myBackend,
76 OUString const & url,
77 Reference<XCommandEnvironment> const &xCmdEnv,
78 OUString const & scriptURL, OUString const & dialogURL,
79 bool bRemoved, OUString const & identifier);
81 friend class PackageImpl;
83 // PackageRegistryBackend
84 virtual Reference<deployment::XPackage> bindPackage_(
85 OUString const & url, OUString const & mediaType,
86 bool bRemoved, OUString const & identifier,
87 Reference<XCommandEnvironment> const & xCmdEnv ) override;
89 void addDataToDb(OUString const & url);
90 bool hasActiveEntry(OUString const & url);
91 void revokeEntryFromDb(OUString const & url);
93 const Reference<deployment::XPackageTypeInfo> m_xBasicLibTypeInfo;
94 const Reference<deployment::XPackageTypeInfo> m_xDialogLibTypeInfo;
95 Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
96 std::unique_ptr<ScriptBackendDb> m_backendDb;
97 public:
98 BackendImpl( Sequence<Any> const & args,
99 Reference<XComponentContext> const & xComponentContext );
101 // XUpdatable
102 virtual void SAL_CALL update() override;
104 // XPackageRegistry
105 virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
106 getSupportedPackageTypes() override;
107 virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType) override;
112 BackendImpl::PackageImpl::PackageImpl(
113 ::rtl::Reference<BackendImpl> const & myBackend,
114 OUString const & url,
115 Reference<XCommandEnvironment> const &xCmdEnv,
116 OUString const & scriptURL, OUString const & dialogURL, bool bRemoved,
117 OUString const & identifier)
118 : Package( myBackend.get(), url,
119 OUString(), OUString(), // will be late-initialized
120 !scriptURL.isEmpty() ? myBackend->m_xBasicLibTypeInfo
121 : myBackend->m_xDialogLibTypeInfo, bRemoved, identifier),
122 m_scriptURL( scriptURL ),
123 m_dialogURL( dialogURL )
125 // name, displayName:
126 if (!dialogURL.isEmpty()) {
127 m_dialogName = LibraryContainer::get_libname(
128 dialogURL, xCmdEnv, myBackend->getComponentContext() );
130 if (!scriptURL.isEmpty()) {
131 assert(m_name.pData);
132 m_name = LibraryContainer::get_libname(
133 scriptURL, xCmdEnv, myBackend->getComponentContext() );
135 else
136 m_name = m_dialogName;
137 m_displayName = m_name;
141 BackendImpl::BackendImpl(
142 Sequence<Any> const & args,
143 Reference<XComponentContext> const & xComponentContext )
144 : t_helper( args, xComponentContext ),
145 m_xBasicLibTypeInfo( new Package::TypeInfo(
146 "application/vnd.sun.star.basic-library",
147 OUString() /* no file filter */,
148 DpResId(RID_STR_BASIC_LIB)
149 ) ),
150 m_xDialogLibTypeInfo( new Package::TypeInfo(
151 "application/vnd.sun.star.dialog-library",
152 OUString() /* no file filter */,
153 DpResId(RID_STR_DIALOG_LIB)
154 ) ),
155 m_typeInfos( 2 )
157 m_typeInfos[ 0 ] = m_xBasicLibTypeInfo;
158 m_typeInfos[ 1 ] = m_xDialogLibTypeInfo;
160 OSL_ASSERT( ! transientMode() );
162 if (!transientMode())
164 OUString dbFile = makeURL(getCachePath(), "backenddb.xml");
165 m_backendDb.reset(
166 new ScriptBackendDb(getComponentContext(), dbFile));
170 void BackendImpl::addDataToDb(OUString const & url)
172 if (m_backendDb)
173 m_backendDb->addEntry(url);
176 bool BackendImpl::hasActiveEntry(OUString const & url)
178 if (m_backendDb)
179 return m_backendDb->hasActiveEntry(url);
180 return false;
183 // XUpdatable
185 void BackendImpl::update()
187 // Nothing to do here after fixing i70283!?
190 // XPackageRegistry
192 Sequence< Reference<deployment::XPackageTypeInfo> >
193 BackendImpl::getSupportedPackageTypes()
195 return m_typeInfos;
197 void BackendImpl::revokeEntryFromDb(OUString const & url)
199 if (m_backendDb)
200 m_backendDb->revokeEntry(url);
203 void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
205 if (m_backendDb)
206 m_backendDb->removeEntry(url);
209 // PackageRegistryBackend
211 Reference<deployment::XPackage> BackendImpl::bindPackage_(
212 OUString const & url, OUString const & mediaType_,
213 bool bRemoved, OUString const & identifier,
214 Reference<XCommandEnvironment> const & xCmdEnv )
216 OUString mediaType( mediaType_ );
217 if (mediaType.isEmpty())
219 // detect media-type:
220 ::ucbhelper::Content ucbContent;
221 if (create_ucb_content( &ucbContent, url, xCmdEnv ) &&
222 ucbContent.isFolder())
224 // probe for script.xlb:
225 if (create_ucb_content(
226 nullptr, makeURL( url, "script.xlb" ),
227 xCmdEnv, false /* no throw */ ))
228 mediaType = "application/vnd.sun.star.basic-library";
229 // probe for dialog.xlb:
230 else if (create_ucb_content(
231 nullptr, makeURL( url, "dialog.xlb" ),
232 xCmdEnv, false /* no throw */ ))
233 mediaType = "application/vnd.sun.star.dialog-library";
235 if (mediaType.isEmpty())
236 throw lang::IllegalArgumentException(
237 StrCannotDetectMediaType() + url,
238 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
241 OUString type, subType;
242 INetContentTypeParameterList params;
243 if (INetContentTypes::parse( mediaType, type, subType, &params ))
245 if (type.equalsIgnoreAsciiCase("application"))
247 OUString dialogURL( makeURL( url, "dialog.xlb" ) );
248 if (! create_ucb_content(
249 nullptr, dialogURL, xCmdEnv, false /* no throw */ )) {
250 dialogURL.clear();
253 if (subType.equalsIgnoreAsciiCase("vnd.sun.star.basic-library"))
255 OUString scriptURL( makeURL( url, "script.xlb"));
256 if (! create_ucb_content(
257 nullptr, scriptURL, xCmdEnv, false /* no throw */ )) {
258 scriptURL.clear();
261 return new PackageImpl(
262 this, url, xCmdEnv, scriptURL,
263 dialogURL, bRemoved, identifier);
265 else if (subType.equalsIgnoreAsciiCase(
266 "vnd.sun.star.dialog-library")) {
267 return new PackageImpl(
268 this, url, xCmdEnv,
269 OUString() /* no script lib */,
270 dialogURL,
271 bRemoved, identifier);
275 throw lang::IllegalArgumentException(
276 StrUnsupportedMediaType() + mediaType,
277 static_cast<OWeakObject *>(this),
278 static_cast<sal_Int16>(-1) );
282 // Package
283 BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
285 BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
286 if (nullptr == pBackend)
288 //May throw a DisposedException
289 check();
290 //We should never get here...
291 throw RuntimeException(
292 "Failed to get the BackendImpl",
293 static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
295 return pBackend;
298 beans::Optional< beans::Ambiguous<sal_Bool> >
299 BackendImpl::PackageImpl::isRegistered_(
300 ::osl::ResettableMutexGuard & /* guard */,
301 ::rtl::Reference<AbortChannel> const & /* abortChannel */,
302 Reference<XCommandEnvironment> const & /* xCmdEnv */ )
304 BackendImpl * that = getMyBackend();
305 Reference< deployment::XPackage > xThisPackage( this );
307 bool registered = that->hasActiveEntry(getURL());
308 return beans::Optional< beans::Ambiguous<sal_Bool> >(
309 true /* IsPresent */,
310 beans::Ambiguous<sal_Bool>( registered, false /* IsAmbiguous */ ) );
313 void
314 lcl_maybeRemoveScript(
315 bool const bExists,
316 OUString const& rName,
317 OUString const& rScriptURL,
318 Reference<css::script::XLibraryContainer3> const& xScriptLibs)
320 if (bExists && xScriptLibs.is() && xScriptLibs->hasByName(rName))
322 const OUString sScriptUrl = xScriptLibs->getOriginalLibraryLinkURL(rName);
323 if (sScriptUrl == rScriptURL)
324 xScriptLibs->removeLibrary(rName);
328 bool
329 lcl_maybeAddScript(
330 bool const bExists,
331 OUString const& rName,
332 OUString const& rScriptURL,
333 Reference<css::script::XLibraryContainer3> const& xScriptLibs)
335 if (bExists && xScriptLibs.is())
337 bool bCanAdd = true;
338 if (xScriptLibs->hasByName(rName))
340 const OUString sOriginalUrl = xScriptLibs->getOriginalLibraryLinkURL(rName);
341 //We assume here that library names in extensions are unique, which may not be the case
342 //ToDo: If the script exist in another extension, then both extensions must have the
343 //same id
344 if (sOriginalUrl.match("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")
345 || sOriginalUrl.match("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")
346 || sOriginalUrl.match("vnd.sun.star.expand:$BUNDLED_EXTENSIONS")
347 || sOriginalUrl.match("$(INST)/share/basic/Access2Base/"))
349 xScriptLibs->removeLibrary(rName);
350 bCanAdd = true;
352 else
354 bCanAdd = false;
358 if (bCanAdd)
360 xScriptLibs->createLibraryLink(rName, rScriptURL, false);
361 return xScriptLibs->hasByName(rName);
365 return false;
368 void BackendImpl::PackageImpl::processPackage_(
369 ::osl::ResettableMutexGuard & /* guard */,
370 bool doRegisterPackage,
371 bool startup,
372 ::rtl::Reference<AbortChannel> const & /* abortChannel */,
373 Reference<XCommandEnvironment> const & /* xCmdEnv */ )
375 BackendImpl * that = getMyBackend();
377 Reference< deployment::XPackage > xThisPackage( this );
378 Reference<XComponentContext> const & xComponentContext = that->getComponentContext();
380 bool bScript = !m_scriptURL.isEmpty();
381 Reference<css::script::XLibraryContainer3> xScriptLibs;
383 bool bDialog = !m_dialogURL.isEmpty();
384 Reference<css::script::XLibraryContainer3> xDialogLibs;
386 bool bRunning = !startup && office_is_running();
387 if( bRunning )
389 if( bScript )
391 xScriptLibs.set(
392 xComponentContext->getServiceManager()->createInstanceWithContext(
393 "com.sun.star.script.ApplicationScriptLibraryContainer",
394 xComponentContext ), UNO_QUERY_THROW );
397 if( bDialog )
399 xDialogLibs.set(
400 xComponentContext->getServiceManager()->createInstanceWithContext(
401 "com.sun.star.script.ApplicationDialogLibraryContainer",
402 xComponentContext ), UNO_QUERY_THROW );
405 bool bRegistered = getMyBackend()->hasActiveEntry(getURL());
406 if( !doRegisterPackage )
408 //We cannot just call removeLibrary(name) because this could remove a
409 //script which was added by an extension in a different repository. For
410 //example, extension foo is contained in the bundled repository and then
411 //the user adds it to the user repository. The extension manager will
412 //then register the new script and revoke the script from the bundled
413 //extension. removeLibrary(name) would now remove the script from the
414 //user repository. That is, the script of the newly added user extension does
415 //not work anymore. Therefore we must check if the currently active
416 //script comes in fact from the currently processed extension.
418 if (bRegistered)
420 //we also prevent and live deployment at startup
421 if (!isRemoved() && !startup)
423 lcl_maybeRemoveScript(bScript, m_name, m_scriptURL, xScriptLibs);
424 lcl_maybeRemoveScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs);
426 getMyBackend()->revokeEntryFromDb(getURL());
427 return;
430 if (bRegistered)
431 return; // Already registered
433 // Update LibraryContainer
434 bool bScriptSuccess = false;
435 bool bDialogSuccess = false;
436 if (!startup)
438 //If there is a bundled extension, and the user installs the same extension
439 //then the script from the bundled extension must be removed. If this does not work
440 //then live deployment does not work for scripts.
441 bScriptSuccess = lcl_maybeAddScript(bScript, m_name, m_scriptURL, xScriptLibs);
442 bDialogSuccess = lcl_maybeAddScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs);
444 bool bSuccess = bScript || bDialog; // Something must have happened
445 if( bRunning )
446 if( (bScript && !bScriptSuccess) || (bDialog && !bDialogSuccess) )
447 bSuccess = false;
449 if (bSuccess)
450 getMyBackend()->addDataToDb(getURL());
453 } // anon namespace
455 namespace sdecl = comphelper::service_decl;
456 sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
457 sdecl::ServiceDecl const serviceDecl(
458 serviceBI,
459 "com.sun.star.comp.deployment.script.PackageRegistryBackend",
460 BACKEND_SERVICE_NAME );
462 } // namespace script
463 } // namespace backend
464 } // namespace dp_registry
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */