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