Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "scripthandler.hxx"
21 :
22 : #include <osl/mutex.hxx>
23 :
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>
28 :
29 : #include <com/sun/star/document/XEmbeddedScripts.hpp>
30 : #include <com/sun/star/document/XScriptInvocationContext.hpp>
31 :
32 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
33 :
34 : #include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
35 : #include <com/sun/star/script/provider/XScriptProviderFactory.hpp>
36 : #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
37 :
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>
43 :
44 : #include <comphelper/processfactory.hxx>
45 : #include <cppuhelper/factory.hxx>
46 : #include <cppuhelper/exc_hlp.hxx>
47 : #include <util/util.hxx>
48 : #include <framework/documentundoguard.hxx>
49 :
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"
54 :
55 : using namespace ::com::sun::star;
56 : using namespace ::com::sun::star::uno;
57 : using namespace ::com::sun::star::frame;
58 : using namespace ::com::sun::star::util;
59 : using namespace ::com::sun::star::beans;
60 : using namespace ::com::sun::star::lang;
61 : using namespace ::com::sun::star::script;
62 : using namespace ::com::sun::star::script::provider;
63 : using namespace ::com::sun::star::document;
64 :
65 : namespace scripting_protocolhandler
66 : {
67 :
68 : const sal_Char * const MYSERVICENAME = "com.sun.star.frame.ProtocolHandler";
69 : const sal_Char * const MYIMPLNAME = "com.sun.star.comp.ScriptProtocolHandler";
70 : const sal_Char * MYSCHEME = "vnd.sun.star.script";
71 : const sal_Int32 MYSCHEME_LEN = 20;
72 :
73 0 : void SAL_CALL ScriptProtocolHandler::initialize(
74 : const css::uno::Sequence < css::uno::Any >& aArguments )
75 : throw ( css::uno::Exception )
76 : {
77 0 : if ( m_bInitialised )
78 : {
79 0 : return ;
80 : }
81 :
82 : // first argument contains a reference to the frame (may be empty or the desktop,
83 : // but usually it's a "real" frame)
84 0 : if ( aArguments.getLength() &&
85 0 : sal_False == ( aArguments[ 0 ] >>= m_xFrame ) )
86 : {
87 0 : ::rtl::OUString temp = OUSTR( "ScriptProtocolHandler::initialize: could not extract reference to the frame" );
88 0 : throw RuntimeException( temp, Reference< XInterface >() );
89 : }
90 :
91 0 : ENSURE_OR_THROW( m_xFactory.is(), "ScriptProtocolHandler::initialize: No Service Manager available" );
92 0 : m_bInitialised = true;
93 : }
94 :
95 0 : Reference< XDispatch > SAL_CALL ScriptProtocolHandler::queryDispatch(
96 : const URL& aURL, const ::rtl::OUString& sTargetFrameName, sal_Int32 nSearchFlags )
97 : throw( ::com::sun::star::uno::RuntimeException )
98 : {
99 : (void)sTargetFrameName;
100 : (void)nSearchFlags;
101 :
102 0 : Reference< XDispatch > xDispatcher;
103 : // get scheme of url
104 :
105 0 : Reference< uri::XUriReferenceFactory > xFac = uri::UriReferenceFactory::create( comphelper::getComponentContext(m_xFactory) );
106 : Reference< uri::XUriReference > uriRef(
107 0 : xFac->parse( aURL.Complete ), UNO_QUERY );
108 0 : if ( uriRef.is() )
109 : {
110 0 : if ( uriRef->getScheme().equals( ::rtl::OUString::createFromAscii( ::scripting_protocolhandler::MYSCHEME ) ) )
111 : {
112 0 : xDispatcher = this;
113 : }
114 : }
115 :
116 0 : return xDispatcher;
117 : }
118 :
119 : Sequence< Reference< XDispatch > > SAL_CALL
120 0 : ScriptProtocolHandler::queryDispatches(
121 : const Sequence < DispatchDescriptor >& seqDescriptor )
122 : throw( RuntimeException )
123 : {
124 0 : sal_Int32 nCount = seqDescriptor.getLength();
125 0 : Sequence< Reference< XDispatch > > lDispatcher( nCount );
126 0 : for ( sal_Int32 i = 0; i < nCount; ++i )
127 : {
128 0 : lDispatcher[ i ] = this->queryDispatch( seqDescriptor[ i ].FeatureURL,
129 0 : seqDescriptor[ i ].FrameName,
130 0 : seqDescriptor[ i ].SearchFlags );
131 : }
132 0 : return lDispatcher;
133 : }
134 :
135 0 : void SAL_CALL ScriptProtocolHandler::dispatchWithNotification(
136 : const URL& aURL, const Sequence < PropertyValue >& lArgs,
137 : const Reference< XDispatchResultListener >& xListener )
138 : throw ( RuntimeException )
139 : {
140 :
141 0 : sal_Bool bSuccess = sal_False;
142 0 : Any invokeResult;
143 0 : bool bCaughtException = sal_False;
144 0 : Any aException;
145 :
146 0 : if ( m_bInitialised )
147 : {
148 : try
149 : {
150 0 : bool bIsDocumentScript = ( aURL.Complete.indexOfAsciiL( RTL_CONSTASCII_STRINGPARAM( "document" ) ) !=-1 );
151 : // TODO: isn't this somewhat strange? This should be a test for a location=document parameter, shouldn't it?
152 :
153 0 : if ( bIsDocumentScript )
154 : {
155 : // obtain the component for our security check
156 0 : Reference< XEmbeddedScripts > xDocumentScripts;
157 0 : if ( getScriptInvocation() )
158 0 : xDocumentScripts.set( m_xScriptInvocation->getScriptContainer(), UNO_SET_THROW );
159 :
160 : OSL_ENSURE( xDocumentScripts.is(), "ScriptProtocolHandler::dispatchWithNotification: can't do the security check!" );
161 0 : if ( !xDocumentScripts.is() || !xDocumentScripts->getAllowMacroExecution() )
162 0 : return;
163 : }
164 :
165 : // Creates a ScriptProvider ( if one is not created allready )
166 0 : createScriptProvider();
167 :
168 : Reference< provider::XScript > xFunc =
169 0 : m_xScriptProvider->getScript( aURL.Complete );
170 0 : ENSURE_OR_THROW( xFunc.is(),
171 : "ScriptProtocolHandler::dispatchWithNotification: validate xFunc - unable to obtain XScript interface" );
172 :
173 :
174 0 : Sequence< Any > inArgs( 0 );
175 0 : Sequence< Any > outArgs( 0 );
176 0 : Sequence< sal_Int16 > outIndex;
177 :
178 0 : if ( lArgs.getLength() > 0 )
179 : {
180 0 : int argCount = 0;
181 0 : for ( int index = 0; index < lArgs.getLength(); index++ )
182 : {
183 : // Sometimes we get a propertyval with name = "Referer"
184 : // this is not an argument to be passed to script, so
185 : // ignore.
186 0 : if ( lArgs[ index ].Name.compareToAscii("Referer") != 0 ||
187 0 : lArgs[ index ].Name.isEmpty() )
188 : {
189 0 : inArgs.realloc( ++argCount );
190 0 : inArgs[ argCount - 1 ] = lArgs[ index ].Value;
191 : }
192 : }
193 : }
194 :
195 : // attempt to protect the document against the script tampering with its Undo Context
196 0 : ::std::auto_ptr< ::framework::DocumentUndoGuard > pUndoGuard;
197 0 : if ( bIsDocumentScript )
198 0 : pUndoGuard.reset( new ::framework::DocumentUndoGuard( m_xScriptInvocation ) );
199 :
200 0 : bSuccess = sal_False;
201 0 : while ( !bSuccess )
202 : {
203 0 : Any aFirstCaughtException;
204 : try
205 : {
206 0 : invokeResult = xFunc->invoke( inArgs, outIndex, outArgs );
207 0 : bSuccess = sal_True;
208 : }
209 0 : catch( const provider::ScriptFrameworkErrorException& se )
210 : {
211 0 : if ( !aFirstCaughtException.hasValue() )
212 0 : aFirstCaughtException = ::cppu::getCaughtException();
213 :
214 0 : if ( se.errorType != provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT )
215 : // the only condition which allows us to retry is if there is no method with the
216 : // given name/signature
217 0 : ::cppu::throwException( aFirstCaughtException );
218 :
219 0 : if ( inArgs.getLength() == 0 )
220 : // no chance to retry if we can't strip more in-args
221 0 : ::cppu::throwException( aFirstCaughtException );
222 :
223 : // strip one argument, then retry
224 0 : inArgs.realloc( inArgs.getLength() - 1 );
225 : }
226 0 : }
227 : }
228 : // Office doesn't handle exceptions rethrown here very well, it cores,
229 : // all we can is log them and then set fail for the dispatch event!
230 : // (if there is a listener of course)
231 0 : catch ( const Exception & e )
232 : {
233 0 : aException = ::cppu::getCaughtException();
234 :
235 0 : ::rtl::OUString reason = ::rtl::OUString( "ScriptProtocolHandler::dispatch: caught " );
236 :
237 0 : invokeResult <<= reason.concat( aException.getValueTypeName() ).concat( e.Message );
238 :
239 0 : bCaughtException = sal_True;
240 : }
241 : }
242 : else
243 : {
244 : ::rtl::OUString reason(
245 : "ScriptProtocolHandler::dispatchWithNotification failed, ScriptProtocolHandler not initialised"
246 0 : );
247 0 : invokeResult <<= reason;
248 : }
249 :
250 0 : if ( bCaughtException )
251 : {
252 0 : SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
253 :
254 0 : if ( pFact != NULL )
255 : {
256 : VclAbstractDialog* pDlg =
257 0 : pFact->CreateScriptErrorDialog( NULL, aException );
258 :
259 0 : if ( pDlg != NULL )
260 : {
261 0 : pDlg->Execute();
262 0 : delete pDlg;
263 : }
264 : }
265 : }
266 :
267 0 : if ( xListener.is() )
268 : {
269 : // always call dispatchFinished(), because we didn't load a document but
270 : // executed a macro instead!
271 0 : ::com::sun::star::frame::DispatchResultEvent aEvent;
272 :
273 0 : aEvent.Source = static_cast< ::cppu::OWeakObject* >( this );
274 0 : aEvent.Result = invokeResult;
275 0 : if ( bSuccess )
276 : {
277 0 : aEvent.State = ::com::sun::star::frame::DispatchResultState::SUCCESS;
278 : }
279 : else
280 : {
281 0 : aEvent.State = ::com::sun::star::frame::DispatchResultState::FAILURE;
282 : }
283 :
284 : try
285 : {
286 0 : xListener->dispatchFinished( aEvent ) ;
287 : }
288 0 : catch(const RuntimeException & e)
289 : {
290 : OSL_TRACE(
291 : "ScriptProtocolHandler::dispatchWithNotification: caught RuntimeException"
292 : "while dispatchFinished %s",
293 : ::rtl::OUStringToOString( e.Message,
294 : RTL_TEXTENCODING_ASCII_US ).pData->buffer );
295 0 : }
296 0 : }
297 : }
298 :
299 0 : void SAL_CALL ScriptProtocolHandler::dispatch(
300 : const URL& aURL, const Sequence< PropertyValue >& lArgs )
301 : throw ( RuntimeException )
302 : {
303 0 : dispatchWithNotification( aURL, lArgs, Reference< XDispatchResultListener >() );
304 0 : }
305 :
306 0 : void SAL_CALL ScriptProtocolHandler::addStatusListener(
307 : const Reference< XStatusListener >& xControl, const URL& aURL )
308 : throw ( RuntimeException )
309 : {
310 : (void)xControl;
311 : (void)aURL;
312 :
313 : // implement if status is supported
314 0 : }
315 :
316 0 : void SAL_CALL ScriptProtocolHandler::removeStatusListener(
317 : const Reference< XStatusListener >& xControl, const URL& aURL )
318 : throw ( RuntimeException )
319 : {
320 : (void)xControl;
321 : (void)aURL;
322 0 : }
323 :
324 : bool
325 0 : ScriptProtocolHandler::getScriptInvocation()
326 : {
327 0 : if ( !m_xScriptInvocation.is() && m_xFrame.is() )
328 : {
329 0 : Reference< XController > xController = m_xFrame->getController();
330 0 : if ( xController .is() )
331 : {
332 : // try to obtain an XScriptInvocationContext interface, preferred from the
333 : // mode, then from the controller
334 0 : if ( !m_xScriptInvocation.set( xController->getModel(), UNO_QUERY ) )
335 0 : m_xScriptInvocation.set( xController, UNO_QUERY );
336 0 : }
337 : }
338 0 : return m_xScriptInvocation.is();
339 : }
340 :
341 0 : void ScriptProtocolHandler::createScriptProvider()
342 : {
343 0 : if ( m_xScriptProvider.is() )
344 0 : return;
345 :
346 : try
347 : {
348 : // first, ask the component supporting the XScriptInvocationContext interface
349 : // (if there is one) for a script provider
350 0 : if ( getScriptInvocation() )
351 : {
352 0 : Reference< XScriptProviderSupplier > xSPS( m_xScriptInvocation, UNO_QUERY );
353 0 : if ( xSPS.is() )
354 0 : m_xScriptProvider = xSPS->getScriptProvider();
355 : }
356 :
357 : // second, ask the model in our frame
358 0 : if ( !m_xScriptProvider.is() && m_xFrame.is() )
359 : {
360 0 : Reference< XController > xController = m_xFrame->getController();
361 0 : if ( xController .is() )
362 : {
363 0 : Reference< XScriptProviderSupplier > xSPS( xController->getModel(), UNO_QUERY );
364 0 : if ( xSPS.is() )
365 0 : m_xScriptProvider = xSPS->getScriptProvider();
366 0 : }
367 : }
368 :
369 :
370 : // as a fallback, ask the controller
371 0 : if ( !m_xScriptProvider.is() && m_xFrame.is() )
372 : {
373 0 : Reference< XScriptProviderSupplier > xSPS( m_xFrame->getController(), UNO_QUERY );
374 0 : if ( xSPS.is() )
375 0 : m_xScriptProvider = xSPS->getScriptProvider();
376 : }
377 :
378 : // if nothing of this is successful, use the master script provider
379 0 : if ( !m_xScriptProvider.is() )
380 : {
381 : Reference< XComponentContext > xCtx(
382 0 : comphelper::getComponentContext( m_xFactory ) );
383 :
384 : ::rtl::OUString tmspf(
385 0 : "/singletons/com.sun.star.script.provider.theMasterScriptProviderFactory");
386 :
387 : Reference< provider::XScriptProviderFactory > xFac(
388 0 : xCtx->getValueByName( tmspf ), UNO_QUERY_THROW );
389 :
390 0 : Any aContext;
391 0 : if ( getScriptInvocation() )
392 0 : aContext = makeAny( m_xScriptInvocation );
393 : m_xScriptProvider = Reference< provider::XScriptProvider > (
394 0 : xFac->createScriptProvider( aContext ), UNO_QUERY_THROW );
395 : }
396 : }
397 0 : catch ( const RuntimeException & e )
398 : {
399 0 : ::rtl::OUString temp = OUSTR( "ScriptProtocolHandler::createScriptProvider(), " );
400 0 : throw RuntimeException( temp.concat( e.Message ), Reference< XInterface >() );
401 : }
402 0 : catch ( const Exception & e )
403 : {
404 0 : ::rtl::OUString temp = OUSTR( "ScriptProtocolHandler::createScriptProvider: " );
405 0 : throw RuntimeException( temp.concat( e.Message ), Reference< XInterface >() );
406 : }
407 : }
408 :
409 0 : ScriptProtocolHandler::ScriptProtocolHandler(
410 : Reference< css::lang::XMultiServiceFactory > const& rFact ) :
411 0 : m_bInitialised( false ), m_xFactory( rFact )
412 : {
413 0 : }
414 :
415 0 : ScriptProtocolHandler::~ScriptProtocolHandler()
416 : {
417 0 : }
418 :
419 : /* XServiceInfo */
420 0 : ::rtl::OUString SAL_CALL ScriptProtocolHandler::getImplementationName( )
421 : throw( RuntimeException )
422 : {
423 0 : return impl_getStaticImplementationName();
424 : }
425 :
426 : /* XServiceInfo */
427 0 : sal_Bool SAL_CALL ScriptProtocolHandler::supportsService(
428 : const ::rtl::OUString& sServiceName )
429 : throw( RuntimeException )
430 : {
431 0 : Sequence< ::rtl::OUString > seqServiceNames = getSupportedServiceNames();
432 0 : const ::rtl::OUString* pArray = seqServiceNames.getConstArray();
433 0 : for ( sal_Int32 nCounter = 0; nCounter < seqServiceNames.getLength(); nCounter++ )
434 : {
435 0 : if ( pArray[ nCounter ] == sServiceName )
436 : {
437 0 : return sal_True ;
438 : }
439 : }
440 :
441 0 : return sal_False ;
442 : }
443 :
444 : /* XServiceInfo */
445 0 : Sequence< ::rtl::OUString > SAL_CALL ScriptProtocolHandler::getSupportedServiceNames()
446 : throw( RuntimeException )
447 : {
448 0 : return impl_getStaticSupportedServiceNames();
449 : }
450 :
451 : /* Helper for XServiceInfo */
452 0 : Sequence< ::rtl::OUString > ScriptProtocolHandler::impl_getStaticSupportedServiceNames()
453 : {
454 0 : ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
455 0 : Sequence< ::rtl::OUString > seqServiceNames( 1 );
456 : seqServiceNames.getArray() [ 0 ] =
457 0 : ::rtl::OUString::createFromAscii( ::scripting_protocolhandler::MYSERVICENAME );
458 0 : return seqServiceNames ;
459 : }
460 :
461 : /* Helper for XServiceInfo */
462 0 : ::rtl::OUString ScriptProtocolHandler::impl_getStaticImplementationName()
463 : {
464 0 : return ::rtl::OUString::createFromAscii( ::scripting_protocolhandler::MYIMPLNAME );
465 : }
466 :
467 : /* Helper for registry */
468 0 : Reference< XInterface > SAL_CALL ScriptProtocolHandler::impl_createInstance(
469 : const Reference< css::lang::XMultiServiceFactory >& xServiceManager )
470 : throw( RuntimeException )
471 : {
472 0 : return Reference< XInterface > ( *new ScriptProtocolHandler( xServiceManager ) );
473 : }
474 :
475 : /* Factory for registration */
476 0 : Reference< XSingleServiceFactory > ScriptProtocolHandler::impl_createFactory(
477 : const Reference< XMultiServiceFactory >& xServiceManager )
478 : {
479 : Reference< XSingleServiceFactory > xReturn (
480 : cppu::createSingleFactory( xServiceManager,
481 : ScriptProtocolHandler::impl_getStaticImplementationName(),
482 : ScriptProtocolHandler::impl_createInstance,
483 : ScriptProtocolHandler::impl_getStaticSupportedServiceNames() )
484 0 : );
485 0 : return xReturn;
486 : }
487 :
488 : } // namespace scripting_protocolhandler
489 :
490 : extern "C"
491 : {
492 0 : SAL_DLLPUBLIC_EXPORT void* SAL_CALL protocolhandler_component_getFactory( const sal_Char * pImplementationName ,
493 : void * pServiceManager ,
494 : void * pRegistryKey )
495 : {
496 : (void)pRegistryKey;
497 :
498 : // Set default return value for this operation - if it failed.
499 0 : void * pReturn = NULL ;
500 :
501 0 : if (
502 : ( pImplementationName != NULL ) &&
503 : ( pServiceManager != NULL )
504 : )
505 : {
506 : // Define variables which are used in following macros.
507 : ::com::sun::star::uno::Reference<
508 0 : ::com::sun::star::lang::XSingleServiceFactory > xFactory ;
509 : ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
510 : xServiceManager( reinterpret_cast<
511 0 : ::com::sun::star::lang::XMultiServiceFactory* >( pServiceManager ) ) ;
512 :
513 0 : if ( ::scripting_protocolhandler::ScriptProtocolHandler::impl_getStaticImplementationName().equals(
514 0 : ::rtl::OUString::createFromAscii( pImplementationName ) ) )
515 : {
516 0 : xFactory = ::scripting_protocolhandler::ScriptProtocolHandler::impl_createFactory( xServiceManager );
517 : }
518 :
519 : // Factory is valid - service was found.
520 0 : if ( xFactory.is() )
521 : {
522 0 : xFactory->acquire();
523 0 : pReturn = xFactory.get();
524 0 : }
525 : }
526 :
527 : // Return with result of this operation.
528 0 : return pReturn ;
529 : }
530 0 : } // extern "C"
531 :
532 :
533 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|