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_xmlhelp.hxx"
30 
31 /**************************************************************************
32 								TODO
33  **************************************************************************
34 
35  *************************************************************************/
36 
37 #include <stdio.h>
38 #include <osl/file.hxx>
39 #ifndef _VOS_DIAGNOSE_HXX_
40 #include <vos/diagnose.hxx>
41 #endif
42 #include <ucbhelper/contentidentifier.hxx>
43 #include <com/sun/star/frame/XConfigManager.hpp>
44 #ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBBUTE_HPP_
45 #include <com/sun/star/beans/PropertyAttribute.hpp>
46 #endif
47 #include <com/sun/star/beans/PropertyValue.hpp>
48 #include <com/sun/star/container/XContainer.hpp>
49 #include <com/sun/star/container/XNameAccess.hpp>
50 #include <com/sun/star/container/XNameReplace.hpp>
51 #include <com/sun/star/uno/XComponentContext.hpp>
52 #include <com/sun/star/beans/XPropertySet.hpp>
53 #include <rtl/bootstrap.hxx>
54 
55 #include "databases.hxx"
56 #include "provider.hxx"
57 #include "content.hxx"
58 #include "databases.hxx"
59 
60 using namespace com::sun::star;
61 using namespace chelp;
62 
63 //=========================================================================
64 //=========================================================================
65 //
66 // ContentProvider Implementation.
67 //
68 //=========================================================================
69 //=========================================================================
70 
71 ContentProvider::ContentProvider(
72     const uno::Reference< lang::XMultiServiceFactory >& rSMgr )
73     : ::ucbhelper::ContentProviderImplHelper( rSMgr ),
74         isInitialized( false ),
75         m_aScheme( rtl::OUString::createFromAscii( MYUCP_URL_SCHEME ) ),
76         m_pDatabases( 0 )
77 {
78 }
79 
80 //=========================================================================
81 // virtual
82 ContentProvider::~ContentProvider()
83 {
84 	delete m_pDatabases;
85 }
86 
87 //=========================================================================
88 //
89 // XInterface methods.
90 //
91 //=========================================================================
92 
93 XINTERFACE_IMPL_6( ContentProvider,
94 				   lang::XTypeProvider,
95 				   lang::XServiceInfo,
96 				   ucb::XContentProvider,
97 				   lang::XComponent,
98                    lang::XEventListener, /* base of XContainerListener */
99 				   container::XContainerListener);
100 
101 //=========================================================================
102 //
103 // XTypeProvider methods.
104 //
105 //=========================================================================
106 
107 XTYPEPROVIDER_IMPL_5( ContentProvider,
108 				   	  lang::XTypeProvider,
109 				   	  lang::XServiceInfo,
110 				   	  ucb::XContentProvider,
111 					  lang::XComponent,
112 					  container::XContainerListener);
113 
114 //=========================================================================
115 //
116 // XServiceInfo methods.
117 //
118 //=========================================================================
119 
120 rtl::OUString SAL_CALL ContentProvider::getImplementationName()
121 	throw( uno::RuntimeException )
122 {
123 	return getImplementationName_Static();
124 }
125 
126 rtl::OUString ContentProvider::getImplementationName_Static()
127 {
128 	return rtl::OUString::createFromAscii("CHelpContentProvider" );
129 }
130 
131 sal_Bool SAL_CALL
132 ContentProvider::supportsService(const rtl::OUString& ServiceName )
133 	throw( uno::RuntimeException )
134 {
135 	uno::Sequence< rtl::OUString > aSNL = getSupportedServiceNames();
136 	const rtl::OUString* pArray = aSNL.getArray();
137 	for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
138 	{
139 		if( pArray[ i ] == ServiceName )
140 			return sal_True;
141 	}
142 
143 	return sal_False;
144 }
145 
146 uno::Sequence< rtl::OUString > SAL_CALL
147 ContentProvider::getSupportedServiceNames()
148 	throw( uno::RuntimeException )
149 {
150 	return getSupportedServiceNames_Static();
151 }
152 
153 static uno::Reference< uno::XInterface > SAL_CALL
154 ContentProvider_CreateInstance(
155  	    const uno::Reference< lang::XMultiServiceFactory> & rSMgr )
156 	throw( uno::Exception )
157 {
158     lang::XServiceInfo * pX = static_cast< lang::XServiceInfo * >(
159         new ContentProvider( rSMgr ) );
160     return uno::Reference< uno::XInterface >::query( pX );
161 }
162 
163 uno::Sequence< rtl::OUString >
164 ContentProvider::getSupportedServiceNames_Static()
165 {
166 	uno::Sequence< rtl::OUString > aSNS( 2 );
167 	aSNS.getArray()[ 0 ] =
168 		rtl::OUString::createFromAscii(
169 			MYUCP_CONTENT_PROVIDER_SERVICE_NAME1 );
170 	aSNS.getArray()[ 1 ] =
171 		rtl::OUString::createFromAscii(
172 			MYUCP_CONTENT_PROVIDER_SERVICE_NAME2 );
173 
174 	return aSNS;
175 }
176 
177 //=========================================================================
178 //
179 // Service factory implementation.
180 //
181 //=========================================================================
182 
183 ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider );
184 
185 //=========================================================================
186 //
187 // XContentProvider methods.
188 //
189 //=========================================================================
190 
191 // virtual
192 uno::Reference< ucb::XContent > SAL_CALL
193 ContentProvider::queryContent(
194         const uno::Reference< ucb::XContentIdentifier >& xCanonicId )
195     throw( ucb::IllegalIdentifierException, uno::RuntimeException )
196 {
197     if ( !xCanonicId->getContentProviderScheme()
198              .equalsIgnoreAsciiCase( m_aScheme ) )
199     {   // Wrong URL-scheme
200         throw ucb::IllegalIdentifierException();
201     }
202 
203     {
204         osl::MutexGuard aGuard( m_aMutex );
205         if( !isInitialized )
206             init();
207     }
208 
209     if( !m_pDatabases )
210         throw uno::RuntimeException();
211 
212     rtl::OUString aOUString( m_pDatabases->getInstallPathAsURL() );
213     rtl::OString aOString( aOUString.getStr(),
214                            aOUString.getLength(),
215                            RTL_TEXTENCODING_UTF8 );
216 
217     // Check, if a content with given id already exists...
218     uno::Reference< ucb::XContent > xContent
219         = queryExistingContent( xCanonicId ).get();
220     if ( xContent.is() )
221         return xContent;
222 
223     xContent = new Content( m_xSMgr, this, xCanonicId, m_pDatabases );
224 
225     // register new content
226     registerNewContent( xContent );
227 
228     // Further checks
229 
230     if ( !xContent->getIdentifier().is() )
231         throw ucb::IllegalIdentifierException();
232 
233     return xContent;
234 }
235 
236 void SAL_CALL
237 ContentProvider::dispose()
238 	throw ( uno::RuntimeException)
239 {
240 	if(m_xContainer.is())
241 	{
242 		m_xContainer->removeContainerListener(this);
243 		m_xContainer.clear();
244 	}
245 }
246 
247 void SAL_CALL
248 ContentProvider::elementReplaced(const container::ContainerEvent& Event)
249 	throw (uno::RuntimeException)
250 {
251 	if(!m_pDatabases)
252 		return;
253 
254 	rtl::OUString accessor;
255 	Event.Accessor >>= accessor;
256 	if(accessor.compareToAscii("HelpStyleSheet"))
257 		return;
258 
259 	rtl::OUString replacedElement,element;
260 	Event.ReplacedElement >>= replacedElement;
261 	Event.Element >>= element;
262 
263 	if(replacedElement == element)
264 		return;
265 
266 	m_pDatabases->changeCSS(element);
267 }
268 
269 void ContentProvider::init()
270 {
271 	osl::MutexGuard aGuard( m_aMutex );
272 
273 	isInitialized = true;
274 	uno::Reference< lang::XMultiServiceFactory > sProvider(
275         getConfiguration() );
276     uno::Reference< container::XHierarchicalNameAccess > xHierAccess(
277         getHierAccess( sProvider,
278                        "org.openoffice.Office.Common" ) );
279 
280 	rtl::OUString instPath( getKey( xHierAccess,"Path/Current/Help" ) );
281 	if( ! instPath.getLength() )
282 		// try to determine path from default
283 		instPath = rtl::OUString::createFromAscii( "$(instpath)/help" );
284 	// replace anything like $(instpath);
285 	subst( instPath );
286 
287 	rtl::OUString stylesheet( getKey( xHierAccess,"Help/HelpStyleSheet" ) );
288 	try
289     {
290 		// now adding as configuration change listener for the stylesheet
291 		uno::Reference< container::XNameAccess> xAccess(
292             xHierAccess, uno::UNO_QUERY );
293 		if( xAccess.is() )
294         {
295             uno::Any aAny =
296                 xAccess->getByName( rtl::OUString::createFromAscii( "Help" ) );
297             aAny >>= m_xContainer;
298             if( m_xContainer.is() )
299                 m_xContainer->addContainerListener( this );
300         }
301 	}
302     catch( uno::Exception const & )
303     {
304 	}
305 
306 	/**
307 	 *  now determing
308 	 *  productname,
309 	 *  productversion,
310 	 */
311 
312 	xHierAccess = getHierAccess( sProvider, "org.openoffice.Setup" );
313 	rtl::OUString productname(
314         getKey( xHierAccess,"Product/ooName" ) );
315 
316 	rtl::OUString setupversion(
317         getKey( xHierAccess,"Product/ooSetupVersion" ) );
318     rtl::OUString setupextension;
319 
320     try
321     {
322         uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
323 	          m_xSMgr ->createInstance(::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationProvider")), uno::UNO_QUERY_THROW);
324 
325         uno::Sequence < uno::Any > lParams(1);
326         beans::PropertyValue                       aParam ;
327         aParam.Name    = ::rtl::OUString::createFromAscii("nodepath");
328         aParam.Value <<= ::rtl::OUString::createFromAscii("/org.openoffice.Setup/Product");
329         lParams[0] = uno::makeAny(aParam);
330 
331         // open it
332         uno::Reference< uno::XInterface > xCFG( xConfigProvider->createInstanceWithArguments(
333                     ::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationAccess"),
334                     lParams) );
335 
336         uno::Reference< container::XNameAccess > xDirectAccess(xCFG, uno::UNO_QUERY);
337         uno::Any aRet = xDirectAccess->getByName(::rtl::OUString::createFromAscii("ooSetupExtension"));
338 
339         aRet >>= setupextension;
340     }
341     catch ( uno::Exception& )
342     {
343     }
344 
345 	rtl::OUString productversion(
346         setupversion +
347 		rtl::OUString::createFromAscii( " " ) +
348 		setupextension );
349 
350     uno::Sequence< rtl::OUString > aImagesZipPaths( 2 );
351     xHierAccess = getHierAccess( sProvider,	 "org.openoffice.Office.Common" );
352 
353     rtl::OUString aPath( getKey( xHierAccess, "Path/Current/UserConfig" ) );
354     subst( aPath );
355     aImagesZipPaths[ 0 ] = aPath;
356 
357 	aPath = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/config"));
358 	rtl::Bootstrap::expandMacros(aPath);
359     aImagesZipPaths[ 1 ] = aPath;
360 
361 	uno::Reference< uno::XComponentContext > xContext;
362 	uno::Reference< beans::XPropertySet > xProps( m_xSMgr, uno::UNO_QUERY );
363     OSL_ASSERT( xProps.is() );
364     if (xProps.is())
365     {
366         xProps->getPropertyValue(
367 			::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
368         OSL_ASSERT( xContext.is() );
369     }
370 
371     sal_Bool showBasic = getBooleanKey(xHierAccess,"Help/ShowBasic");
372     m_pDatabases = new Databases( showBasic,
373 								  instPath,
374 								  aImagesZipPaths,
375 								  productname,
376 								  productversion,
377 								  stylesheet,
378 								  xContext );
379 }
380 
381 uno::Reference< lang::XMultiServiceFactory >
382 ContentProvider::getConfiguration() const
383 {
384     uno::Reference< lang::XMultiServiceFactory > sProvider;
385 	if( m_xSMgr.is() )
386 	{
387 		try
388 		{
389 			rtl::OUString sProviderService =
390 				rtl::OUString::createFromAscii(
391 					"com.sun.star.configuration.ConfigurationProvider" );
392 			sProvider =
393 				uno::Reference< lang::XMultiServiceFactory >(
394 					m_xSMgr->createInstance( sProviderService ),
395 					uno::UNO_QUERY );
396 		}
397 		catch( const uno::Exception& )
398 		{
399             OSL_ENSURE( sProvider.is(), "cant instantiate configuration" );
400 		}
401 	}
402 
403 	return sProvider;
404 }
405 
406 uno::Reference< container::XHierarchicalNameAccess >
407 ContentProvider::getHierAccess(
408     const uno::Reference< lang::XMultiServiceFactory >& sProvider,
409     const char* file ) const
410 {
411 	uno::Reference< container::XHierarchicalNameAccess > xHierAccess;
412 
413 	if( sProvider.is() )
414 	{
415 		uno::Sequence< uno::Any > seq( 1 );
416 		rtl::OUString sReaderService(
417 			rtl::OUString::createFromAscii(
418                 "com.sun.star.configuration.ConfigurationAccess" ) );
419 
420 		seq[ 0 ] <<= rtl::OUString::createFromAscii( file );
421 
422 		try
423 		{
424 			xHierAccess =
425 				uno::Reference< container::XHierarchicalNameAccess >(
426                     sProvider->createInstanceWithArguments(
427                         sReaderService, seq ),
428                     uno::UNO_QUERY );
429 		}
430 		catch( const uno::Exception& )
431 		{
432 		}
433 	}
434 	return xHierAccess;
435 }
436 
437 
438 
439 rtl::OUString
440 ContentProvider::getKey(
441     const uno::Reference< container::XHierarchicalNameAccess >& xHierAccess,
442     const char* key ) const
443 {
444     rtl::OUString instPath;
445 	if( xHierAccess.is() )
446 	{
447 		uno::Any aAny;
448 		try
449 		{
450 			aAny =
451 				xHierAccess->getByHierarchicalName(
452 					rtl::OUString::createFromAscii( key ) );
453 		}
454 		catch( const container::NoSuchElementException& )
455 		{
456 		}
457 		aAny >>= instPath;
458 	}
459 	return instPath;
460 }
461 
462 sal_Bool
463 ContentProvider::getBooleanKey(
464     const uno::Reference< container::XHierarchicalNameAccess >& xHierAccess,
465     const char* key ) const
466 {
467   sal_Bool ret = sal_False;
468   if( xHierAccess.is() )
469   {
470 	  uno::Any aAny;
471 	  try
472       {
473 		  aAny =
474 			xHierAccess->getByHierarchicalName(
475                 rtl::OUString::createFromAscii( key ) );
476       }
477 	  catch( const container::NoSuchElementException& )
478       {
479       }
480 	  aAny >>= ret;
481   }
482   return ret;
483 }
484 
485 void ContentProvider::subst( rtl::OUString& instpath ) const
486 {
487 	uno::Reference< frame::XConfigManager > xCfgMgr;
488 	if( m_xSMgr.is() )
489 	{
490 		try
491 		{
492 			xCfgMgr =
493 				uno::Reference< frame::XConfigManager >(
494 					m_xSMgr->createInstance(
495                         rtl::OUString::createFromAscii(
496                             "com.sun.star.config.SpecialConfigManager" ) ),
497 					uno::UNO_QUERY );
498 		}
499 		catch( const uno::Exception&)
500 		{
501 			OSL_ENSURE( xCfgMgr.is(),
502                         "cant instantiate the special config manager " );
503 		}
504     }
505 
506 	OSL_ENSURE( xCfgMgr.is(), "specialconfigmanager not found\n" );
507 
508 	if( xCfgMgr.is() )
509         instpath = xCfgMgr->substituteVariables( instpath );
510 }
511