1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
)
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
;
101 Reference
< XDispatch
> xDispatcher
;
104 Reference
< uri::XUriReferenceFactory
> xFac
= uri::UriReferenceFactory::create( m_xContext
);
105 Reference
< uri::XUriReference
> uriRef(
106 xFac
->parse( aURL
.Complete
), UNO_QUERY
);
109 if ( uriRef
->getScheme() == "vnd.sun.star.script" )
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
);
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;
142 bool bCaughtException
= false;
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
,
170 xListener
->dispatchFinished( aEvent
) ;
172 catch(RuntimeException
& e
)
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
);
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 )
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
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
) );
223 Any aFirstCaughtException
;
226 invokeResult
= xFunc
->invoke( inArgs
, outIndex
, outArgs
);
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;
265 "ScriptProtocolHandler::dispatchWithNotification failed, ScriptProtocolHandler not initialised"
267 invokeResult
<<= reason
;
270 if ( bCaughtException
)
272 SfxAbstractDialogFactory
* pFact
= SfxAbstractDialogFactory::Create();
276 boost::scoped_ptr
<VclAbstractDialog
> pDlg(
277 pFact
->CreateScriptErrorDialog( NULL
, aException
));
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
;
294 aEvent
.State
= ::com::sun::star::frame::DispatchResultState::SUCCESS
;
298 aEvent
.State
= ::com::sun::star::frame::DispatchResultState::FAILURE
;
303 xListener
->dispatchFinished( aEvent
) ;
305 catch(const RuntimeException
& e
)
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
)
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
)
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
);
356 Reference
< XFrame
> xFrame( m_xFrame
.get(), UNO_QUERY
);
359 SfxFrame
* pFrame
= NULL
;
360 for ( pFrame
= SfxFrame::GetFirst(); pFrame
; pFrame
= SfxFrame::GetNext( *pFrame
) )
362 if ( pFrame
->GetFrameInterface() == xFrame
)
365 SfxObjectShell
* pDocShell
= pFrame
? pFrame
->GetCurrentDocument() : SfxObjectShell::Current();
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() )
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
);
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
);
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
);
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
);
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()
449 OUString SAL_CALL
ScriptProtocolHandler::getImplementationName( )
450 throw( RuntimeException
, std::exception
)
452 return impl_getStaticImplementationName();
456 sal_Bool SAL_CALL
ScriptProtocolHandler::supportsService(const OUString
& sServiceName
)
457 throw( RuntimeException
, std::exception
)
459 return cppu::supportsService(this, sServiceName
);
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() )
506 } // namespace scripting_protocolhandler
510 SAL_DLLPUBLIC_EXPORT
void* SAL_CALL
protocolhandler_component_getFactory( const sal_Char
* pImplementationName
,
511 void * pServiceManager
,
512 void * pRegistryKey
)
516 // Set default return value for this operation - if it failed.
517 void * pReturn
= NULL
;
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.
541 pReturn
= xFactory
.get();
545 // Return with result of this operation.
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */