/************************************************************** * * 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. * *************************************************************/ #include #include "com/sun/star/awt/XWindow.hpp" #include "com/sun/star/beans/PropertyValue.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/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/sync2/BadPartnershipException.hpp" #include "com/sun/star/task/ErrorCodeIOException.hpp" #include "com/sun/star/task/ErrorCodeRequest.hpp" #include "com/sun/star/task/FutureDocumentVersionProductUpdateRequest.hpp" #include "com/sun/star/task/XInteractionAbort.hpp" #include "com/sun/star/task/XInteractionApprove.hpp" #include "com/sun/star/task/XInteractionAskLater.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/task/XInteractionRetry.hpp" #include "com/sun/star/ucb/InteractiveAppException.hpp" #include "com/sun/star/ucb/InteractiveCHAOSException.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 "osl/conditn.hxx" #include "tools/rcid.h" // RSC_STRING #include "tools/errinf.hxx" // ErrorHandler, ErrorContext, ... #include "vos/mutex.hxx" #include "tools/diagnose_ex.h" #include "comphelper/documentconstants.hxx" // ODFVER_012_TEXT #include "svtools/sfxecode.hxx" // ERRCODE_SFX_* #include "vcl/msgbox.hxx" #include "vcl/svapp.hxx" #include "unotools/configmgr.hxx" #include "toolkit/helper/vclunohelper.hxx" #include "comphelper/namedvaluecollection.hxx" #include "typelib/typedescription.hxx" #include "unotools/confignode.hxx" #include "ids.hrc" #include "getcontinuations.hxx" #include "secmacrowarnings.hxx" #include "newerverwarn.hxx" #include "iahndl.hxx" #include "nameclashdlg.hxx" /** === begin UNO using === **/ 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::task::XInteractionAskLater; using ::com::sun::star::task::FutureDocumentVersionProductUpdateRequest; 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::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; /** === end UNO using === **/ using namespace ::com::sun::star; namespace { class HandleData : public osl::Condition { public: HandleData( uno::Reference< task::XInteractionRequest > const & rRequest) : osl::Condition(), m_rRequest(rRequest), bHandled( false ) { } uno::Reference< task::XInteractionRequest > m_rRequest; bool bHandled; beans::Optional< rtl::OUString > m_aResult; }; } /* namespace */ UUIInteractionHelper::UUIInteractionHelper( uno::Reference< lang::XMultiServiceFactory > const & rServiceFactory, uno::Sequence< uno::Any > const & rArguments) SAL_THROW(()): m_xServiceFactory(rServiceFactory), m_aProperties(rArguments) { } UUIInteractionHelper::UUIInteractionHelper( uno::Reference< lang::XMultiServiceFactory > const & rServiceFactory) SAL_THROW(()): m_xServiceFactory(rServiceFactory) { } UUIInteractionHelper::~UUIInteractionHelper() { } long UUIInteractionHelper::handlerequest( void* pHandleData, void* pInteractionHelper) { HandleData* pHND = static_cast< HandleData * >(pHandleData); UUIInteractionHelper* pUUI = static_cast< UUIInteractionHelper * >(pInteractionHelper); bool bDummy = false; rtl::OUString aDummy; pHND->bHandled = pUUI->handleRequest_impl(pHND->m_rRequest, false, bDummy, aDummy); pHND->set(); return 0; } bool UUIInteractionHelper::handleRequest( uno::Reference< task::XInteractionRequest > const & rRequest) SAL_THROW((uno::RuntimeException)) { Application* pApp = 0; if( // be aware,it is the same type static_cast< oslThreadIdentifier >( Application::GetMainThreadIdentifier()) != osl_getThreadIdentifier(NULL) && (pApp = GetpApp()) != 0 ) { // we are not in the main thread, let it handle that stuff HandleData aHD(rRequest); Link aLink(&aHD,handlerequest); pApp->PostUserEvent(aLink,this); sal_uLong locks = Application::ReleaseSolarMutex(); aHD.wait(); Application::AcquireSolarMutex(locks); return aHD.bHandled; } else { bool bDummy = false; rtl::OUString aDummy; return handleRequest_impl(rRequest, false, bDummy, aDummy); } } long UUIInteractionHelper::getstringfromrequest( void* pHandleData,void* pInteractionHelper) { HandleData* pHND = (HandleData*) pHandleData; UUIInteractionHelper* pUUI = (UUIInteractionHelper*) pInteractionHelper; pHND->m_aResult = pUUI->getStringFromRequest_impl(pHND->m_rRequest); pHND->set(); return 0; } beans::Optional< rtl::OUString > UUIInteractionHelper::getStringFromRequest_impl( uno::Reference< task::XInteractionRequest > const & rRequest) SAL_THROW((uno::RuntimeException)) { bool bSuccess = false; rtl::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< rtl::OUString >(bSuccess, aMessage); } beans::Optional< rtl::OUString > UUIInteractionHelper::getStringFromRequest( uno::Reference< task::XInteractionRequest > const & rRequest) SAL_THROW((uno::RuntimeException)) { Application* pApp = 0; if( // be aware,it is the same type static_cast< oslThreadIdentifier >( Application::GetMainThreadIdentifier()) != osl_getThreadIdentifier(NULL) && (pApp = GetpApp()) != 0 ) { // we are not in the main thread, let it handle that stuff HandleData aHD(rRequest); Link aLink(&aHD,getstringfromrequest); pApp->PostUserEvent(aLink,this); sal_uLong locks = Application::ReleaseSolarMutex(); aHD.wait(); Application::AcquireSolarMutex(locks); return aHD.m_aResult; } else return getStringFromRequest_impl(rRequest); } ::rtl::OUString UUIInteractionHelper::replaceMessageWithArguments( ::rtl::OUString aMessage, std::vector< rtl::OUString > const & rArguments ) { for (sal_Int32 i = 0;;) { i = aMessage. indexOf(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("$(ARG")), i); if (i == -1) break; if (aMessage.getLength() - i >= RTL_CONSTASCII_LENGTH("$(ARGx)") && aMessage.getStr()[i + RTL_CONSTASCII_LENGTH("$(ARGx")] == ')') { sal_Unicode c = aMessage.getStr()[i + RTL_CONSTASCII_LENGTH("$(ARG")]; if (c >= '1' && c <= '2') { std::vector< rtl::OUString >::size_type nIndex = static_cast< std::vector< rtl::OUString >::size_type >( c - '1'); if (nIndex < rArguments.size()) { aMessage = aMessage.replaceAt(i, RTL_CONSTASCII_LENGTH("$(ARGx)"), rArguments[nIndex]); i += rArguments[nIndex].getLength(); continue; } } } ++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); if (xAbort.is()) return true; return false; } bool UUIInteractionHelper::tryOtherInteractionHandler( uno::Reference< task::XInteractionRequest > const & rRequest) SAL_THROW((uno::RuntimeException)) { InteractionHandlerDataList dataList; getInteractionHandlerList(dataList); InteractionHandlerDataList::const_iterator aEnd(dataList.end()); for (InteractionHandlerDataList::const_iterator aIt(dataList.begin()); aIt != aEnd; ++aIt) { if ( handleCustomRequest( rRequest, aIt->ServiceName ) ) return true; } return false; } namespace { // ................................................................................................................. static bool lcl_matchesRequest( const Any& i_rRequest, const ::rtl::OUString& i_rTypeName, const ::rtl::OUString& i_rPropagation ) { const ::com::sun::star::uno::TypeDescription aTypeDesc( i_rTypeName ); const typelib_TypeDescription* pTypeDesc = aTypeDesc.get(); if ( !pTypeDesc || !pTypeDesc->pWeakRef ) { #if OSL_DEBUG_LEVEL > 0 ::rtl::OStringBuffer aMessage; aMessage.append( "no type found for '" ); aMessage.append( ::rtl::OUStringToOString( i_rTypeName, RTL_TEXTENCODING_UTF8 ) ); aMessage.append( "'" ); OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() ); #endif return false; } const ::com::sun::star::uno::Type aType( pTypeDesc->pWeakRef ); const bool bExactMatch = ( i_rPropagation.compareToAscii( "named-only" ) == 0 ); if ( bExactMatch ) return i_rRequest.getValueType().equals( aType ); return i_rRequest.isExtractableTo( aType ); } } // --------------------------------------------------------------------------------------------------------------------- bool UUIInteractionHelper::handleCustomRequest( const Reference< XInteractionRequest >& i_rRequest, const ::rtl::OUString& i_rServiceName ) const { try { Reference< XInteractionHandler2 > xHandler( m_xServiceFactory->createInstance( i_rServiceName ), 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(); } 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::createWithServiceFactory( m_xServiceFactory, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Interaction/InteractionHandlers" ) ), -1, ::utl::OConfigurationTreeRoot::CM_READONLY ) ); // loop through all registered implementations const Sequence< ::rtl::OUString > aRegisteredHandlers( aConfigRoot.getNodeNames() ); const ::rtl::OUString* pHandlerName = aRegisteredHandlers.getConstArray(); const ::rtl::OUString* pHandlersEnd = aRegisteredHandlers.getConstArray() + aRegisteredHandlers.getLength(); for ( ; pHandlerName != pHandlersEnd; ++pHandlerName ) { const ::utl::OConfigurationNode aHandlerNode( aConfigRoot.openNode( *pHandlerName ) ); const ::utl::OConfigurationNode aTypesNode( aHandlerNode.openNode( "HandledRequestTypes" ) ); // loop through all the types which the current handler is registered for const Sequence< ::rtl::OUString > aHandledTypes( aTypesNode.getNodeNames() ); const ::rtl::OUString* pType = aHandledTypes.getConstArray(); const ::rtl::OUString* pTypesEnd = aHandledTypes.getConstArray() + aHandledTypes.getLength(); for ( ; pType != pTypesEnd; ++pType ) { // the UNO type is the node name ::utl::OConfigurationNode aType( aTypesNode.openNode( *pType ) ); // and there's a child denoting how the responsibility propagates ::rtl::OUString sPropagation; OSL_VERIFY( aType.getNodeValue( "Propagation" ) >>= sPropagation ); if ( lcl_matchesRequest( aRequest, *pType, sPropagation ) ) { // retrieve the service/implementation name of the handler ::rtl::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, rtl::OUString & rErrorString) SAL_THROW((uno::RuntimeException)) { try { if (!rRequest.is()) return false; uno::Any aAnyRequest(rRequest->getRequest()); script::ModuleSizeExceededRequest aModSizeException; if (aAnyRequest >>= aModSizeException ) { ErrCode nErrorCode = ERRCODE_UUI_IO_MODULESIZEEXCEEDED; std::vector< rtl::OUString > aArguments; uno::Sequence< rtl::OUString > sModules = aModSizeException.Names; if ( sModules.getLength() ) { rtl::OUString aName; for ( sal_Int32 index=0; index< sModules.getLength(); ++index ) { if ( index ) aName = aName + rtl::OUString( ',' ) + sModules[index]; else aName = sModules[index]; // 1st name } aArguments.push_back( aName ); } handleErrorHandlerRequest( task::InteractionClassification_WARNING, nErrorCode, aArguments, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString); return true; } ucb::NameClashException aNCException; if (aAnyRequest >>= aNCException) { ErrCode nErrorCode = ERRCODE_UUI_IO_TARGETALREADYEXISTS; std::vector< rtl::OUString > aArguments; if( aNCException.Name.getLength() ) { 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) { ErrCode nErrorCode = ERRCODE_UUI_IO_UNSUPPORTEDOVERWRITE; std::vector< rtl::OUString > aArguments; uno::Reference< task::XInteractionApprove > xApprove; uno::Reference< task::XInteractionDisapprove > xDisapprove; getContinuations( rRequest->getContinuations(), &xApprove, &xDisapprove); if ( xApprove.is() && xDisapprove.is() ) { handleErrorHandlerRequest( task::InteractionClassification_QUERY, nErrorCode, aArguments, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString); } return true; } if ( handleInteractiveIOException( rRequest, bObtainErrorStringOnly, bHasErrorString, rErrorString ) ) return true; ucb::InteractiveAppException aAppException; if (aAnyRequest >>= aAppException) { std::vector< rtl::OUString > aArguments; handleErrorHandlerRequest( aAppException.Classification, aAppException.Code, aArguments, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString); return true; } ucb::InteractiveNetworkException aNetworkException; if (aAnyRequest >>= aNetworkException) { ErrCode nErrorCode; std::vector< rtl::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::InteractiveCHAOSException aChaosException; if (aAnyRequest >>= aChaosException) { std::vector< rtl::OUString > aArguments; sal_Int32 nCount = std::min< sal_Int32 >(aChaosException.Arguments.getLength(), 2); aArguments. reserve(static_cast< std::vector< rtl::OUString >::size_type >( nCount)); for (sal_Int32 i = 0; i < nCount; ++i) aArguments.push_back(aChaosException.Arguments[i]); handleErrorHandlerRequest(aChaosException.Classification, aChaosException.ID, aArguments, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString); return true; } ucb::InteractiveWrongMediumException aWrongMediumException; if (aAnyRequest >>= aWrongMediumException) { sal_Int32 nMedium = 0; aWrongMediumException.Medium >>= nMedium; std::vector< rtl::OUString > aArguments; aArguments.push_back(UniString::CreateFromInt32(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< rtl::OUString > aArguments; if (aWrongJavaVersionException.DetectedVersion.getLength() == 0) if (aWrongJavaVersionException.LowestSupportedVersion. getLength() == 0) nErrorCode = ERRCODE_UUI_WRONGJAVA; else { nErrorCode = ERRCODE_UUI_WRONGJAVA_MIN; aArguments.push_back(aWrongJavaVersionException. LowestSupportedVersion); } else if (aWrongJavaVersionException.LowestSupportedVersion. getLength() == 0) { 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; } sync2::BadPartnershipException aBadPartnershipException; if (aAnyRequest >>= aBadPartnershipException) { ErrCode nErrorCode; std::vector< rtl::OUString > aArguments; if (aBadPartnershipException.Partnership.getLength() == 0) nErrorCode = ERRCODE_UUI_BADPARTNERSHIP; else { nErrorCode = ERRCODE_UUI_BADPARTNERSHIP_NAME; aArguments.push_back(aBadPartnershipException.Partnership); } 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< rtl::OUString > aArguments; aArguments.push_back(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; rtl::OUString aStratum = aStratumCreationException.StratumData; if (aStratum.getLength() == 0) aStratum = aStratumCreationException.StratumService; std::vector< rtl::OUString > aArguments; aArguments.push_back(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< rtl::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< rtl::OUString > aArguments; aArguments.push_back( aLLException.Url ); handleErrorHandlerRequest( aLLException.Classification, nErrorCode, aArguments, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString ); return true; } ucb::InteractiveLockingNotLockedException aLNLException; if (aAnyRequest >>= aLNLException) { ErrCode nErrorCode = ERRCODE_UUI_LOCKING_NOT_LOCKED; std::vector< rtl::OUString > aArguments; aArguments.push_back( aLNLException.Url ); handleErrorHandlerRequest( aLNLException.Classification, nErrorCode, aArguments, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString ); return true; } ucb::InteractiveLockingLockExpiredException aLLEException; if (aAnyRequest >>= aLLEException) { ErrCode nErrorCode = ERRCODE_UUI_LOCKING_LOCK_EXPIRED; std::vector< rtl::OUString > aArguments; aArguments.push_back( aLLEException.Url ); handleErrorHandlerRequest( aLLEException.Classification, nErrorCode, aArguments, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString ); return true; } document::BrokenPackageRequest aBrokenPackageRequest; if (aAnyRequest >>= aBrokenPackageRequest) { std::vector< rtl::OUString > aArguments; if( aBrokenPackageRequest.aName.getLength() ) aArguments.push_back( aBrokenPackageRequest.aName ); handleBrokenPackageRequest( aArguments, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString ); return true; } task::ErrorCodeRequest aErrorCodeRequest; if (aAnyRequest >>= aErrorCodeRequest) { handleGenericErrorRequest( aErrorCodeRequest.ErrCode, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString); return true; } task::ErrorCodeIOException aErrorCodeIOException; if (aAnyRequest >>= aErrorCodeIOException) { handleGenericErrorRequest( aErrorCodeIOException.ErrCode, rRequest->getContinuations(), bObtainErrorStringOnly, bHasErrorString, rErrorString); return true; } /////////////////////////////////////////////////////////////////// // Handle requests which do not have a plain string representation. /////////////////////////////////////////////////////////////////// if (!bObtainErrorStringOnly) { 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 ( handleCookiesRequest( rRequest ) ) return true; if ( handleNoSuchFilterRequest( rRequest ) ) return true; if ( handleAmbigousFilterRequest( rRequest ) ) return true; if ( handleFilterOptionsRequest( rRequest ) ) return true; if ( handleLockedDocumentRequest( rRequest ) ) return true; if ( handleChangedByOthersRequest( rRequest ) ) return true; if ( handleLockFileIgnoreRequest( rRequest ) ) return true; task::DocumentMacroConfirmationRequest aMacroConfirmRequest; if (aAnyRequest >>= aMacroConfirmRequest) { handleMacroConfirmRequest( aMacroConfirmRequest.DocumentURL, aMacroConfirmRequest.DocumentStorage, aMacroConfirmRequest.DocumentVersion.getLength() ? aMacroConfirmRequest.DocumentVersion : ODFVER_012_TEXT, aMacroConfirmRequest.DocumentSignatureInformation, rRequest->getContinuations()); return true; } task::FutureDocumentVersionProductUpdateRequest aProductUpdateRequest; if (aAnyRequest >>= aProductUpdateRequest) { handleFutureDocumentVersionUpdateRequest( aProductUpdateRequest, 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 (std::bad_alloc const &) { throw uno::RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("out of memory")), uno::Reference< uno::XInterface >()); } catch( const uno::RuntimeException& ) { throw; // allowed to leave here } catch( const uno::Exception& ) { DBG_UNHANDLED_EXCEPTION(); } return false; } void UUIInteractionHelper::getInteractionHandlerList( InteractionHandlerDataList &rdataList) SAL_THROW((uno::RuntimeException)) { try { uno::Reference< lang::XMultiServiceFactory > xConfigProv( m_xServiceFactory->createInstance( rtl::OUString::createFromAscii( "com.sun.star.configuration.ConfigurationProvider" ) ), uno::UNO_QUERY ); if ( !xConfigProv.is() ) throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "unable to instanciate config provider service")), uno::Reference< uno::XInterface >()); rtl::OUStringBuffer aFullPath; aFullPath.appendAscii( "/org.openoffice.ucb.InteractionHandler/InteractionHandlers" ); uno::Sequence< uno::Any > aArguments( 1 ); beans::PropertyValue aProperty; aProperty.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ); aProperty.Value <<= aFullPath.makeStringAndClear(); aArguments[ 0 ] <<= aProperty; uno::Reference< uno::XInterface > xInterface( xConfigProv->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationAccess" ) ), aArguments ) ); if ( !xInterface.is() ) throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "unable to instanciate config access")), uno::Reference< uno::XInterface >()); uno::Reference< container::XNameAccess > xNameAccess( xInterface, uno::UNO_QUERY ); if ( !xNameAccess.is() ) throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "config access does not implement XNameAccess")), uno::Reference< uno::XInterface >()); uno::Sequence< rtl::OUString > aElems = xNameAccess->getElementNames(); const rtl::OUString* pElems = aElems.getConstArray(); sal_Int32 nCount = aElems.getLength(); if ( nCount > 0 ) { uno::Reference< container::XHierarchicalNameAccess > xHierNameAccess( xInterface, uno::UNO_QUERY ); if ( !xHierNameAccess.is() ) throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "config access does not implement XHierarchicalNameAccess")), uno::Reference< uno::XInterface >()); // Iterate over children. for ( sal_Int32 n = 0; n < nCount; ++n ) { rtl::OUStringBuffer aElemBuffer; aElemBuffer.appendAscii( "['" ); aElemBuffer.append( pElems[ n ] ); try { InteractionHandlerData aInfo; // Obtain service name. rtl::OUStringBuffer aKeyBuffer = aElemBuffer; aKeyBuffer.appendAscii( "']/ServiceName" ); rtl::OUString aValue; if ( !( xHierNameAccess->getByHierarchicalName( aKeyBuffer.makeStringAndClear() ) >>= aValue ) ) { OSL_ENSURE( false, "GetInteractionHandlerList - " "Error getting item value!" ); continue; } aInfo.ServiceName = aValue; // Append info to list. rdataList.push_back( aInfo ); } catch ( container::NoSuchElementException& ) { // getByHierarchicalName OSL_ENSURE( false, "GetInteractionHandlerList - " "caught NoSuchElementException!" ); } } } } catch ( uno::RuntimeException const & ) { throw; } catch ( uno::Exception const & ) { OSL_ENSURE( false, "GetInteractionHandlerList - Caught Exception!" ); } } Window * UUIInteractionHelper::getParentProperty() SAL_THROW(()) { uno::Reference< awt::XWindow > xWindow = getParentXWindow(); if ( xWindow.is() ) return VCLUnoHelper::GetWindow(xWindow); return 0; } uno::Reference< awt::XWindow> UUIInteractionHelper::getParentXWindow() const SAL_THROW(()) { osl::MutexGuard aGuard(m_aPropertyMutex); ::comphelper::NamedValueCollection aProperties( m_aProperties ); if ( aProperties.has( "Parent" ) ) { uno::Reference< awt::XWindow > xWindow; OSL_VERIFY( aProperties.get( "Parent" ) >>= xWindow ); return xWindow; } return 0; } rtl::OUString UUIInteractionHelper::getContextProperty() SAL_THROW(()) { osl::MutexGuard aGuard(m_aPropertyMutex); for (sal_Int32 i = 0; i < m_aProperties.getLength(); ++i) { beans::PropertyValue aProperty; if ((m_aProperties[i] >>= aProperty) && aProperty. Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Context"))) { rtl::OUString aContext; aProperty.Value >>= aContext; return aContext; } } return rtl::OUString(); } uno::Reference< task::XInteractionHandler > UUIInteractionHelper::getInteractionHandler() SAL_THROW((uno::RuntimeException)) { uno::Reference< task::XInteractionHandler > xIH; try { xIH.set(m_xServiceFactory->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.task.InteractionHandler")), m_aProperties), uno::UNO_QUERY); } catch (uno::Exception const &) {} if (!xIH.is()) throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "unable to instanciate Interaction Handler service")), uno::Reference< uno::XInterface >()); return xIH; } namespace { sal_uInt16 executeMessageBox( Window * pParent, rtl::OUString const & rTitle, rtl::OUString const & rMessage, WinBits nButtonMask ) SAL_THROW((uno::RuntimeException)) { vos::OGuard aGuard(Application::GetSolarMutex()); MessBox xBox( pParent, nButtonMask, rTitle, rMessage ); sal_uInt16 aResult = xBox.Execute(); switch( aResult ) { case BUTTONID_OK: aResult = ERRCODE_BUTTON_OK; break; case BUTTONID_CANCEL: aResult = ERRCODE_BUTTON_CANCEL; break; case BUTTONID_YES: aResult = ERRCODE_BUTTON_YES; break; case BUTTONID_NO: aResult = ERRCODE_BUTTON_NO; break; case BUTTONID_RETRY: aResult = ERRCODE_BUTTON_RETRY; break; } return aResult; } NameClashResolveDialogResult executeSimpleNameClashResolveDialog( Window *pParent, rtl::OUString const & rTargetFolderURL, rtl::OUString const & rClashingName, rtl::OUString & rProposedNewName, bool bAllowOverwrite ) { std::auto_ptr< ResMgr > xManager( ResMgr::CreateResMgr( CREATEVERSIONRESMGR_NAME( uui ) ) ); if ( !xManager.get() ) return ABORT; NameClashDialog aDialog( pParent, xManager.get(), rTargetFolderURL, rClashingName, rProposedNewName, bAllowOverwrite ); NameClashResolveDialogResult eResult = (NameClashResolveDialogResult) aDialog.Execute(); rProposedNewName = aDialog.getNewName(); return eResult; } } // namespace void UUIInteractionHelper::handleNameClashResolveRequest( ucb::NameClashResolveRequest const & rRequest, uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & rContinuations) SAL_THROW((uno::RuntimeException)) { OSL_ENSURE( rRequest.TargetFolderURL.getLength() > 0, "NameClashResolveRequest must not contain empty TargetFolderURL" ); OSL_ENSURE( rRequest.ClashingName.getLength() > 0, "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; rtl::OUString aProposedNewName( rRequest.ProposedNewName ); eResult = executeSimpleNameClashResolveDialog( getParentProperty(), 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( sal_Int32 nErrorCode, uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & rContinuations, bool bObtainErrorStringOnly, bool & bHasErrorString, rtl::OUString & rErrorString) SAL_THROW((uno::RuntimeException)) { if (bObtainErrorStringOnly) { bHasErrorString = isInformationalErrorMessageRequest(rContinuations); if (bHasErrorString) { String 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 = static_cast< ErrCode >(nErrorCode); sal_Bool bWarning = !ERRCODE_TOERROR(nError); if ( nError == ERRCODE_SFX_BROKENSIGNATURE || nError == ERRCODE_SFX_INCOMPLETE_ENCRYPTION ) { // the security warning box needs a special title String aErrorString; ErrorHandler::GetErrorString( nErrorCode, aErrorString ); std::auto_ptr< ResMgr > xManager( ResMgr::CreateResMgr( CREATEVERSIONRESMGR_NAME( uui ) ) ); ::rtl::OUString aTitle; try { uno::Any aProductNameAny = ::utl::ConfigManager::GetConfigManager() ->GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTNAME ); aProductNameAny >>= aTitle; } catch( uno::Exception& ) { } ::rtl::OUString aErrTitle = String( ResId( nError == ERRCODE_SFX_BROKENSIGNATURE ? STR_WARNING_BROKENSIGNATURE_TITLE : STR_WARNING_INCOMPLETE_ENCRYPTION_TITLE, *xManager.get() ) ); if ( aTitle.getLength() && aErrTitle.getLength() ) aTitle += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( " - " ) ); aTitle += aErrTitle; executeMessageBox( getParentProperty(), aTitle, aErrorString, WB_OK ); } else ErrorHandler::HandleError(nErrorCode); if (xApprove.is() && bWarning) xApprove->select(); else if (xAbort.is()) xAbort->select(); } } void UUIInteractionHelper::handleMacroConfirmRequest( const ::rtl::OUString& aDocumentURL, const uno::Reference< embed::XStorage >& xZipStorage, const ::rtl::OUString& aDocumentVersion, const uno::Sequence< security::DocumentSignatureInformation > aSignInfo, uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & rContinuations ) SAL_THROW((uno::RuntimeException)) { uno::Reference< task::XInteractionAbort > xAbort; uno::Reference< task::XInteractionApprove > xApprove; getContinuations( rContinuations, &xApprove, &xAbort ); bool bApprove = false; std::auto_ptr< ResMgr > pResMgr( ResMgr::CreateResMgr( CREATEVERSIONRESMGR_NAME( uui ) ) ); if ( pResMgr.get() ) { bool bShowSignatures = aSignInfo.getLength() > 0; MacroWarning aWarning( getParentProperty(), bShowSignatures, *pResMgr.get() ); aWarning.SetDocumentURL( aDocumentURL ); if ( aSignInfo.getLength() > 1 ) { aWarning.SetStorage( xZipStorage, aDocumentVersion, aSignInfo ); } else if ( aSignInfo.getLength() == 1 ) { aWarning.SetCertificate( aSignInfo[ 0 ].Signer ); } bApprove = aWarning.Execute() == RET_OK; } if ( bApprove && xApprove.is() ) xApprove->select(); else if ( xAbort.is() ) xAbort->select(); } void UUIInteractionHelper::handleFutureDocumentVersionUpdateRequest( const task::FutureDocumentVersionProductUpdateRequest& _rRequest, uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & rContinuations ) SAL_THROW((uno::RuntimeException)) { uno::Reference< task::XInteractionAbort > xAbort; uno::Reference< task::XInteractionApprove > xApprove; uno::Reference< task::XInteractionAskLater > xAskLater; getContinuations( rContinuations, &xApprove, &xAbort, &xAskLater ); short nResult = RET_CANCEL; static bool s_bDeferredToNextSession = false; // TODO: this static variable is somewhat hacky. Formerly (before the dialog was moved from SFX2 to the // interaction handler implementation), this was stored in SFX_APP()'s impl structure, in member // bODFVersionWarningLater. Of course, we do not have access to it here. // // A proper solution which I would envision would be: // - There's a central implementation (this one here) of css.task.InteractionHandler // - There's a configuration which maps UNO names to service names // - If the handler is confronted with a request, it tries to find the name of the UNO structure describing // the request in the said configuration. // - If an entry is found, then // - the respective service is instantiated // - the component is queried for css.task.XInteractionHandler, and the request is delegated // - if no entry is found, then the request is silenced (with calling the AbortContinuation, if possible) // This way, the FutureDocumentVersionProductUpdateRequest could be handled in SFX (or any other // suitable place), again, and we would only have one place where we remember the s_bDeferredToNextSession // flag. // // Note: The above pattern has been implemented in CWS autorecovery. Now the remaining task is to move the // handling of this interaction to SFX, again. if ( !s_bDeferredToNextSession ) { std::auto_ptr< ResMgr > pResMgr( ResMgr::CreateResMgr( CREATEVERSIONRESMGR_NAME( uui ) ) ); if ( pResMgr.get() ) { ::uui::NewerVersionWarningDialog aDialog( getParentProperty(), _rRequest.DocumentODFVersion, *pResMgr.get() ); nResult = aDialog.Execute(); } } switch ( nResult ) { case RET_OK: if ( xApprove.is() ) xApprove->select(); break; case RET_CANCEL: if ( xAbort.is() ) xAbort->select(); break; case RET_ASK_LATER: if ( xAskLater.is() ) xAskLater->select(); s_bDeferredToNextSession = true; break; default: OSL_ENSURE( false, "UUIInteractionHelper::handleFutureDocumentVersionUpdateRequest: " "unexpected dialog return value!" ); break; } } void UUIInteractionHelper::handleBrokenPackageRequest( std::vector< rtl::OUString > const & rArguments, uno::Sequence< uno::Reference< task::XInteractionContinuation > > const & rContinuations, bool bObtainErrorStringOnly, bool & bHasErrorString, rtl::OUString & rErrorString) SAL_THROW((uno::RuntimeException)) { 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; ::rtl::OUString aMessage; { vos::OGuard aGuard(Application::GetSolarMutex()); std::auto_ptr< ResMgr > xManager( ResMgr::CreateResMgr(CREATEVERSIONRESMGR_NAME(uui))); if (!xManager.get()) return; ResId aResId( RID_UUI_ERRHDL, *xManager.get() ); if ( !ErrorResource(aResId).getString(nErrorCode, &aMessage) ) return; } aMessage = replaceMessageWithArguments( aMessage, rArguments ); if (bObtainErrorStringOnly) { rErrorString = aMessage; return; } WinBits nButtonMask; if( xApprove.is() && xDisapprove.is() ) { nButtonMask = WB_YES_NO | WB_DEF_YES; } else if ( xAbort.is() ) { nButtonMask = WB_OK; } else return; uno::Any aProductNameAny = ::utl::ConfigManager::GetConfigManager()->GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTNAME ); uno::Any aProductVersionAny = ::utl::ConfigManager::GetConfigManager()->GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTVERSION ); ::rtl::OUString aProductName, aProductVersion; if ( !( aProductNameAny >>= aProductName ) ) aProductName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarOffice") ); ::rtl::OUString aTitle( aProductName ); if( aProductVersionAny >>= aProductVersion ) { aTitle += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(" ") ); aTitle += aProductVersion; } switch ( executeMessageBox( getParentProperty(), aTitle, aMessage, nButtonMask )) { case ERRCODE_BUTTON_OK: OSL_ENSURE( xAbort.is(), "unexpected situation" ); if (xAbort.is()) xAbort->select(); break; case ERRCODE_BUTTON_NO: OSL_ENSURE(xDisapprove.is(), "unexpected situation"); if (xDisapprove.is()) xDisapprove->select(); break; case ERRCODE_BUTTON_YES: OSL_ENSURE(xApprove.is(), "unexpected situation"); if (xApprove.is()) xApprove->select(); break; } } //========================================================================= // ErrorResource Implementation //========================================================================= bool ErrorResource::getString(ErrCode nErrorCode, rtl::OUString * pString) const SAL_THROW(()) { OSL_ENSURE(pString, "specification violation"); ResId aResId(static_cast< sal_uInt16 >(nErrorCode & ERRCODE_RES_MASK), *m_pResMgr); aResId.SetRT(RSC_STRING); if (!IsAvailableRes(aResId)) return false; aResId.SetAutoRelease(false); *pString = UniString(aResId); m_pResMgr->PopContext(); return true; }