diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /uui/source/iahndl.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'uui/source/iahndl.cxx')
-rw-r--r-- | uui/source/iahndl.cxx | 1240 |
1 files changed, 1240 insertions, 0 deletions
diff --git a/uui/source/iahndl.cxx b/uui/source/iahndl.cxx new file mode 100644 index 000000000..a704baf13 --- /dev/null +++ b/uui/source/iahndl.cxx @@ -0,0 +1,1240 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <memory> + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/configuration/backend/MergeRecoveryRequest.hpp> +#include <com/sun/star/configuration/backend/StratumCreationException.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/document/BrokenPackageRequest.hpp> +#include <com/sun/star/document/ExoticFileLoadException.hpp> +#include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp> +#include <com/sun/star/java/WrongJavaVersionException.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/script/ModuleSizeExceededRequest.hpp> +#include <com/sun/star/task/ErrorCodeIOException.hpp> +#include <com/sun/star/task/ErrorCodeRequest.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/task/XInteractionApprove.hpp> +#include <com/sun/star/task/XInteractionDisapprove.hpp> +#include <com/sun/star/task/XInteractionHandler2.hpp> +#include <com/sun/star/task/XInteractionRequest.hpp> +#include <com/sun/star/ucb/AuthenticationFallbackRequest.hpp> +#include <com/sun/star/ucb/InteractiveAppException.hpp> +#include <com/sun/star/ucb/InteractiveLockingLockedException.hpp> +#include <com/sun/star/ucb/InteractiveLockingNotLockedException.hpp> +#include <com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp> +#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp> +#include <com/sun/star/ucb/InteractiveNetworkOffLineException.hpp> +#include <com/sun/star/ucb/InteractiveNetworkReadException.hpp> +#include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp> +#include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp> +#include <com/sun/star/ucb/InteractiveWrongMediumException.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/ucb/NameClashResolveRequest.hpp> +#include <com/sun/star/ucb/UnsupportedNameClashException.hpp> +#include <com/sun/star/ucb/XInteractionReplaceExistingData.hpp> +#include <com/sun/star/ucb/XInteractionSupplyName.hpp> +#include <com/sun/star/xforms/InvalidDataOnSubmitException.hpp> +#include <com/sun/star/loader/CannotActivateFactoryException.hpp> + +#include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/conditn.hxx> +#include <unotools/resmgr.hxx> +#include <utility> +#include <vcl/errinf.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <tools/diagnose_ex.h> +#include <comphelper/documentconstants.hxx> +#include <comphelper/propertysequence.hxx> +#include <svtools/sfxecode.hxx> +#include <unotools/configmgr.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <typelib/typedescription.hxx> +#include <unotools/confignode.hxx> + +#include <ids.hxx> +#include <ids.hrc> +#include <strings.hrc> + +#include "getcontinuations.hxx" +#include "secmacrowarnings.hxx" + +#include "iahndl.hxx" +#include "nameclashdlg.hxx" + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::task::XInteractionContinuation; +using ::com::sun::star::task::XInteractionAbort; +using ::com::sun::star::task::XInteractionApprove; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::lang::XInitialization; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::task::InteractionHandler; +using ::com::sun::star::task::XInteractionHandler2; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Any; +using ::com::sun::star::task::XInteractionRequest; +using ::com::sun::star::lang::XMultiServiceFactory; + +using namespace ::com::sun::star; + +namespace { + +class HandleData : public osl::Condition +{ +public: + explicit HandleData( + uno::Reference< task::XInteractionRequest > xRequest) + : m_rRequest(std::move(xRequest)), + bHandled( false ) + { + } + uno::Reference< task::XInteractionRequest > m_rRequest; + bool bHandled; + beans::Optional< OUString > m_aResult; +}; + +} /* namespace */ + +UUIInteractionHelper::UUIInteractionHelper( + uno::Reference< uno::XComponentContext > xContext) + : m_xContext(std::move(xContext)) +{ +} + +UUIInteractionHelper::~UUIInteractionHelper() +{ +} + +void UUIInteractionHelper::handlerequest( + void* pHandleData, void* pInteractionHelper) +{ + HandleData* pHND + = static_cast< HandleData * >(pHandleData); + UUIInteractionHelper* pUUI + = static_cast< UUIInteractionHelper * >(pInteractionHelper); + bool bDummy = false; + OUString aDummy; + pHND->bHandled + = pUUI->handleRequest_impl(pHND->m_rRequest, false, bDummy, aDummy); + pHND->set(); +} + +bool +UUIInteractionHelper::handleRequest( + uno::Reference< task::XInteractionRequest > const & rRequest) +{ + if(!Application::IsMainThread() && GetpApp()) + { + // we are not in the main thread, let it handle that stuff + HandleData aHD(rRequest); + Link<void*,void> aLink(&aHD,handlerequest); + Application::PostUserEvent(aLink,this); + comphelper::SolarMutex& rSolarMutex = Application::GetSolarMutex(); + sal_uInt32 nLockCount = (rSolarMutex.IsCurrentThread()) ? rSolarMutex.release(true) : 0; + aHD.wait(); + if (nLockCount) + rSolarMutex.acquire(nLockCount); + return aHD.bHandled; + } + else + { + bool bDummy = false; + OUString aDummy; + return handleRequest_impl(rRequest, false, bDummy, aDummy); + } +} + +void UUIInteractionHelper::getstringfromrequest( + void* pHandleData,void* pInteractionHelper) +{ + HandleData* pHND = static_cast<HandleData*>(pHandleData); + UUIInteractionHelper* pUUI = static_cast<UUIInteractionHelper*>(pInteractionHelper); + pHND->m_aResult = pUUI->getStringFromRequest_impl(pHND->m_rRequest); + pHND->set(); +} + +beans::Optional< OUString > +UUIInteractionHelper::getStringFromRequest_impl( + uno::Reference< task::XInteractionRequest > const & rRequest) +{ + bool bSuccess = false; + OUString aMessage; + handleRequest_impl(rRequest, true, bSuccess, aMessage); + + OSL_ENSURE(bSuccess || + !isInformationalErrorMessageRequest( + rRequest->getContinuations()), + "Interaction request is a candidate for a string representation." + "Please implement!"); + + return beans::Optional< OUString >(bSuccess, aMessage); +} + +beans::Optional< OUString > +UUIInteractionHelper::getStringFromRequest( + uno::Reference< task::XInteractionRequest > const & rRequest) +{ + if(!Application::IsMainThread() && GetpApp()) + { + // we are not in the main thread, let it handle that stuff + HandleData aHD(rRequest); + Link<void*,void> aLink(&aHD,getstringfromrequest); + Application::PostUserEvent(aLink,this); + comphelper::SolarMutex& rSolarMutex = Application::GetSolarMutex(); + sal_uInt32 nLockCount = (rSolarMutex.IsCurrentThread()) ? rSolarMutex.release(true) : 0; + aHD.wait(); + if (nLockCount) + rSolarMutex.acquire(nLockCount); + return aHD.m_aResult; + } + else + return getStringFromRequest_impl(rRequest); +} + +OUString +UUIInteractionHelper::replaceMessageWithArguments( + const OUString& _aMessage, + std::vector< OUString > const & rArguments ) +{ + OUString aMessage = _aMessage; + + SAL_WARN_IF(rArguments.empty(), "uui", "replaceMessageWithArguments: No arguments passed!"); + for (size_t i = 0; i < rArguments.size(); ++i) + { + const OUString sReplaceTemplate = "$(ARG" + OUString::number(i+1) + ")"; + aMessage = aMessage.replaceAll(sReplaceTemplate, rArguments[i]); + } + + return aMessage; +} + +bool +UUIInteractionHelper::isInformationalErrorMessageRequest( + uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & + rContinuations) +{ + // Only requests with a single continuation (user has no choice, request + // is just informational) + if (rContinuations.getLength() != 1 ) + return false; + + // user can only abort or approve, all other continuations are not + // considered to be informational. + uno::Reference< task::XInteractionApprove > xApprove( + rContinuations[0], uno::UNO_QUERY); + if (xApprove.is()) + return true; + + uno::Reference< task::XInteractionAbort > xAbort( + rContinuations[0], uno::UNO_QUERY); + return xAbort.is(); +} + +bool +UUIInteractionHelper::tryOtherInteractionHandler( + uno::Reference< task::XInteractionRequest > const & rRequest) +{ + InteractionHandlerDataList dataList; + getInteractionHandlerList(dataList); + + return std::any_of(dataList.cbegin(), dataList.cend(), + [&](const InteractionHandlerData& rData) { return handleCustomRequest( rRequest, rData.ServiceName ); }); +} + +namespace +{ + + bool lcl_matchesRequest( const Any& i_rRequest, const OUString& i_rTypeName, std::u16string_view i_rPropagation ) + { + const css::uno::TypeDescription aTypeDesc( i_rTypeName ); + const typelib_TypeDescription* pTypeDesc = aTypeDesc.get(); + if ( !pTypeDesc || !pTypeDesc->pWeakRef ) + { + SAL_WARN( "uui","no type found for '" << i_rTypeName << "'" ); + return false; + } + const css::uno::Type aType( pTypeDesc->pWeakRef ); + + const bool bExactMatch = i_rPropagation == u"named-only"; + if ( bExactMatch ) + return i_rRequest.getValueType().equals( aType ); + + return i_rRequest.isExtractableTo( aType ); + } +} + + +bool UUIInteractionHelper::handleCustomRequest( const Reference< XInteractionRequest >& i_rRequest, const OUString& i_rServiceName ) const +{ + try + { + Reference< XInteractionHandler2 > xHandler( m_xContext->getServiceManager()->createInstanceWithContext( i_rServiceName, m_xContext ), UNO_QUERY_THROW ); + + Reference< XInitialization > xHandlerInit( xHandler, UNO_QUERY ); + if ( xHandlerInit.is() ) + { + ::comphelper::NamedValueCollection aInitArgs; + aInitArgs.put( "Parent", getParentXWindow() ); + xHandlerInit->initialize( aInitArgs.getWrappedPropertyValues() ); + } + + if ( xHandler->handleInteractionRequest( i_rRequest ) ) + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("uui"); + } + return false; +} + + +bool UUIInteractionHelper::handleTypedHandlerImplementations( Reference< XInteractionRequest > const & rRequest ) +{ + // the request + const Any aRequest( rRequest->getRequest() ); + + const StringHashMap::const_iterator aCacheHitTest = m_aTypedCustomHandlers.find( aRequest.getValueTypeName() ); + if ( aCacheHitTest != m_aTypedCustomHandlers.end() ) + return handleCustomRequest( rRequest, aCacheHitTest->second ); + + // the base registration node for "typed" interaction handlers + const ::utl::OConfigurationTreeRoot aConfigRoot( ::utl::OConfigurationTreeRoot::createWithComponentContext( + m_xContext, + "/org.openoffice.Interaction/InteractionHandlers", + -1, + ::utl::OConfigurationTreeRoot::CM_READONLY + ) ); + + // loop through all registered implementations + const Sequence< OUString > aRegisteredHandlers( aConfigRoot.getNodeNames() ); + for ( auto const & handlerName : aRegisteredHandlers ) + { + const ::utl::OConfigurationNode aHandlerNode( aConfigRoot.openNode( handlerName ) ); + const ::utl::OConfigurationNode aTypesNode( aHandlerNode.openNode( "HandledRequestTypes" ) ); + + // loop through all the types which the current handler is registered for + const Sequence< OUString > aHandledTypes( aTypesNode.getNodeNames() ); + for ( auto const & type : aHandledTypes ) + { + // the UNO type is the node name + ::utl::OConfigurationNode aType( aTypesNode.openNode( type ) ); + // and there's a child denoting how the responsibility propagates + OUString sPropagation; + OSL_VERIFY( aType.getNodeValue( "Propagation" ) >>= sPropagation ); + if ( lcl_matchesRequest( aRequest, type, sPropagation ) ) + { + // retrieve the service/implementation name of the handler + OUString sServiceName; + OSL_VERIFY( aHandlerNode.getNodeValue( "ServiceName" ) >>= sServiceName ); + // cache the information who feels responsible for requests of this type + m_aTypedCustomHandlers[ aRequest.getValueTypeName() ] = sServiceName; + // actually handle the request + return handleCustomRequest( rRequest, sServiceName ); + } + } + } + + return false; +} + +bool +UUIInteractionHelper::handleRequest_impl( + uno::Reference< task::XInteractionRequest > const & rRequest, + bool bObtainErrorStringOnly, + bool & bHasErrorString, + OUString & rErrorString) +{ + try + { + if (!rRequest.is()) + return false; + + uno::Any aAnyRequest(rRequest->getRequest()); + + script::ModuleSizeExceededRequest aModSizeException; + if (aAnyRequest >>= aModSizeException ) + { + std::vector< OUString > aArguments; + uno::Sequence< OUString > sModules + = aModSizeException.Names; + if ( sModules.hasElements() ) + { + OUStringBuffer aName; + for ( sal_Int32 index=0; index< sModules.getLength(); ++index ) + { + if ( index ) + aName.append(","); + aName.append(sModules[index]); + } + aArguments.push_back( aName.makeStringAndClear() ); + } + handleErrorHandlerRequest( task::InteractionClassification_WARNING, + ERRCODE_UUI_IO_MODULESIZEEXCEEDED, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + document::ExoticFileLoadException aExoticFileLoadException; + if (aAnyRequest >>= aExoticFileLoadException) + { + std::vector< OUString > aArguments; + + if( !aExoticFileLoadException.URL.isEmpty() ) + { + aArguments.push_back( aExoticFileLoadException.URL ); + } + if( !aExoticFileLoadException.FilterUIName.isEmpty() ) + { + aArguments.push_back( aExoticFileLoadException.FilterUIName ); + } + + handleErrorHandlerRequest( task::InteractionClassification_WARNING, + ERRCODE_UUI_IO_EXOTICFILEFORMAT, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + ucb::NameClashException aNCException; + if (aAnyRequest >>= aNCException) + { + ErrCode nErrorCode = ERRCODE_UUI_IO_TARGETALREADYEXISTS; + std::vector< OUString > aArguments; + + if( !aNCException.Name.isEmpty() ) + { + nErrorCode = ERRCODE_UUI_IO_ALREADYEXISTS; + aArguments.push_back( aNCException.Name ); + } + + handleErrorHandlerRequest( aNCException.Classification, + nErrorCode, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + ucb::UnsupportedNameClashException aUORequest; + if (aAnyRequest >>= aUORequest) + { + + uno::Reference< task::XInteractionApprove > xApprove; + uno::Reference< task::XInteractionDisapprove > xDisapprove; + getContinuations( + rRequest->getContinuations(), &xApprove, &xDisapprove); + + if ( xApprove.is() && xDisapprove.is() ) + { + std::vector< OUString > aArguments; + handleErrorHandlerRequest( task::InteractionClassification_QUERY, + ERRCODE_UUI_IO_UNSUPPORTEDOVERWRITE, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + } + return true; + } + + if ( handleInteractiveIOException( rRequest, + bObtainErrorStringOnly, + bHasErrorString, + rErrorString ) ) + return true; + + ucb::InteractiveAppException aAppException; + if (aAnyRequest >>= aAppException) + { + std::vector< OUString > aArguments; + handleErrorHandlerRequest( aAppException.Classification, + ErrCode(aAppException.Code), + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + ucb::InteractiveNetworkException aNetworkException; + if (aAnyRequest >>= aNetworkException) + { + ErrCode nErrorCode; + std::vector< OUString > aArguments; + ucb::InteractiveNetworkOffLineException aOffLineException; + ucb::InteractiveNetworkResolveNameException aResolveNameException; + ucb::InteractiveNetworkConnectException aConnectException; + ucb::InteractiveNetworkReadException aReadException; + ucb::InteractiveNetworkWriteException aWriteException; + if (aAnyRequest >>= aOffLineException) + nErrorCode = ERRCODE_INET_OFFLINE; + else if (aAnyRequest >>= aResolveNameException) + { + nErrorCode = ERRCODE_INET_NAME_RESOLVE; + aArguments.push_back(aResolveNameException.Server); + } + else if (aAnyRequest >>= aConnectException) + { + nErrorCode = ERRCODE_INET_CONNECT; + aArguments.push_back(aConnectException.Server); + } + else if (aAnyRequest >>= aReadException) + { + nErrorCode = ERRCODE_INET_READ; + aArguments.push_back(aReadException.Diagnostic); + } + else if (aAnyRequest >>= aWriteException) + { + nErrorCode = ERRCODE_INET_WRITE; + aArguments.push_back(aWriteException.Diagnostic); + } + else + nErrorCode = ERRCODE_INET_GENERAL; + + handleErrorHandlerRequest(aNetworkException.Classification, + nErrorCode, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + ucb::InteractiveWrongMediumException aWrongMediumException; + if (aAnyRequest >>= aWrongMediumException) + { + sal_Int32 nMedium = 0; + aWrongMediumException.Medium >>= nMedium; + std::vector< OUString > aArguments { OUString::number(nMedium + 1) }; + handleErrorHandlerRequest(aWrongMediumException.Classification, + ERRCODE_UUI_WRONGMEDIUM, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + java::WrongJavaVersionException aWrongJavaVersionException; + if (aAnyRequest >>= aWrongJavaVersionException) + { + ErrCode nErrorCode; + std::vector< OUString > aArguments; + if (aWrongJavaVersionException.DetectedVersion.isEmpty()) + if (aWrongJavaVersionException.LowestSupportedVersion.isEmpty()) + nErrorCode = ERRCODE_UUI_WRONGJAVA; + else + { + nErrorCode = ERRCODE_UUI_WRONGJAVA_MIN; + aArguments.push_back(aWrongJavaVersionException.LowestSupportedVersion); + } + else if (aWrongJavaVersionException.LowestSupportedVersion.isEmpty()) + { + nErrorCode = ERRCODE_UUI_WRONGJAVA_VERSION; + aArguments.push_back(aWrongJavaVersionException.DetectedVersion); + } + else + { + nErrorCode = ERRCODE_UUI_WRONGJAVA_VERSION_MIN; + aArguments.reserve(2); + aArguments.push_back(aWrongJavaVersionException.DetectedVersion); + aArguments.push_back(aWrongJavaVersionException.LowestSupportedVersion); + } + handleErrorHandlerRequest(task::InteractionClassification_ERROR, + nErrorCode, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + configuration::backend::MergeRecoveryRequest aMergeRecoveryRequest; + if (aAnyRequest >>= aMergeRecoveryRequest) + { + ErrCode nErrorCode = aMergeRecoveryRequest.IsRemovalRequest + ? ERRCODE_UUI_CONFIGURATION_BROKENDATA_WITHREMOVE + : ERRCODE_UUI_CONFIGURATION_BROKENDATA_NOREMOVE; + + std::vector< OUString > aArguments { aMergeRecoveryRequest.ErrorLayerId }; + + handleErrorHandlerRequest(task::InteractionClassification_ERROR, + nErrorCode, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + configuration::backend::StratumCreationException + aStratumCreationException; + + if (aAnyRequest >>= aStratumCreationException) + { + const ErrCode nErrorCode = ERRCODE_UUI_CONFIGURATION_BACKENDMISSING; + + OUString aStratum = aStratumCreationException.StratumData; + if (aStratum.isEmpty()) + aStratum = aStratumCreationException.StratumService; + + std::vector< OUString > aArguments { aStratum }; + + handleErrorHandlerRequest(task::InteractionClassification_ERROR, + nErrorCode, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + xforms::InvalidDataOnSubmitException aInvalidDataOnSubmitException; + if (aAnyRequest >>= aInvalidDataOnSubmitException) + { + const ErrCode nErrorCode = + ERRCODE_UUI_INVALID_XFORMS_SUBMISSION_DATA; + + std::vector< OUString > aArguments; + + handleErrorHandlerRequest(task::InteractionClassification_QUERY, + nErrorCode, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + ucb::InteractiveLockingLockedException aLLException; + if (aAnyRequest >>= aLLException) + { + ErrCode nErrorCode = aLLException.SelfOwned + ? ERRCODE_UUI_LOCKING_LOCKED_SELF : ERRCODE_UUI_LOCKING_LOCKED; + std::vector< OUString > aArguments { aLLException.Url }; + + handleErrorHandlerRequest( aLLException.Classification, + nErrorCode, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString ); + return true; + } + + ucb::InteractiveLockingNotLockedException aLNLException; + if (aAnyRequest >>= aLNLException) + { + std::vector< OUString > aArguments { aLNLException.Url }; + + handleErrorHandlerRequest( aLNLException.Classification, + ERRCODE_UUI_LOCKING_NOT_LOCKED, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString ); + return true; + } + + ucb::InteractiveLockingLockExpiredException aLLEException; + if (aAnyRequest >>= aLLEException) + { + std::vector< OUString > aArguments { aLLEException.Url }; + + handleErrorHandlerRequest( aLLEException.Classification, + ERRCODE_UUI_LOCKING_LOCK_EXPIRED, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString ); + return true; + } + + document::BrokenPackageRequest aBrokenPackageRequest; + if (aAnyRequest >>= aBrokenPackageRequest) + { + std::vector< OUString > aArguments; + + if( !aBrokenPackageRequest.aName.isEmpty() ) + aArguments.push_back( aBrokenPackageRequest.aName ); + + handleBrokenPackageRequest( aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString ); + return true; + } + + task::ErrorCodeRequest aErrorCodeRequest; + if (aAnyRequest >>= aErrorCodeRequest) + { + handleGenericErrorRequest( ErrCode(aErrorCodeRequest.ErrCode), + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + task::ErrorCodeIOException aErrorCodeIOException; + if (aAnyRequest >>= aErrorCodeIOException) + { + handleGenericErrorRequest( ErrCode(aErrorCodeIOException.ErrCode), + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString); + return true; + } + + loader::CannotActivateFactoryException aCannotActivateFactoryException; + if (aAnyRequest >>= aCannotActivateFactoryException) + { + std::vector< OUString > aArguments { aCannotActivateFactoryException.Message }; + + handleErrorHandlerRequest( task::InteractionClassification_ERROR, + ERRCODE_UUI_CANNOT_ACTIVATE_FACTORY, + aArguments, + rRequest->getContinuations(), + bObtainErrorStringOnly, + bHasErrorString, + rErrorString ); + return true; + } + + + // Handle requests which do not have a plain string representation. + + if (!bObtainErrorStringOnly) + { + ucb::AuthenticationFallbackRequest anAuthFallbackRequest; + if ( aAnyRequest >>= anAuthFallbackRequest ) + { + handleAuthFallbackRequest( anAuthFallbackRequest.instructions, + anAuthFallbackRequest.url, rRequest->getContinuations() ); + return true; + } + + if ( handleAuthenticationRequest( rRequest ) ) + return true; + + if ( handleCertificateValidationRequest( rRequest ) ) + return true; + + ucb::NameClashResolveRequest aNameClashResolveRequest; + if (aAnyRequest >>= aNameClashResolveRequest) + { + handleNameClashResolveRequest(aNameClashResolveRequest, + rRequest->getContinuations()); + return true; + } + + if ( handleMasterPasswordRequest( rRequest ) ) + return true; + + if ( handlePasswordRequest( rRequest ) ) + return true; + + if ( handleNoSuchFilterRequest( rRequest ) ) + return true; + + if ( handleFilterOptionsRequest( rRequest ) ) + return true; + + if ( handleLockedDocumentRequest( rRequest ) ) + return true; + + if ( handleChangedByOthersRequest( rRequest ) ) + return true; + + if ( handleLockFileProblemRequest( rRequest ) ) + return true; + + if ( handleReloadEditableRequest( rRequest ) ) + return true; + + task::DocumentMacroConfirmationRequest aMacroConfirmRequest; + if (aAnyRequest >>= aMacroConfirmRequest) + { + handleMacroConfirmRequest( + aMacroConfirmRequest.DocumentURL, + aMacroConfirmRequest.DocumentStorage, + !aMacroConfirmRequest.DocumentVersion.isEmpty() ? aMacroConfirmRequest.DocumentVersion : ODFVER_013_TEXT, + aMacroConfirmRequest.DocumentSignatureInformation, + rRequest->getContinuations()); + return true; + } + + // Last chance: interaction handlers registered in the configuration + + + // typed InteractionHandlers (ooo.Interactions) + if ( handleTypedHandlerImplementations( rRequest ) ) + return true; + + // legacy configuration (ooo.ucb.InteractionHandlers) + if (tryOtherInteractionHandler( rRequest )) + return true; + } + + // Not handled. + return false; + } + catch( const uno::RuntimeException& ) + { + throw; // allowed to leave here + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("uui"); + } + return false; +} + +void +UUIInteractionHelper::getInteractionHandlerList( + InteractionHandlerDataList &rdataList) +{ + try + { + uno::Reference< lang::XMultiServiceFactory > xConfigProv = + configuration::theDefaultProvider::get( m_xContext ); + + uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence( + { + {"nodepath", uno::Any(OUString("/org.openoffice.ucb.InteractionHandler/InteractionHandlers"))} + })); + + uno::Reference< uno::XInterface > xInterface( + xConfigProv->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess" , aArguments ) ); + + if ( !xInterface.is() ) + throw uno::RuntimeException("unable to instantiate config access"); + + uno::Reference< container::XNameAccess > xNameAccess( + xInterface, uno::UNO_QUERY_THROW ); + const uno::Sequence< OUString > aElems = xNameAccess->getElementNames(); + + if ( aElems.hasElements() ) + { + uno::Reference< container::XHierarchicalNameAccess > + xHierNameAccess( xInterface, uno::UNO_QUERY_THROW ); + + // Iterate over children. + for ( const auto& rElem : aElems ) + { + try + { + InteractionHandlerData aInfo; + + // Obtain service name. + OUString aKeyBuffer = "['" + rElem + "']/ServiceName"; + + OUString aValue; + if ( !( xHierNameAccess->getByHierarchicalName( + aKeyBuffer ) >>= aValue ) ) + { + OSL_FAIL( "GetInteractionHandlerList - " + "Error getting item value!" ); + continue; + } + + aInfo.ServiceName = aValue; + + // Append info to list. + rdataList.push_back( aInfo ); + } + catch ( container::NoSuchElementException& ) + { + // getByHierarchicalName + + OSL_FAIL( "GetInteractionHandlerList - " + "caught NoSuchElementException!" ); + } + } + } + } + catch ( uno::RuntimeException const & ) + { + throw; + } + catch ( uno::Exception const & ) + { + TOOLS_WARN_EXCEPTION( "uui", "GetInteractionHandlerList" ); + } +} + +const uno::Reference< awt::XWindow>& +UUIInteractionHelper::getParentXWindow() const +{ + return m_xWindowParam; +} + +uno::Reference< task::XInteractionHandler2 > +UUIInteractionHelper::getInteractionHandler() const +{ + return InteractionHandler::createWithParentAndContext( + m_xContext, m_xWindowParam, + m_aContextParam); +} + +namespace { + +DialogMask +executeMessageBox( + weld::Window * pParent, + OUString const & rTitle, + OUString const & rMessage, + VclMessageType eMessageType) +{ + SolarMutexGuard aGuard; + + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent, eMessageType, + eMessageType == VclMessageType::Question ? VclButtonsType::YesNo : VclButtonsType::Ok, rMessage)); + xBox->set_title(rTitle); + + short nMessResult = xBox->run(); + DialogMask aResult = DialogMask::NONE; + switch (nMessResult) + { + case RET_OK: + aResult = DialogMask::ButtonsOk; + break; + case RET_CANCEL: + aResult = DialogMask::ButtonsCancel; + break; + case RET_YES: + aResult = DialogMask::ButtonsYes; + break; + case RET_NO: + aResult = DialogMask::ButtonsNo; + break; + default: + assert(false); + } + + return aResult; +} + +NameClashResolveDialogResult executeSimpleNameClashResolveDialog(weld::Window *pParent, + OUString const & rTargetFolderURL, + OUString const & rClashingName, + OUString & rProposedNewName, + bool bAllowOverwrite) +{ + std::locale aResLocale = Translate::Create("uui"); + NameClashDialog aDialog(pParent, aResLocale, rTargetFolderURL, + rClashingName, rProposedNewName, bAllowOverwrite); + + NameClashResolveDialogResult eResult = static_cast<NameClashResolveDialogResult>(aDialog.run()); + rProposedNewName = aDialog.getNewName(); + return eResult; +} + +} // namespace + +void +UUIInteractionHelper::handleNameClashResolveRequest( + ucb::NameClashResolveRequest const & rRequest, + uno::Sequence< uno::Reference< + task::XInteractionContinuation > > const & rContinuations) +{ + OSL_ENSURE(!rRequest.TargetFolderURL.isEmpty(), + "NameClashResolveRequest must not contain empty TargetFolderURL" ); + + OSL_ENSURE(!rRequest.ClashingName.isEmpty(), + "NameClashResolveRequest must not contain empty ClashingName" ); + + uno::Reference< task::XInteractionAbort > xAbort; + uno::Reference< ucb::XInteractionSupplyName > xSupplyName; + uno::Reference< ucb::XInteractionReplaceExistingData > xReplaceExistingData; + getContinuations( + rContinuations, &xAbort, &xSupplyName, &xReplaceExistingData); + + OSL_ENSURE( xAbort.is(), + "NameClashResolveRequest must contain Abort continuation" ); + + OSL_ENSURE( xSupplyName.is(), + "NameClashResolveRequest must contain SupplyName continuation" ); + + NameClashResolveDialogResult eResult = ABORT; + OUString aProposedNewName( rRequest.ProposedNewName ); + + uno::Reference<awt::XWindow> xParent = getParentXWindow(); + eResult = executeSimpleNameClashResolveDialog(Application::GetFrameWeld(xParent), + rRequest.TargetFolderURL, + rRequest.ClashingName, + aProposedNewName, + xReplaceExistingData.is()); + + switch ( eResult ) + { + case ABORT: + xAbort->select(); + break; + + case RENAME: + xSupplyName->setName( aProposedNewName ); + xSupplyName->select(); + break; + + case OVERWRITE: + OSL_ENSURE( + xReplaceExistingData.is(), + "Invalid NameClashResolveDialogResult: OVERWRITE - " + "No ReplaceExistingData continuation available!" ); + xReplaceExistingData->select(); + break; + } +} + +void +UUIInteractionHelper::handleGenericErrorRequest( + ErrCode nErrorCode, + uno::Sequence< uno::Reference< + task::XInteractionContinuation > > const & rContinuations, + bool bObtainErrorStringOnly, + bool & bHasErrorString, + OUString & rErrorString) +{ + if (bObtainErrorStringOnly) + { + bHasErrorString = isInformationalErrorMessageRequest(rContinuations); + if (bHasErrorString) + { + OUString aErrorString; + ErrorHandler::GetErrorString(nErrorCode, aErrorString); + rErrorString = aErrorString; + } + } + else + { + uno::Reference< task::XInteractionAbort > xAbort; + uno::Reference< task::XInteractionApprove > xApprove; + getContinuations(rContinuations, &xApprove, &xAbort); + + // Note: It's important to convert the transported long to the + // required unsigned long value. Otherwise using as flag field + // can fail ... + ErrCode nError(nErrorCode); + bool bWarning = !nError.IgnoreWarning(); + + if ( nError == ERRCODE_SFX_INCOMPLETE_ENCRYPTION ) + { + // the security warning box needs a special title + OUString aErrorString; + ErrorHandler::GetErrorString( nErrorCode, aErrorString ); + + std::locale aResLocale = Translate::Create("uui"); + OUString aTitle( utl::ConfigManager::getProductName() ); + + OUString aErrTitle = Translate::get(STR_WARNING_INCOMPLETE_ENCRYPTION_TITLE, aResLocale); + + if ( !aTitle.isEmpty() && !aErrTitle.isEmpty() ) + aTitle += " - " ; + aTitle += aErrTitle; + + uno::Reference<awt::XWindow> xParent = getParentXWindow(); + executeMessageBox(Application::GetFrameWeld(xParent), aTitle, aErrorString, VclMessageType::Error); + } + else + { + uno::Reference<awt::XWindow> xParent = getParentXWindow(); + ErrorHandler::HandleError(nErrorCode, Application::GetFrameWeld(xParent)); + } + + if (xApprove.is() && bWarning) + xApprove->select(); + else if (xAbort.is()) + xAbort->select(); + } +} + +void +UUIInteractionHelper::handleMacroConfirmRequest( + const OUString& aDocumentURL, + const uno::Reference< embed::XStorage >& xZipStorage, + const OUString& aDocumentVersion, + const uno::Sequence< security::DocumentSignatureInformation >& aSignInfo, + uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & + rContinuations ) +{ + uno::Reference< task::XInteractionAbort > xAbort; + uno::Reference< task::XInteractionApprove > xApprove; + getContinuations( rContinuations, &xApprove, &xAbort ); + + bool bApprove = false; + + bool bShowSignatures = aSignInfo.hasElements(); + uno::Reference<awt::XWindow> xParent = getParentXWindow(); + MacroWarning aWarning(Application::GetFrameWeld(xParent), bShowSignatures); + + aWarning.SetDocumentURL(aDocumentURL); + if ( aSignInfo.getLength() > 1 ) + { + aWarning.SetStorage(xZipStorage, aDocumentVersion, aSignInfo); + } + else if ( aSignInfo.getLength() == 1 ) + { + aWarning.SetCertificate(aSignInfo[0].Signer); + } + + bApprove = aWarning.run() == RET_OK; + + if ( bApprove && xApprove.is() ) + xApprove->select(); + else if ( xAbort.is() ) + xAbort->select(); +} + +void +UUIInteractionHelper::handleBrokenPackageRequest( + std::vector< OUString > const & rArguments, + uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & + rContinuations, + bool bObtainErrorStringOnly, + bool & bHasErrorString, + OUString & rErrorString) +{ + if (bObtainErrorStringOnly) + { + bHasErrorString = isInformationalErrorMessageRequest(rContinuations); + if (!bHasErrorString) + return; + } + + uno::Reference< task::XInteractionApprove > xApprove; + uno::Reference< task::XInteractionDisapprove > xDisapprove; + uno::Reference< task::XInteractionAbort > xAbort; + getContinuations(rContinuations, &xApprove, &xDisapprove, &xAbort); + + ErrCode nErrorCode; + if( xApprove.is() && xDisapprove.is() ) + { + nErrorCode = ERRCODE_UUI_IO_BROKENPACKAGE; + } + else if ( xAbort.is() ) + { + nErrorCode = ERRCODE_UUI_IO_BROKENPACKAGE_CANTREPAIR; + } + else + return; + + OUString aMessage; + { + std::locale aResLocale = Translate::Create("uui"); + ErrorResource aErrorResource(RID_UUI_ERRHDL, aResLocale); + if (!aErrorResource.getString(nErrorCode, aMessage)) + return; + } + + aMessage = replaceMessageWithArguments( aMessage, rArguments ); + + if (bObtainErrorStringOnly) + { + rErrorString = aMessage; + return; + } + + VclMessageType eMessageType; + if( xApprove.is() && xDisapprove.is() ) + eMessageType = VclMessageType::Question; + else if ( xAbort.is() ) + eMessageType = VclMessageType::Warning; + else + return; + + OUString title( + utl::ConfigManager::getProductName() + + " " + + utl::ConfigManager::getProductVersion() ); + + uno::Reference<awt::XWindow> xParent = getParentXWindow(); + switch (executeMessageBox(Application::GetFrameWeld(xParent), title, aMessage, eMessageType)) + { + case DialogMask::ButtonsOk: + OSL_ENSURE( xAbort.is(), "unexpected situation" ); + if (xAbort.is()) + xAbort->select(); + break; + + case DialogMask::ButtonsNo: + OSL_ENSURE(xDisapprove.is(), "unexpected situation"); + if (xDisapprove.is()) + xDisapprove->select(); + break; + + case DialogMask::ButtonsYes: + OSL_ENSURE(xApprove.is(), "unexpected situation"); + if (xApprove.is()) + xApprove->select(); + break; + + default: break; + } +} + +// ErrorResource Implementation +bool ErrorResource::getString(ErrCode nErrorCode, OUString &rString) const +{ + for (const std::pair<TranslateId, ErrCode>* pStringArray = m_pStringArray; pStringArray->first; ++pStringArray) + { + if (nErrorCode.StripWarningAndDynamic() == pStringArray->second.StripWarningAndDynamic()) + { + rString = Translate::get(pStringArray->first, m_rResLocale); + return true; + } + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |