Branch libreoffice-5-0-4
[LibreOffice.git] / scripting / source / protocolhandler / scripthandler.cxx
blob3c2a9dff652ca619e3baae5f80bbc945ad84d8f5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scripthandler.hxx"
22 #include <osl/mutex.hxx>
24 #include <com/sun/star/frame/DispatchResultEvent.hpp>
25 #include <com/sun/star/frame/DispatchResultState.hpp>
26 #include <com/sun/star/frame/XController.hpp>
27 #include <com/sun/star/frame/XModel.hpp>
29 #include <com/sun/star/document/XEmbeddedScripts.hpp>
30 #include <com/sun/star/document/XScriptInvocationContext.hpp>
32 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
34 #include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
35 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
36 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
38 #include <sfx2/objsh.hxx>
39 #include <sfx2/frame.hxx>
40 #include <sfx2/sfxdlg.hxx>
41 #include <vcl/abstdlg.hxx>
42 #include <tools/diagnose_ex.h>
44 #include <comphelper/processfactory.hxx>
45 #include <cppuhelper/factory.hxx>
46 #include <cppuhelper/exc_hlp.hxx>
47 #include <cppuhelper/supportsservice.hxx>
48 #include <framework/documentundoguard.hxx>
50 #include "com/sun/star/uno/XComponentContext.hpp"
51 #include "com/sun/star/uri/XUriReference.hpp"
52 #include "com/sun/star/uri/UriReferenceFactory.hpp"
53 #include "com/sun/star/uri/XVndSunStarScriptUrl.hpp"
55 #include <boost/scoped_ptr.hpp>
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::frame;
60 using namespace ::com::sun::star::util;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::script;
64 using namespace ::com::sun::star::script::provider;
65 using namespace ::com::sun::star::document;
67 namespace scripting_protocolhandler
70 const sal_Char * const MYSERVICENAME = "com.sun.star.frame.ProtocolHandler";
71 const sal_Char * const MYIMPLNAME = "com.sun.star.comp.ScriptProtocolHandler";
73 void SAL_CALL ScriptProtocolHandler::initialize(
74 const css::uno::Sequence < css::uno::Any >& aArguments )
75 throw ( css::uno::Exception, std::exception )
77 if ( m_bInitialised )
79 return ;
82 // first argument contains a reference to the frame (may be empty or the desktop,
83 // but usually it's a "real" frame)
84 if ( aArguments.getLength() && !( aArguments[ 0 ] >>= m_xFrame ) )
86 OUString temp = "ScriptProtocolHandler::initialize: could not extract reference to the frame";
87 throw RuntimeException( temp );
90 ENSURE_OR_THROW( m_xContext.is(), "ScriptProtocolHandler::initialize: No Service Manager available" );
91 m_bInitialised = true;
94 Reference< XDispatch > SAL_CALL ScriptProtocolHandler::queryDispatch(
95 const URL& aURL, const OUString& sTargetFrameName, sal_Int32 nSearchFlags )
96 throw( ::com::sun::star::uno::RuntimeException, std::exception )
98 (void)sTargetFrameName;
99 (void)nSearchFlags;
101 Reference< XDispatch > xDispatcher;
102 // get scheme of url
104 Reference< uri::XUriReferenceFactory > xFac = uri::UriReferenceFactory::create( m_xContext );
105 Reference< uri::XUriReference > uriRef(
106 xFac->parse( aURL.Complete ), UNO_QUERY );
107 if ( uriRef.is() )
109 if ( uriRef->getScheme() == "vnd.sun.star.script" )
111 xDispatcher = this;
115 return xDispatcher;
118 Sequence< Reference< XDispatch > > SAL_CALL
119 ScriptProtocolHandler::queryDispatches(
120 const Sequence < DispatchDescriptor >& seqDescriptor )
121 throw( RuntimeException, std::exception )
123 sal_Int32 nCount = seqDescriptor.getLength();
124 Sequence< Reference< XDispatch > > lDispatcher( nCount );
125 for ( sal_Int32 i = 0; i < nCount; ++i )
127 lDispatcher[ i ] = this->queryDispatch( seqDescriptor[ i ].FeatureURL,
128 seqDescriptor[ i ].FrameName,
129 seqDescriptor[ i ].SearchFlags );
131 return lDispatcher;
134 void SAL_CALL ScriptProtocolHandler::dispatchWithNotification(
135 const URL& aURL, const Sequence < PropertyValue >& lArgs,
136 const Reference< XDispatchResultListener >& xListener )
137 throw ( RuntimeException, std::exception )
140 bool bSuccess = false;
141 Any invokeResult;
142 bool bCaughtException = false;
143 Any aException;
145 if ( m_bInitialised )
149 bool bIsDocumentScript = ( aURL.Complete.indexOf( "document" ) !=-1 );
150 // TODO: isn't this somewhat strange? This should be a test for a location=document parameter, shouldn't it?
152 if ( bIsDocumentScript )
154 // obtain the component for our security check
155 Reference< XEmbeddedScripts > xDocumentScripts;
156 if ( getScriptInvocation() )
157 xDocumentScripts.set( m_xScriptInvocation->getScriptContainer(), UNO_SET_THROW );
159 OSL_ENSURE( xDocumentScripts.is(), "ScriptProtocolHandler::dispatchWithNotification: can't do the security check!" );
160 if ( !xDocumentScripts.is() || !xDocumentScripts->getAllowMacroExecution() )
162 if ( xListener.is() )
164 ::com::sun::star::frame::DispatchResultEvent aEvent(
165 static_cast< ::cppu::OWeakObject* >( this ),
166 ::com::sun::star::frame::DispatchResultState::FAILURE,
167 invokeResult );
170 xListener->dispatchFinished( aEvent ) ;
172 catch(RuntimeException & e)
174 OSL_TRACE(
175 "ScriptProtocolHandler::dispatchWithNotification: caught RuntimeException"
176 "while dispatchFinished with failture of the execution %s",
177 ::rtl::OUStringToOString( e.Message,
178 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
181 return;
185 // Creates a ScriptProvider ( if one is not created already )
186 createScriptProvider();
188 Reference< provider::XScript > xFunc =
189 m_xScriptProvider->getScript( aURL.Complete );
190 ENSURE_OR_THROW( xFunc.is(),
191 "ScriptProtocolHandler::dispatchWithNotification: validate xFunc - unable to obtain XScript interface" );
194 Sequence< Any > inArgs( 0 );
195 Sequence< Any > outArgs( 0 );
196 Sequence< sal_Int16 > outIndex;
198 if ( lArgs.getLength() > 0 )
200 int argCount = 0;
201 for ( int index = 0; index < lArgs.getLength(); index++ )
203 // Sometimes we get a propertyval with name = "Referer"
204 // this is not an argument to be passed to script, so
205 // ignore.
206 if ( lArgs[ index ].Name != "Referer" ||
207 lArgs[ index ].Name.isEmpty() ) //TODO:???
209 inArgs.realloc( ++argCount );
210 inArgs[ argCount - 1 ] = lArgs[ index ].Value;
215 // attempt to protect the document against the script tampering with its Undo Context
216 boost::scoped_ptr< ::framework::DocumentUndoGuard > pUndoGuard;
217 if ( bIsDocumentScript )
218 pUndoGuard.reset( new ::framework::DocumentUndoGuard( m_xScriptInvocation ) );
220 bSuccess = false;
221 while ( !bSuccess )
223 Any aFirstCaughtException;
226 invokeResult = xFunc->invoke( inArgs, outIndex, outArgs );
227 bSuccess = true;
229 catch( const provider::ScriptFrameworkErrorException& se )
231 if ( !aFirstCaughtException.hasValue() )
232 aFirstCaughtException = ::cppu::getCaughtException();
234 if ( se.errorType != provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT )
235 // the only condition which allows us to retry is if there is no method with the
236 // given name/signature
237 ::cppu::throwException( aFirstCaughtException );
239 if ( inArgs.getLength() == 0 )
240 // no chance to retry if we can't strip more in-args
241 ::cppu::throwException( aFirstCaughtException );
243 // strip one argument, then retry
244 inArgs.realloc( inArgs.getLength() - 1 );
248 // Office doesn't handle exceptions rethrown here very well, it cores,
249 // all we can is log them and then set fail for the dispatch event!
250 // (if there is a listener of course)
251 catch ( const Exception & e )
253 aException = ::cppu::getCaughtException();
255 OUString reason = "ScriptProtocolHandler::dispatch: caught ";
257 invokeResult <<= reason.concat( aException.getValueTypeName() ).concat( e.Message );
259 bCaughtException = true;
262 else
264 OUString reason(
265 "ScriptProtocolHandler::dispatchWithNotification failed, ScriptProtocolHandler not initialised"
267 invokeResult <<= reason;
270 if ( bCaughtException )
272 SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
274 if ( pFact != NULL )
276 boost::scoped_ptr<VclAbstractDialog> pDlg(
277 pFact->CreateScriptErrorDialog( NULL, aException ));
279 if ( pDlg )
280 pDlg->Execute();
284 if ( xListener.is() )
286 // always call dispatchFinished(), because we didn't load a document but
287 // executed a macro instead!
288 ::com::sun::star::frame::DispatchResultEvent aEvent;
290 aEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
291 aEvent.Result = invokeResult;
292 if ( bSuccess )
294 aEvent.State = ::com::sun::star::frame::DispatchResultState::SUCCESS;
296 else
298 aEvent.State = ::com::sun::star::frame::DispatchResultState::FAILURE;
303 xListener->dispatchFinished( aEvent ) ;
305 catch(const RuntimeException & e)
307 OSL_TRACE(
308 "ScriptProtocolHandler::dispatchWithNotification: caught RuntimeException"
309 "while dispatchFinished %s",
310 OUStringToOString( e.Message,
311 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
316 void SAL_CALL ScriptProtocolHandler::dispatch(
317 const URL& aURL, const Sequence< PropertyValue >& lArgs )
318 throw ( RuntimeException, std::exception )
320 dispatchWithNotification( aURL, lArgs, Reference< XDispatchResultListener >() );
323 void SAL_CALL ScriptProtocolHandler::addStatusListener(
324 const Reference< XStatusListener >& xControl, const URL& aURL )
325 throw ( RuntimeException, std::exception )
327 (void)xControl;
328 (void)aURL;
330 // implement if status is supported
333 void SAL_CALL ScriptProtocolHandler::removeStatusListener(
334 const Reference< XStatusListener >& xControl, const URL& aURL )
335 throw ( RuntimeException, std::exception )
337 (void)xControl;
338 (void)aURL;
341 bool
342 ScriptProtocolHandler::getScriptInvocation()
344 if ( !m_xScriptInvocation.is() && m_xFrame.is() )
346 Reference< XController > xController = m_xFrame->getController();
347 if ( xController .is() )
349 // try to obtain an XScriptInvocationContext interface, preferred from the
350 // mode, then from the controller
351 if ( !m_xScriptInvocation.set( xController->getModel(), UNO_QUERY ) )
352 m_xScriptInvocation.set( xController, UNO_QUERY );
354 else
356 Reference< XFrame > xFrame( m_xFrame.get(), UNO_QUERY );
357 if ( xFrame.is() )
359 SfxFrame* pFrame = NULL;
360 for ( pFrame = SfxFrame::GetFirst(); pFrame; pFrame = SfxFrame::GetNext( *pFrame ) )
362 if ( pFrame->GetFrameInterface() == xFrame )
363 break;
365 SfxObjectShell* pDocShell = pFrame ? pFrame->GetCurrentDocument() : SfxObjectShell::Current();
366 if ( pDocShell )
368 Reference< XModel > xModel( pDocShell->GetModel() );
369 m_xScriptInvocation.set( xModel, UNO_QUERY );
374 return m_xScriptInvocation.is();
377 void ScriptProtocolHandler::createScriptProvider()
379 if ( m_xScriptProvider.is() )
380 return;
384 // first, ask the component supporting the XScriptInvocationContext interface
385 // (if there is one) for a script provider
386 if ( getScriptInvocation() )
388 Reference< XScriptProviderSupplier > xSPS( m_xScriptInvocation, UNO_QUERY );
389 if ( xSPS.is() )
390 m_xScriptProvider = xSPS->getScriptProvider();
393 // second, ask the model in our frame
394 if ( !m_xScriptProvider.is() && m_xFrame.is() )
396 Reference< XController > xController = m_xFrame->getController();
397 if ( xController .is() )
399 Reference< XScriptProviderSupplier > xSPS( xController->getModel(), UNO_QUERY );
400 if ( xSPS.is() )
401 m_xScriptProvider = xSPS->getScriptProvider();
406 // as a fallback, ask the controller
407 if ( !m_xScriptProvider.is() && m_xFrame.is() )
409 Reference< XScriptProviderSupplier > xSPS( m_xFrame->getController(), UNO_QUERY );
410 if ( xSPS.is() )
411 m_xScriptProvider = xSPS->getScriptProvider();
414 // if nothing of this is successful, use the master script provider
415 if ( !m_xScriptProvider.is() )
417 Reference< provider::XScriptProviderFactory > xFac =
418 provider::theMasterScriptProviderFactory::get( m_xContext );
420 Any aContext;
421 if ( getScriptInvocation() )
422 aContext = makeAny( m_xScriptInvocation );
423 m_xScriptProvider = Reference< provider::XScriptProvider > (
424 xFac->createScriptProvider( aContext ), UNO_QUERY_THROW );
427 catch ( const RuntimeException & e )
429 OUString temp = "ScriptProtocolHandler::createScriptProvider(), ";
430 throw RuntimeException( temp.concat( e.Message ) );
432 catch ( const Exception & e )
434 OUString temp = "ScriptProtocolHandler::createScriptProvider: ";
435 throw RuntimeException( temp.concat( e.Message ) );
439 ScriptProtocolHandler::ScriptProtocolHandler( const Reference< css::uno::XComponentContext > & xContext )
440 : m_bInitialised( false ), m_xContext( xContext )
444 ScriptProtocolHandler::~ScriptProtocolHandler()
448 /* XServiceInfo */
449 OUString SAL_CALL ScriptProtocolHandler::getImplementationName( )
450 throw( RuntimeException, std::exception )
452 return impl_getStaticImplementationName();
455 /* XServiceInfo */
456 sal_Bool SAL_CALL ScriptProtocolHandler::supportsService(const OUString& sServiceName )
457 throw( RuntimeException, std::exception )
459 return cppu::supportsService(this, sServiceName);
462 /* XServiceInfo */
463 Sequence< OUString > SAL_CALL ScriptProtocolHandler::getSupportedServiceNames()
464 throw( RuntimeException, std::exception )
466 return impl_getStaticSupportedServiceNames();
469 /* Helper for XServiceInfo */
470 Sequence< OUString > ScriptProtocolHandler::impl_getStaticSupportedServiceNames()
472 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
473 Sequence< OUString > seqServiceNames( 1 );
474 seqServiceNames.getArray() [ 0 ] =
475 OUString::createFromAscii( ::scripting_protocolhandler::MYSERVICENAME );
476 return seqServiceNames ;
479 /* Helper for XServiceInfo */
480 OUString ScriptProtocolHandler::impl_getStaticImplementationName()
482 return OUString::createFromAscii( ::scripting_protocolhandler::MYIMPLNAME );
485 /* Helper for registry */
486 Reference< XInterface > SAL_CALL ScriptProtocolHandler::impl_createInstance(
487 const Reference< css::lang::XMultiServiceFactory >& xServiceManager )
488 throw( RuntimeException )
490 return Reference< XInterface > ( *new ScriptProtocolHandler( comphelper::getComponentContext(xServiceManager) ) );
493 /* Factory for registration */
494 Reference< XSingleServiceFactory > ScriptProtocolHandler::impl_createFactory(
495 const Reference< XMultiServiceFactory >& xServiceManager )
497 Reference< XSingleServiceFactory > xReturn (
498 cppu::createSingleFactory( xServiceManager,
499 ScriptProtocolHandler::impl_getStaticImplementationName(),
500 ScriptProtocolHandler::impl_createInstance,
501 ScriptProtocolHandler::impl_getStaticSupportedServiceNames() )
503 return xReturn;
506 } // namespace scripting_protocolhandler
508 extern "C"
510 SAL_DLLPUBLIC_EXPORT void* SAL_CALL protocolhandler_component_getFactory( const sal_Char * pImplementationName ,
511 void * pServiceManager ,
512 void * pRegistryKey )
514 (void)pRegistryKey;
516 // Set default return value for this operation - if it failed.
517 void * pReturn = NULL ;
519 if (
520 ( pImplementationName != NULL ) &&
521 ( pServiceManager != NULL )
524 // Define variables which are used in following macros.
525 ::com::sun::star::uno::Reference<
526 ::com::sun::star::lang::XSingleServiceFactory > xFactory ;
527 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
528 xServiceManager( static_cast<
529 ::com::sun::star::lang::XMultiServiceFactory* >( pServiceManager ) ) ;
531 if ( ::scripting_protocolhandler::ScriptProtocolHandler::impl_getStaticImplementationName().equals(
532 OUString::createFromAscii( pImplementationName ) ) )
534 xFactory = ::scripting_protocolhandler::ScriptProtocolHandler::impl_createFactory( xServiceManager );
537 // Factory is valid - service was found.
538 if ( xFactory.is() )
540 xFactory->acquire();
541 pReturn = xFactory.get();
545 // Return with result of this operation.
546 return pReturn ;
548 } // extern "C"
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */