1 /*************************************************************************
2 *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26 ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_scripting.hxx"
30 
31 #include <stdio.h>
32 
33 #include <cppuhelper/implementationentry.hxx>
34 #include <sal/config.h>
35 #include <rtl/uri.hxx>
36 
37 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
38 #include <com/sun/star/util/XMacroExpander.hpp>
39 #include <com/sun/star/lang/XComponent.hpp>
40 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/frame/XModel.hpp>
43 #include <drafts/com/sun/star/script/framework/storage/XScriptInfoAccess.hpp>
44 
45 #include "ScriptStorageManager.hxx"
46 #include <util/util.hxx>
47 #include <util/scriptingconstants.hxx>
48 #include <tools/diagnose_ex.h>
49 
50 using namespace ::rtl;
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::uno;
53 using namespace ::drafts::com::sun::star::script::framework;
54 
55 namespace scripting_impl
56 {
57 
58 static OUString s_implName =
59     ::rtl::OUString::createFromAscii(
60         "drafts.com.sun.star.script.framework.storage.ScriptStorageManager" );
61 static OUString s_serviceName =
62     ::rtl::OUString::createFromAscii(
63         "drafts.com.sun.star.script.framework.storage.ScriptStorageManager" );
64 static Sequence< OUString > s_serviceNames = Sequence< OUString >( &s_serviceName, 1 );
65 
66 //extern ::rtl_StandardModuleCount s_moduleCount = MODULE_COUNT_INIT;
67 //extern ::rtl_StandardModuleCount s_moduleCount;
68 
69 
70 //*************************************************************************
71 // ScriptStorageManager Constructor
72 ScriptStorageManager::ScriptStorageManager( const Reference<
73         XComponentContext > & xContext ) SAL_THROW ( ( RuntimeException ) )
74         : m_xContext( xContext, UNO_SET_THROW ), m_count( 0 ), m_securityMgr( xContext )
75 {
76     OSL_TRACE( "< ScriptStorageManager ctor called >\n" );
77     //s_moduleCount.modCnt.acquire( &s_moduleCount.modCnt );
78 
79     m_xMgr.set( m_xContext->getServiceManager(), UNO_SET_THROW );
80 
81     try
82     {
83         // obtain the macro expander singleton to use in determining the
84         // location of the application script storage
85         Reference< util::XMacroExpander > xME( m_xContext->getValueByName( OUString::createFromAscii(
86                                                    "/singletons/com.sun.star.util.theMacroExpander" ) ), UNO_QUERY_THROW );
87 
88         OUString base = OUString::createFromAscii(
89                             SAL_CONFIGFILE( "${$BRAND_BASE_DIR/program/bootstrap" ) );
90 
91         setupAppStorage( xME,
92                          base.concat( OUString::createFromAscii( "::BaseInstallation}/share" ) ),
93                          OUSTR( "SHARE" ) );
94         setupAppStorage( xME,
95                          base.concat( OUString::createFromAscii( "::UserInstallation}/user" ) ),
96                          OUSTR( "USER" ) );
97 
98     }
99     catch ( Exception & e )
100     {
101         throw RuntimeException( OUSTR( "ScriptStorageManager::ScriptStorageManager: " ).concat( e.Message ), Reference< XInterface >() );
102     }
103     OSL_ASSERT( m_count == 2 );
104 }
105 
106 //*************************************************************************
107 // ScriptStorageManager setupAppStorage
108 void
109 ScriptStorageManager::setupAppStorage(
110     const Reference< util::XMacroExpander > & xME,
111     const OUString & storageStr,
112     const OUString & appStr)
113 SAL_THROW ( ( RuntimeException ) )
114 {
115     try
116     {
117         Reference< ucb::XSimpleFileAccess > xSFA(
118             m_xMgr->createInstanceWithContext(
119                 OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
120                 m_xContext
121             ),
122             UNO_QUERY_THROW
123         );
124 
125         setupAnyStorage( xSFA, xME->expandMacros( storageStr ), appStr );
126     }
127     catch ( Exception & e )
128     {
129         throw RuntimeException(
130             OUSTR( "ScriptStorageManager::setupAppStorage: " ).concat( e.Message ),
131             Reference< XInterface >() );
132     }
133 }
134 
135 //*************************************************************************
136 // ScriptStorageManager setupAnyStorage
137 sal_Int32
138 ScriptStorageManager::setupAnyStorage(
139     const Reference< ucb::XSimpleFileAccess > & xSFA,
140     const OUString & storageStr,
141     const OUString & origStringURI )
142 SAL_THROW ( ( RuntimeException ) )
143 {
144     // Required for scope of fnc to protect all access read and writes to m_count
145     ::osl::Guard< ::osl::Mutex > aGuard( m_mutex );
146     try
147     {
148 
149         // create a ScriptingStorage using the SimpleFileAccess, the storageID
150         // (from the count), and the URL to the application's shared area
151         Sequence < Any > aArgs( 3 );
152         aArgs[ 0 ] <<= xSFA;
153         aArgs[ 1 ] <<= m_count;
154         aArgs[ 2 ] <<= storageStr;
155 
156         OSL_TRACE( "creating storage for: %s\n",
157                    ::rtl::OUStringToOString( storageStr,
158                                              RTL_TEXTENCODING_ASCII_US ).pData->buffer );
159 
160         Reference< XInterface > xInterface(
161             m_xMgr->createInstanceWithArgumentsAndContext(
162                 OUString::createFromAscii( "drafts.com.sun.star.script.framework.storage.ScriptStorage" ),
163                 aArgs,
164                 m_xContext
165             ),
166             UNO_QUERY_THROW
167         );
168 
169         // and place it in the hash_map. Increment the counter
170         m_ScriptStorageMap[ m_count++ ] = xInterface;
171         sal_Int32 sid =  m_count - 1;
172 
173         // create hash of original uri i.e. file:///home/users/docs/mydoc.sxw
174         // and storage id (sid) this will allow us to retrieve
175         // the sid based on the url of the document.
176         m_StorageIdOrigURIHash [ origStringURI ] = sid;
177         OSL_TRACE( "\tcreated with ID=%d\n", m_count - 1 );
178 
179     }
180     catch ( Exception & e )
181     {
182         throw RuntimeException(
183             OUSTR( "ScriptStorageManager::setupAnyStorage: " ).concat(
184                 e.Message ), Reference< XInterface >() );
185     }
186 
187     return m_count -1;
188 }
189 
190 //*************************************************************************
191 // ScriptStorageManager Destructor
192 ScriptStorageManager::~ScriptStorageManager()
193 SAL_THROW ( () )
194 {
195     OSL_TRACE( "< ScriptStorageManager dtor called >\n" );
196 //    s_moduleCount.modCnt.release( &s_moduleCount.modCnt );
197 }
198 
199 //*************************************************************************
200 // This method assumes that the XSimpleFileAccess knows it's on root URL
201 // and can be used with relative URLs
202 sal_Int32 SAL_CALL
203 ScriptStorageManager::createScriptStorage(
204     const Reference< ucb::XSimpleFileAccess >& xSFA )
205 throw ( RuntimeException )
206 {
207     OSL_TRACE( "** ==> ScriptStorageManager in createScriptingStorage\n" );
208     ENSURE_OR_THROW( xSFA.is(), "ScriptStorageManager::createScriptStorage: XSimpleFileAccess is not valid" );
209 
210     return setupAnyStorage( xSFA, ::rtl::OUString::createFromAscii( "" ),
211                             ::rtl::OUString::createFromAscii( "" ) );
212 }
213 
214 //*************************************************************************
215 sal_Int32 SAL_CALL
216 ScriptStorageManager::createScriptStorageWithURI(
217     const Reference< ucb::XSimpleFileAccess >& xSFA, const OUString & cStringURI )
218 throw ( RuntimeException )
219 {
220     OSL_TRACE( "** ==> ScriptStorageManager in createScriptingStorageWithURI\n" );
221     ENSURE_OR_THROW( xSFA.is(), "ScriptStorageManager::createScriptStorage: XSimpleFileAccess is not valid" );
222 
223     // related to issue 11866
224     // warning dialog gets launched when adding binding to script in doc
225     // workaround issue: no functionProvider created on doc open
226     // if NODIALOG tag, strip from stringURI, set boolean=true
227     bool displayDialog = true;
228     ::rtl::OUString dialogTag = ::rtl::OUString::createFromAscii( "NoDialog::" );
229     ::rtl::OUString stringURI = cStringURI;
230     if( stringURI.indexOf( dialogTag ) == 0 )
231     {
232         OSL_TRACE( "ScriptStorageManager::createScriptStorage: will not display security dialogs" );
233         stringURI = stringURI.copy( dialogTag.getLength() );
234         displayDialog = false;
235     }
236     sal_Int32 returnedID = getScriptStorageID(stringURI);
237 
238 
239     // convert file:///... url to vnd... syntax
240     ::rtl::OUString canonicalURI(
241         ::rtl::OUString::createFromAscii( "vnd.sun.star.pkg://" ) );
242     canonicalURI = canonicalURI.concat( ::rtl::Uri::encode( stringURI,
243                                         rtl_UriCharClassUricNoSlash, rtl_UriEncodeCheckEscapes,
244                                         RTL_TEXTENCODING_ASCII_US ) );
245 
246     if (returnedID == -1)
247     {
248         OSL_TRACE("Creating new storage for %s",
249             ::rtl::OUStringToOString( stringURI,
250                 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
251         returnedID = setupAnyStorage( xSFA, canonicalURI, stringURI );
252     }
253     else
254     {
255        OSL_TRACE("Using existing storage for %s",
256            ::rtl::OUStringToOString( stringURI,
257                RTL_TEXTENCODING_ASCII_US ).pData->buffer );
258     }
259 
260 // np - removed previous scripting framework security handling
261 // now handled by modification to existing calls in sfx for basic
262 //
263 /*    if( displayDialog )
264     {
265         try
266         {
267            OSL_TRACE("Adding to security mgr for %s",
268                ::rtl::OUStringToOString( stringURI,
269                    RTL_TEXTENCODING_ASCII_US ).pData->buffer );
270             m_securityMgr.addScriptStorage( stringURI, returnedID );
271         }
272         catch ( RuntimeException & rte )
273         {
274             throw RuntimeException(
275                 OUSTR( "ScriptStorageManager::createScriptStorageWithURI: " ).concat(
276                     rte.Message ), Reference< XInterface >() );
277         }
278     }
279     else
280     {
281        OSL_TRACE("No need to security mgr for %s",
282            ::rtl::OUStringToOString( stringURI,
283                RTL_TEXTENCODING_ASCII_US ).pData->buffer );
284     }*/
285     return returnedID;
286 }
287 
288 //*************************************************************************
289 Reference < XInterface > SAL_CALL
290 ScriptStorageManager::getScriptStorage( sal_Int32 scriptStorageID )
291 throw( RuntimeException )
292 {
293     OSL_TRACE( "** ==> ScriptStorageManager in getStorageInstance\n" );
294     OSL_TRACE( "** ==> request for id=%d",scriptStorageID );
295 
296     ScriptStorage_map::const_iterator itr =
297         m_ScriptStorageMap.find( scriptStorageID );
298 
299     if ( itr == m_ScriptStorageMap.end() )
300     {
301         throw RuntimeException(
302             OUSTR( "ScriptStorageManager::getScriptStorage: invalid storage ID" ),
303             Reference< XInterface >() );
304     }
305     ENSURE_OR_THROW( itr->second.is(),
306                   "ScriptStorageManager::getScriptStorage: Cannot get ScriptStorage from ScriptStorageHash" );
307     return itr->second;
308 }
309 
310 //*******************************************************************
311 sal_Int32 SAL_CALL
312 ScriptStorageManager::getScriptStorageID( const ::rtl::OUString& origURI )
313         throw (::com::sun::star::uno::RuntimeException)
314 {
315     StorageId_hash::const_iterator it = m_StorageIdOrigURIHash.find( origURI );
316 
317     if ( it == m_StorageIdOrigURIHash.end() )
318     {
319         OUString message = OUSTR( "ScriptStorageManager::getScriptStorageID(): Cannot find storage for " );
320         if ( origURI.getLength() == 0 )
321         {
322             message = message.concat( OUSTR("Empty URI") );
323         }
324         else
325         {
326             message = message.concat( origURI );
327         }
328         OSL_TRACE( ::rtl::OUStringToOString( message,
329                                             RTL_TEXTENCODING_ASCII_US ).pData->buffer );
330         return -1;
331     }
332 
333     return it->second;
334 }
335 
336 //*******************************************************************
337 void
338 ScriptStorageManager::removeScriptDocURIHashEntry( const OUString & origURI )
339 {
340     StorageId_hash::iterator it = m_StorageIdOrigURIHash.find( origURI );
341     if ( it == m_StorageIdOrigURIHash.end() )
342     {
343         OSL_TRACE( "ScriptStorageManager::removeScriptDocURIHashEntry: no entry to remove" );
344         return;
345     }
346 
347     // remove entry for this doc url from orig uri map.
348     m_StorageIdOrigURIHash.erase( it );
349 }
350 
351 //*******************************************************************
352 void SAL_CALL
353 ScriptStorageManager::refreshScriptStorage( const OUString & stringURI )
354 throw( RuntimeException )
355 {
356     OSL_TRACE( "** => ScriptStorageManager in refreshScriptStorage\n" );
357     OSL_TRACE( "** => refreshing URI: %s\n",
358                ::rtl::OUStringToOString(
359                    stringURI, RTL_TEXTENCODING_ASCII_US ).pData->buffer);
360 
361     sal_Int32 storageID = getScriptStorageID( stringURI );
362 
363     if ( storageID == -1 )
364     {
365         OSL_TRACE( "** id was -1, no storage");
366         // Refreshing noexistent storage - just return
367         return;
368     }
369 
370     try
371     {
372         Reference < storage::XScriptStorageRefresh > xSSR(
373             getScriptStorage( storageID ), UNO_QUERY );
374 
375         xSSR->refresh();
376     }
377     catch ( RuntimeException & e )
378     {
379         throw RuntimeException(
380             OUSTR( "ScriptStorageManager::refreshScriptStorage: " ).concat(
381                 e.Message ), Reference< XInterface >() );
382     }
383     catch ( Exception & e )
384     {
385         throw RuntimeException(
386             OUSTR( "ScriptStorageManager::refreshScriptStorage: " ).concat(
387                 e.Message ), Reference< XInterface >() );
388     }
389 }
390 
391 //*************************************************************************
392 void SAL_CALL
393 ScriptStorageManager::checkPermission( const OUString &
394 scriptStorageURI, const OUString & permissionRequest )
395 throw ( RuntimeException, lang::IllegalArgumentException, css::security::AccessControlException )
396 {
397     try
398     {
399         m_securityMgr.checkPermission( scriptStorageURI, permissionRequest );
400     }
401     catch ( css::security::AccessControlException & e )
402     {
403         throw css::security::AccessControlException(
404             OUSTR( "ScriptStorageManager::checkPermission: AccessControlException: " ).concat(
405                 e.Message ), Reference< XInterface >(), e.LackingPermission );
406     }
407     catch ( lang::IllegalArgumentException & e )
408     {
409         throw lang::IllegalArgumentException(
410             OUSTR( "ScriptStorageManager::checkPermission: IllegalArgumentException: " ).concat(
411                 e.Message ), Reference< XInterface >(), e.ArgumentPosition );
412     }
413     catch ( RuntimeException & e )
414     {
415         throw RuntimeException(
416             OUSTR( "ScriptStorageManager::checkPermission: RuntimeException: " ).concat(
417                 e.Message ), Reference< XInterface >() );
418     }
419 }
420 
421 //*************************************************************************
422 OUString SAL_CALL
423 ScriptStorageManager::getImplementationName( )
424 throw( RuntimeException )
425 {
426     return s_implName;
427 }
428 
429 //*************************************************************************
430 sal_Bool SAL_CALL
431 ScriptStorageManager::supportsService( const OUString& serviceName )
432 throw( RuntimeException )
433 {
434     OUString const * pNames = s_serviceNames.getConstArray();
435     for ( sal_Int32 nPos = s_serviceNames.getLength(); nPos--; )
436     {
437         if ( serviceName.equals( pNames[ nPos ] ) )
438         {
439             return sal_True;
440         }
441     }
442     return sal_False;
443 }
444 
445 //*************************************************************************
446 Sequence< OUString > SAL_CALL
447 ScriptStorageManager::getSupportedServiceNames( )
448 throw( RuntimeException )
449 {
450     return s_serviceNames;
451 }
452 
453 //*************************************************************************
454 void SAL_CALL
455 ScriptStorageManager::disposing( const ::com::sun::star::lang::EventObject& Source )
456 throw ( ::com::sun::star::uno::RuntimeException )
457 {
458     OSL_TRACE( "ScriptStorageManager::disposing started" );
459     OSL_TRACE( "event object type=%s",
460                       ::rtl::OUStringToOString( getCppuType( &Source ).getTypeName(),
461                                                 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
462     OUString storageURI;
463     bool removeSecurityPermission = true;
464     try
465     {
466         Reference< XInterface > xInterface = Source.Source;
467         // no UNO_QUERY_THROW since we want a 2nd change to query if it's
468         // not a document being disposed
469         Reference< frame::XModel > xModel = Reference< frame::XModel > ( xInterface, UNO_QUERY );
470         if( xModel.is() )
471         {
472             storageURI = xModel->getURL();
473         }
474         else
475         {
476             // UNO_QURY_THROW here since it's supposed to be either a doc
477             // or a XScriptInfo (in the case of a filesys script)
478             Reference< storage::XScriptInfo > xScriptInfo = Reference< storage::XScriptInfo > ( xInterface, UNO_QUERY_THROW );
479             storageURI = xScriptInfo->getParcelURI().concat( xScriptInfo->getFunctionName() );
480             // to save the user seeing the security dialogs every time they
481             // run the script we hang on to the permission for a given script
482             // for the lifetime of the Office
483             removeSecurityPermission = false;
484             // possibly need to encode it??
485         }
486         if ( storageURI.getLength() > 0 )
487         {
488             OSL_TRACE( "URI disposing is ... %s",
489                       ::rtl::OUStringToOString( storageURI,
490                                                 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
491         }
492     }
493     catch ( RuntimeException& e )
494     {
495         OUString message =
496             OUSTR(
497                 "ScriptStorageManager::disposing: can't get script context, reason = " );
498         message = message.concat( e.Message );
499         OSL_TRACE( ::rtl::OUStringToOString( message,
500                                             RTL_TEXTENCODING_ASCII_US ).pData->buffer );
501         return;
502     }
503 
504 
505     // grab storage id.
506     sal_Int32 scriptStorageID = getScriptStorageID( storageURI );
507 
508     // no need to do anything if there's no doc storage
509     if( scriptStorageID == -1 )
510     {
511         return;
512     }
513 
514     OSL_TRACE( "disposing storageID = %d", scriptStorageID );
515 
516     // attempt to get the storage from the hash to ensure that we have a
517     // valid storageID
518     ScriptStorage_map::const_iterator itr =
519         m_ScriptStorageMap.find( scriptStorageID );
520 
521     if ( itr == m_ScriptStorageMap.end() )
522     {
523         OSL_TRACE( "Entry for storage id %d doesn't exist in map", scriptStorageID );
524         return;
525     }
526 
527     // erase the entry from the hash
528     m_ScriptStorageMap.erase( scriptStorageID );
529     removeScriptDocURIHashEntry( storageURI );
530     if ( removeSecurityPermission )
531     {
532         m_securityMgr.removePermissionSettings ( storageURI );
533     }
534 }
535 } // Namespace
536 
537 namespace scripting_runtimemgr
538 {
539 //*************************************************************************
540 Reference< XInterface > SAL_CALL
541 ssm_create(
542     const Reference< XComponentContext > & xCompC )
543 {
544     return ( cppu::OWeakObject * ) new ::scripting_impl::ScriptStorageManager( xCompC );
545 }
546 
547 //*************************************************************************
548 Sequence< OUString >
549 ssm_getSupportedServiceNames( )
550 SAL_THROW( () )
551 {
552     return ::scripting_impl::s_serviceNames;
553 }
554 
555 //*************************************************************************
556 OUString
557 ssm_getImplementationName( )
558 SAL_THROW( () )
559 {
560     return ::scripting_impl::s_implName;
561 }
562 }
563