| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_desktop.hxx" |
| |
| #include "dp_script.hrc" |
| #include "dp_lib_container.h" |
| #include "dp_backend.h" |
| #include "dp_ucb.h" |
| #include "rtl/uri.hxx" |
| #include "ucbhelper/content.hxx" |
| #include "cppuhelper/exc_hlp.hxx" |
| #include "cppuhelper/implbase1.hxx" |
| #include "comphelper/servicedecl.hxx" |
| #include "svl/inettype.hxx" |
| #include "com/sun/star/util/XUpdatable.hpp" |
| #include "com/sun/star/script/XLibraryContainer3.hpp" |
| #include <com/sun/star/ucb/XSimpleFileAccess.hpp> |
| #include <com/sun/star/util/XMacroExpander.hpp> |
| #include <com/sun/star/uri/XUriReferenceFactory.hpp> |
| #include <memory> |
| #include "dp_scriptbackenddb.hxx" |
| |
| using namespace ::dp_misc; |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::ucb; |
| using ::rtl::OUString; |
| namespace css = ::com::sun::star; |
| |
| namespace dp_registry { |
| namespace backend { |
| namespace script { |
| namespace { |
| |
| typedef ::cppu::ImplInheritanceHelper1< |
| ::dp_registry::backend::PackageRegistryBackend, util::XUpdatable > t_helper; |
| |
| //============================================================================== |
| class BackendImpl : public t_helper |
| { |
| class PackageImpl : public ::dp_registry::backend::Package |
| { |
| BackendImpl * getMyBackend() const; |
| |
| const OUString m_scriptURL; |
| const OUString m_dialogURL; |
| OUString m_dialogName; |
| |
| // Package |
| virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( |
| ::osl::ResettableMutexGuard & guard, |
| ::rtl::Reference<AbortChannel> const & abortChannel, |
| Reference<XCommandEnvironment> const & xCmdEnv ); |
| virtual void processPackage_( |
| ::osl::ResettableMutexGuard & guard, |
| bool registerPackage, |
| bool startup, |
| ::rtl::Reference<AbortChannel> const & abortChannel, |
| Reference<XCommandEnvironment> const & xCmdEnv ); |
| |
| public: |
| PackageImpl( |
| ::rtl::Reference<BackendImpl> const & myBackend, |
| OUString const & url, |
| Reference<XCommandEnvironment> const &xCmdEnv, |
| OUString const & scriptURL, OUString const & dialogURL, |
| bool bRemoved, OUString const & identifier); |
| }; |
| friend class PackageImpl; |
| |
| // PackageRegistryBackend |
| virtual Reference<deployment::XPackage> bindPackage_( |
| OUString const & url, OUString const & mediaType, |
| sal_Bool bRemoved, OUString const & identifier, |
| Reference<XCommandEnvironment> const & xCmdEnv ); |
| |
| void addDataToDb(OUString const & url); |
| bool hasActiveEntry(OUString const & url); |
| void revokeEntryFromDb(OUString const & url); |
| |
| const Reference<deployment::XPackageTypeInfo> m_xBasicLibTypeInfo; |
| const Reference<deployment::XPackageTypeInfo> m_xDialogLibTypeInfo; |
| Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; |
| std::auto_ptr<ScriptBackendDb> m_backendDb; |
| public: |
| BackendImpl( Sequence<Any> const & args, |
| Reference<XComponentContext> const & xComponentContext ); |
| |
| // XUpdatable |
| virtual void SAL_CALL update() throw (RuntimeException); |
| |
| // XPackageRegistry |
| virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL |
| getSupportedPackageTypes() throw (RuntimeException); |
| virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType) |
| throw (deployment::DeploymentException, |
| uno::RuntimeException); |
| |
| }; |
| |
| //______________________________________________________________________________ |
| BackendImpl::PackageImpl::PackageImpl( |
| ::rtl::Reference<BackendImpl> const & myBackend, |
| OUString const & url, |
| Reference<XCommandEnvironment> const &xCmdEnv, |
| OUString const & scriptURL, OUString const & dialogURL, bool bRemoved, |
| OUString const & identifier) |
| : Package( myBackend.get(), url, |
| OUString(), OUString(), // will be late-initialized |
| scriptURL.getLength() > 0 ? myBackend->m_xBasicLibTypeInfo |
| : myBackend->m_xDialogLibTypeInfo, bRemoved, identifier), |
| m_scriptURL( scriptURL ), |
| m_dialogURL( dialogURL ) |
| { |
| // name, displayName: |
| if (dialogURL.getLength() > 0) { |
| m_dialogName = LibraryContainer::get_libname( |
| dialogURL, xCmdEnv, myBackend->getComponentContext() ); |
| } |
| if (scriptURL.getLength() > 0) { |
| m_name = LibraryContainer::get_libname( |
| scriptURL, xCmdEnv, myBackend->getComponentContext() ); |
| } |
| else |
| m_name = m_dialogName; |
| m_displayName = m_name; |
| } |
| |
| //______________________________________________________________________________ |
| BackendImpl::BackendImpl( |
| Sequence<Any> const & args, |
| Reference<XComponentContext> const & xComponentContext ) |
| : t_helper( args, xComponentContext ), |
| m_xBasicLibTypeInfo( new Package::TypeInfo( |
| OUSTR("application/" |
| "vnd.sun.star.basic-library"), |
| OUString() /* no file filter */, |
| getResourceString(RID_STR_BASIC_LIB), |
| RID_IMG_SCRIPTLIB, RID_IMG_SCRIPTLIB_HC ) ), |
| m_xDialogLibTypeInfo( new Package::TypeInfo( |
| OUSTR("application/" |
| "vnd.sun.star.dialog-library"), |
| OUString() /* no file filter */, |
| getResourceString(RID_STR_DIALOG_LIB), |
| RID_IMG_DIALOGLIB, RID_IMG_DIALOGLIB_HC ) ), |
| m_typeInfos( 2 ) |
| { |
| m_typeInfos[ 0 ] = m_xBasicLibTypeInfo; |
| m_typeInfos[ 1 ] = m_xDialogLibTypeInfo; |
| |
| OSL_ASSERT( ! transientMode() ); |
| |
| if (!transientMode()) |
| { |
| OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); |
| m_backendDb.reset( |
| new ScriptBackendDb(getComponentContext(), dbFile)); |
| } |
| |
| } |
| void BackendImpl::addDataToDb(OUString const & url) |
| { |
| if (m_backendDb.get()) |
| m_backendDb->addEntry(url); |
| } |
| |
| bool BackendImpl::hasActiveEntry(OUString const & url) |
| { |
| if (m_backendDb.get()) |
| return m_backendDb->hasActiveEntry(url); |
| return false; |
| } |
| |
| // XUpdatable |
| //______________________________________________________________________________ |
| void BackendImpl::update() throw (RuntimeException) |
| { |
| // Nothing to do here after fixing i70283!? |
| } |
| |
| // XPackageRegistry |
| //______________________________________________________________________________ |
| Sequence< Reference<deployment::XPackageTypeInfo> > |
| BackendImpl::getSupportedPackageTypes() throw (RuntimeException) |
| { |
| return m_typeInfos; |
| } |
| void BackendImpl::revokeEntryFromDb(OUString const & url) |
| { |
| if (m_backendDb.get()) |
| m_backendDb->revokeEntry(url); |
| } |
| |
| void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/) |
| throw (deployment::DeploymentException, |
| uno::RuntimeException) |
| { |
| if (m_backendDb.get()) |
| m_backendDb->removeEntry(url); |
| } |
| |
| // PackageRegistryBackend |
| //______________________________________________________________________________ |
| Reference<deployment::XPackage> BackendImpl::bindPackage_( |
| OUString const & url, OUString const & mediaType_, |
| sal_Bool bRemoved, OUString const & identifier, |
| Reference<XCommandEnvironment> const & xCmdEnv ) |
| { |
| OUString mediaType( mediaType_ ); |
| if (mediaType.getLength() == 0) |
| { |
| // detect media-type: |
| ::ucbhelper::Content ucbContent; |
| if (create_ucb_content( &ucbContent, url, xCmdEnv ) && |
| ucbContent.isFolder()) |
| { |
| // probe for script.xlb: |
| if (create_ucb_content( |
| 0, makeURL( url, OUSTR("script.xlb") ), |
| xCmdEnv, false /* no throw */ )) |
| mediaType = OUSTR("application/vnd.sun.star.basic-library"); |
| // probe for dialog.xlb: |
| else if (create_ucb_content( |
| 0, makeURL( url, OUSTR("dialog.xlb") ), |
| xCmdEnv, false /* no throw */ )) |
| mediaType = OUSTR("application/vnd.sun.star.dialog-library"); |
| } |
| if (mediaType.getLength() == 0) |
| throw lang::IllegalArgumentException( |
| StrCannotDetectMediaType::get() + url, |
| static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); |
| } |
| |
| String type, subType; |
| INetContentTypeParameterList params; |
| if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) |
| { |
| if (type.EqualsIgnoreCaseAscii("application")) |
| { |
| OUString dialogURL( makeURL( url, OUSTR("dialog.xlb") ) ); |
| if (! create_ucb_content( |
| 0, dialogURL, xCmdEnv, false /* no throw */ )) { |
| dialogURL = OUString(); |
| } |
| |
| if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.basic-library")) |
| { |
| OUString scriptURL( makeURL( url, OUSTR("script.xlb"))); |
| if (! create_ucb_content( |
| 0, scriptURL, xCmdEnv, false /* no throw */ )) { |
| scriptURL = OUString(); |
| } |
| |
| return new PackageImpl( |
| this, url, xCmdEnv, scriptURL, |
| dialogURL, bRemoved, identifier); |
| } |
| else if (subType.EqualsIgnoreCaseAscii( |
| "vnd.sun.star.dialog-library")) { |
| return new PackageImpl( |
| this, url, xCmdEnv, |
| OUString() /* no script lib */, |
| dialogURL, |
| bRemoved, identifier); |
| } |
| } |
| } |
| throw lang::IllegalArgumentException( |
| StrUnsupportedMediaType::get() + mediaType, |
| static_cast<OWeakObject *>(this), |
| static_cast<sal_Int16>(-1) ); |
| } |
| |
| //############################################################################## |
| |
| // Package |
| BackendImpl * BackendImpl::PackageImpl::getMyBackend() const |
| { |
| BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); |
| if (NULL == pBackend) |
| { |
| //May throw a DisposedException |
| check(); |
| //We should never get here... |
| throw RuntimeException( |
| OUSTR("Failed to get the BackendImpl"), |
| static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); |
| } |
| return pBackend; |
| } |
| //______________________________________________________________________________ |
| beans::Optional< beans::Ambiguous<sal_Bool> > |
| BackendImpl::PackageImpl::isRegistered_( |
| ::osl::ResettableMutexGuard &, |
| ::rtl::Reference<AbortChannel> const &, |
| Reference<XCommandEnvironment> const & xCmdEnv ) |
| { |
| (void)xCmdEnv; |
| |
| BackendImpl * that = getMyBackend(); |
| Reference< deployment::XPackage > xThisPackage( this ); |
| |
| bool registered = that->hasActiveEntry(getURL()); |
| return beans::Optional< beans::Ambiguous<sal_Bool> >( |
| true /* IsPresent */, |
| beans::Ambiguous<sal_Bool>( registered, false /* IsAmbiguous */ ) ); |
| } |
| |
| //______________________________________________________________________________ |
| void BackendImpl::PackageImpl::processPackage_( |
| ::osl::ResettableMutexGuard &, |
| bool doRegisterPackage, |
| bool startup, |
| ::rtl::Reference<AbortChannel> const &, |
| Reference<XCommandEnvironment> const & xCmdEnv ) |
| { |
| (void)xCmdEnv; |
| |
| BackendImpl * that = getMyBackend(); |
| |
| Reference< deployment::XPackage > xThisPackage( this ); |
| Reference<XComponentContext> const & xComponentContext = that->getComponentContext(); |
| |
| bool bScript = (m_scriptURL.getLength() > 0); |
| Reference<css::script::XLibraryContainer3> xScriptLibs; |
| |
| bool bDialog = (m_dialogURL.getLength() > 0); |
| Reference<css::script::XLibraryContainer3> xDialogLibs; |
| |
| bool bRunning = office_is_running(); |
| if( bRunning ) |
| { |
| if( bScript ) |
| { |
| xScriptLibs.set( |
| xComponentContext->getServiceManager()->createInstanceWithContext( |
| OUSTR("com.sun.star.script.ApplicationScriptLibraryContainer"), |
| xComponentContext ), UNO_QUERY_THROW ); |
| } |
| |
| if( bDialog ) |
| { |
| xDialogLibs.set( |
| xComponentContext->getServiceManager()->createInstanceWithContext( |
| OUSTR("com.sun.star.script.ApplicationDialogLibraryContainer"), |
| xComponentContext ), UNO_QUERY_THROW ); |
| } |
| } |
| bool bRegistered = getMyBackend()->hasActiveEntry(getURL()); |
| if( !doRegisterPackage ) |
| { |
| //We cannot just call removeLibrary(name) because this could remove a |
| //script which was added by an extension in a different repository. For |
| //example, extension foo is contained in the bundled repository and then |
| //the user adds it it to the user repository. The extension manager will |
| //then register the new script and revoke the script from the bundled |
| //extension. removeLibrary(name) would now remove the script from the |
| //user repository. That is, the script of the newly added user extension does |
| //not work anymore. Therefore we must check if the currently active |
| //script comes in fact from the currently processed extension. |
| |
| if (bRegistered) |
| { |
| //we also prevent and live deployment at startup |
| if (!isRemoved() && !startup) |
| { |
| if (bScript && xScriptLibs.is() && xScriptLibs->hasByName(m_name)) |
| { |
| const OUString sScriptUrl = xScriptLibs->getOriginalLibraryLinkURL(m_name); |
| if (sScriptUrl.equals(m_scriptURL)) |
| xScriptLibs->removeLibrary(m_name); |
| } |
| |
| if (bDialog && xDialogLibs.is() && xDialogLibs->hasByName(m_dialogName)) |
| { |
| const OUString sDialogUrl = xDialogLibs->getOriginalLibraryLinkURL(m_dialogName); |
| if (sDialogUrl.equals(m_dialogURL)) |
| xDialogLibs->removeLibrary(m_dialogName); |
| } |
| } |
| getMyBackend()->revokeEntryFromDb(getURL()); |
| return; |
| } |
| } |
| if (bRegistered) |
| return; // Already registered |
| |
| // Update LibraryContainer |
| bool bScriptSuccess = false; |
| const bool bReadOnly = false; |
| |
| bool bDialogSuccess = false; |
| if (!startup) |
| { |
| //If there is a bundled extension, and the user installes the same extension |
| //then the script from the bundled extension must be removed. If this does not work |
| //then live deployment does not work for scripts. |
| if (bScript && xScriptLibs.is()) |
| { |
| bool bCanAdd = true; |
| if (xScriptLibs->hasByName(m_name)) |
| { |
| const OUString sOriginalUrl = xScriptLibs->getOriginalLibraryLinkURL(m_name); |
| //We assume here that library names in extensions are unique, which may not be the case |
| //ToDo: If the script exist in another extension, then both extensions must have the |
| //same id |
| if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")) |
| || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")) |
| || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS"))) |
| { |
| xScriptLibs->removeLibrary(m_name); |
| bCanAdd = true; |
| } |
| else |
| { |
| bCanAdd = false; |
| } |
| } |
| |
| if (bCanAdd) |
| { |
| xScriptLibs->createLibraryLink( m_name, m_scriptURL, bReadOnly ); |
| bScriptSuccess = xScriptLibs->hasByName( m_name ); |
| } |
| } |
| |
| |
| if (bDialog && xDialogLibs.is()) |
| { |
| bool bCanAdd = true; |
| if (xDialogLibs->hasByName(m_dialogName)) |
| { |
| const OUString sOriginalUrl = xDialogLibs->getOriginalLibraryLinkURL(m_dialogName); |
| //We assume here that library names in extensions are unique, which may not be the case |
| //ToDo: If the script exist in another extension, then both extensions must have the |
| //same id |
| if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")) |
| || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")) |
| || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS"))) |
| { |
| xDialogLibs->removeLibrary(m_dialogName); |
| bCanAdd = true; |
| } |
| else |
| { |
| bCanAdd = false; |
| } |
| } |
| |
| if (bCanAdd) |
| { |
| xDialogLibs->createLibraryLink( m_dialogName, m_dialogURL, bReadOnly ); |
| bDialogSuccess = xDialogLibs->hasByName(m_dialogName); |
| } |
| } |
| } |
| bool bSuccess = bScript || bDialog; // Something must have happened |
| if( bRunning && !startup) |
| if( (bScript && !bScriptSuccess) || (bDialog && !bDialogSuccess) ) |
| bSuccess = false; |
| |
| if (bSuccess) |
| getMyBackend()->addDataToDb(getURL()); |
| } |
| |
| } // anon namespace |
| |
| namespace sdecl = comphelper::service_decl; |
| sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; |
| extern sdecl::ServiceDecl const serviceDecl( |
| serviceBI, |
| "com.sun.star.comp.deployment.script.PackageRegistryBackend", |
| BACKEND_SERVICE_NAME ); |
| |
| } // namespace script |
| } // namespace backend |
| } // namespace dp_registry |
| |