/************************************************************** * * 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 #include #include #include #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 > isRegistered_( ::osl::ResettableMutexGuard & guard, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ); virtual void processPackage_( ::osl::ResettableMutexGuard & guard, bool registerPackage, bool startup, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ); public: PackageImpl( ::rtl::Reference const & myBackend, OUString const & url, Reference const &xCmdEnv, OUString const & scriptURL, OUString const & dialogURL, bool bRemoved, OUString const & identifier); }; friend class PackageImpl; // PackageRegistryBackend virtual Reference bindPackage_( OUString const & url, OUString const & mediaType, sal_Bool bRemoved, OUString const & identifier, Reference const & xCmdEnv ); void addDataToDb(OUString const & url); bool hasActiveEntry(OUString const & url); void revokeEntryFromDb(OUString const & url); const Reference m_xBasicLibTypeInfo; const Reference m_xDialogLibTypeInfo; Sequence< Reference > m_typeInfos; std::auto_ptr m_backendDb; public: BackendImpl( Sequence const & args, Reference const & xComponentContext ); // XUpdatable virtual void SAL_CALL update() throw (RuntimeException); // XPackageRegistry virtual Sequence< Reference > 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 const & myBackend, OUString const & url, Reference 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 const & args, Reference 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 > 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 BackendImpl::bindPackage_( OUString const & url, OUString const & mediaType_, sal_Bool bRemoved, OUString const & identifier, Reference 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(this), static_cast(-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(this), static_cast(-1) ); } //############################################################################## // Package BackendImpl * BackendImpl::PackageImpl::getMyBackend() const { BackendImpl * pBackend = static_cast(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(const_cast(this))); } return pBackend; } //______________________________________________________________________________ beans::Optional< beans::Ambiguous > BackendImpl::PackageImpl::isRegistered_( ::osl::ResettableMutexGuard &, ::rtl::Reference const &, Reference const & xCmdEnv ) { (void)xCmdEnv; BackendImpl * that = getMyBackend(); Reference< deployment::XPackage > xThisPackage( this ); bool registered = that->hasActiveEntry(getURL()); return beans::Optional< beans::Ambiguous >( true /* IsPresent */, beans::Ambiguous( registered, false /* IsAmbiguous */ ) ); } //______________________________________________________________________________ void BackendImpl::PackageImpl::processPackage_( ::osl::ResettableMutexGuard &, bool doRegisterPackage, bool startup, ::rtl::Reference const &, Reference const & xCmdEnv ) { (void)xCmdEnv; BackendImpl * that = getMyBackend(); Reference< deployment::XPackage > xThisPackage( this ); Reference const & xComponentContext = that->getComponentContext(); bool bScript = (m_scriptURL.getLength() > 0); Reference xScriptLibs; bool bDialog = (m_dialogURL.getLength() > 0); Reference 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_ > serviceBI; extern sdecl::ServiceDecl const serviceDecl( serviceBI, "com.sun.star.comp.deployment.script.PackageRegistryBackend", BACKEND_SERVICE_NAME ); } // namespace script } // namespace backend } // namespace dp_registry