12722ceddSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
32722ceddSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
42722ceddSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
52722ceddSAndrew Rist  * distributed with this work for additional information
62722ceddSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
72722ceddSAndrew Rist  * to you under the Apache License, Version 2.0 (the
82722ceddSAndrew Rist  * "License"); you may not use this file except in compliance
92722ceddSAndrew Rist  * with the License.  You may obtain a copy of the License at
102722ceddSAndrew Rist  *
112722ceddSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
122722ceddSAndrew Rist  *
132722ceddSAndrew Rist  * Unless required by applicable law or agreed to in writing,
142722ceddSAndrew Rist  * software distributed under the License is distributed on an
152722ceddSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
162722ceddSAndrew Rist  * KIND, either express or implied.  See the License for the
172722ceddSAndrew Rist  * specific language governing permissions and limitations
182722ceddSAndrew Rist  * under the License.
192722ceddSAndrew Rist  *
202722ceddSAndrew Rist  *************************************************************/
212722ceddSAndrew Rist 
222722ceddSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_desktop.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "dp_help.hrc"
28cdf0e10cSrcweir #include "dp_backend.h"
29cdf0e10cSrcweir #include "dp_helpbackenddb.hxx"
30cdf0e10cSrcweir #include "dp_ucb.h"
31cdf0e10cSrcweir #include "rtl/uri.hxx"
32cdf0e10cSrcweir #include "osl/file.hxx"
33cdf0e10cSrcweir #include "rtl/bootstrap.hxx"
34cdf0e10cSrcweir #include "ucbhelper/content.hxx"
35cdf0e10cSrcweir #include "comphelper/servicedecl.hxx"
36cdf0e10cSrcweir #include "svl/inettype.hxx"
37cdf0e10cSrcweir #include "unotools/pathoptions.hxx"
38cdf0e10cSrcweir 
39cdf0e10cSrcweir #include <l10ntools/compilehelp.hxx>
40cdf0e10cSrcweir #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
41cdf0e10cSrcweir #include <com/sun/star/util/XMacroExpander.hpp>
42cdf0e10cSrcweir #include <com/sun/star/uri/XUriReferenceFactory.hpp>
43cdf0e10cSrcweir #include <com/sun/star/uri/XVndSunStarExpandUrl.hpp>
44cdf0e10cSrcweir #include <com/sun/star/script/XInvocation.hpp>
45cdf0e10cSrcweir #include "boost/optional.hpp"
46cdf0e10cSrcweir 
47cdf0e10cSrcweir using namespace ::dp_misc;
48cdf0e10cSrcweir using namespace ::com::sun::star;
49cdf0e10cSrcweir using namespace ::com::sun::star::uno;
50cdf0e10cSrcweir using namespace ::com::sun::star::ucb;
51cdf0e10cSrcweir using ::rtl::OUString;
52cdf0e10cSrcweir 
53cdf0e10cSrcweir namespace dp_registry {
54cdf0e10cSrcweir namespace backend {
55cdf0e10cSrcweir namespace help {
56cdf0e10cSrcweir namespace {
57cdf0e10cSrcweir 
58cdf0e10cSrcweir //==============================================================================
59cdf0e10cSrcweir class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend
60cdf0e10cSrcweir {
61cdf0e10cSrcweir     class PackageImpl : public ::dp_registry::backend::Package
62cdf0e10cSrcweir     {
63cdf0e10cSrcweir         BackendImpl * getMyBackend() const;
64cdf0e10cSrcweir 
65cdf0e10cSrcweir //        HelpBackendDb::Data m_dbData;
66cdf0e10cSrcweir 
67cdf0e10cSrcweir         // Package
68cdf0e10cSrcweir         virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
69cdf0e10cSrcweir             ::osl::ResettableMutexGuard & guard,
70cdf0e10cSrcweir             ::rtl::Reference<AbortChannel> const & abortChannel,
71cdf0e10cSrcweir             Reference<XCommandEnvironment> const & xCmdEnv );
72cdf0e10cSrcweir         virtual void processPackage_(
73cdf0e10cSrcweir             ::osl::ResettableMutexGuard & guard,
74cdf0e10cSrcweir             bool registerPackage,
75cdf0e10cSrcweir             bool startup,
76cdf0e10cSrcweir             ::rtl::Reference<AbortChannel> const & abortChannel,
77cdf0e10cSrcweir             Reference<XCommandEnvironment> const & xCmdEnv );
78cdf0e10cSrcweir 
79cdf0e10cSrcweir 
80cdf0e10cSrcweir     public:
81cdf0e10cSrcweir         PackageImpl(
82cdf0e10cSrcweir             ::rtl::Reference<PackageRegistryBackend> const & myBackend,
83cdf0e10cSrcweir             OUString const & url, OUString const & name,
84cdf0e10cSrcweir             Reference<deployment::XPackageTypeInfo> const & xPackageType,
85cdf0e10cSrcweir             bool bRemoved, OUString const & identifier);
86cdf0e10cSrcweir 
87cdf0e10cSrcweir         bool extensionContainsCompiledHelp();
88cdf0e10cSrcweir 
89cdf0e10cSrcweir         //XPackage
90cdf0e10cSrcweir         virtual css::beans::Optional< ::rtl::OUString > SAL_CALL getRegistrationDataURL()
91cdf0e10cSrcweir             throw (deployment::ExtensionRemovedException, css::uno::RuntimeException);
92cdf0e10cSrcweir     };
93cdf0e10cSrcweir     friend class PackageImpl;
94cdf0e10cSrcweir 
95cdf0e10cSrcweir     // PackageRegistryBackend
96cdf0e10cSrcweir     virtual Reference<deployment::XPackage> bindPackage_(
97cdf0e10cSrcweir         OUString const & url, OUString const & mediaType,
98cdf0e10cSrcweir         sal_Bool bRemoved, OUString const & identifier,
99cdf0e10cSrcweir         Reference<XCommandEnvironment> const & xCmdEnv );
100cdf0e10cSrcweir 
101cdf0e10cSrcweir 	void implProcessHelp( PackageImpl * package, bool doRegisterPackage,
102cdf0e10cSrcweir                           Reference<ucb::XCommandEnvironment> const & xCmdEnv);
103cdf0e10cSrcweir 	void implCollectXhpFiles( const rtl::OUString& aDir,
104cdf0e10cSrcweir 		std::vector< rtl::OUString >& o_rXhpFileVector );
105cdf0e10cSrcweir 
106cdf0e10cSrcweir     void addDataToDb(OUString const & url, HelpBackendDb::Data const & data);
107cdf0e10cSrcweir     ::boost::optional<HelpBackendDb::Data> readDataFromDb(OUString const & url);
108cdf0e10cSrcweir     bool hasActiveEntry(OUString const & url);
109cdf0e10cSrcweir     void revokeEntryFromDb(OUString const & url);
110cdf0e10cSrcweir     bool activateEntry(OUString const & url);
111cdf0e10cSrcweir 
112cdf0e10cSrcweir 	Reference< ucb::XSimpleFileAccess > getFileAccess( void );
113cdf0e10cSrcweir 	Reference< ucb::XSimpleFileAccess > m_xSFA;
114cdf0e10cSrcweir 
115cdf0e10cSrcweir     const Reference<deployment::XPackageTypeInfo> m_xHelpTypeInfo;
116cdf0e10cSrcweir     Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
117cdf0e10cSrcweir     std::auto_ptr<HelpBackendDb> m_backendDb;
118cdf0e10cSrcweir 
119cdf0e10cSrcweir public:
120cdf0e10cSrcweir     BackendImpl( Sequence<Any> const & args,
121cdf0e10cSrcweir                  Reference<XComponentContext> const & xComponentContext );
122cdf0e10cSrcweir 
123cdf0e10cSrcweir     // XPackageRegistry
124cdf0e10cSrcweir     virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
125cdf0e10cSrcweir 	    getSupportedPackageTypes() throw (RuntimeException);
126cdf0e10cSrcweir     virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
127cdf0e10cSrcweir         throw (deployment::DeploymentException,
128cdf0e10cSrcweir                uno::RuntimeException);
129cdf0e10cSrcweir 
130cdf0e10cSrcweir };
131cdf0e10cSrcweir 
132cdf0e10cSrcweir //______________________________________________________________________________
BackendImpl(Sequence<Any> const & args,Reference<XComponentContext> const & xComponentContext)133cdf0e10cSrcweir BackendImpl::BackendImpl(
134cdf0e10cSrcweir     Sequence<Any> const & args,
135cdf0e10cSrcweir     Reference<XComponentContext> const & xComponentContext )
136cdf0e10cSrcweir     : PackageRegistryBackend( args, xComponentContext ),
137cdf0e10cSrcweir       m_xHelpTypeInfo( new Package::TypeInfo(
138cdf0e10cSrcweir                                OUSTR("application/vnd.sun.star.help"),
139cdf0e10cSrcweir                                rtl::OUString(),
140cdf0e10cSrcweir                                getResourceString(RID_STR_HELP),
141cdf0e10cSrcweir                                RID_IMG_HELP, RID_IMG_HELP_HC ) ),
142cdf0e10cSrcweir       m_typeInfos( 1 )
143cdf0e10cSrcweir {
144cdf0e10cSrcweir     m_typeInfos[ 0 ] = m_xHelpTypeInfo;
145cdf0e10cSrcweir     if (!transientMode())
146cdf0e10cSrcweir     {
147cdf0e10cSrcweir         OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml"));
148cdf0e10cSrcweir         m_backendDb.reset(
149cdf0e10cSrcweir             new HelpBackendDb(getComponentContext(), dbFile));
150cdf0e10cSrcweir 
151cdf0e10cSrcweir         //clean up data folders which are no longer used.
152cdf0e10cSrcweir         //This must not be done in the same process where the help files
153cdf0e10cSrcweir         //are still registers. Only after revoking and restarting OOo the folders
154cdf0e10cSrcweir         //can be removed. This works now, because the extension manager is a singleton
155cdf0e10cSrcweir         //and the backends are only create once per process.
156cdf0e10cSrcweir         ::std::list<OUString> folders = m_backendDb->getAllDataUrls();
157cdf0e10cSrcweir         deleteUnusedFolders(OUString(), folders);
158cdf0e10cSrcweir    }
159cdf0e10cSrcweir }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir // XPackageRegistry
162cdf0e10cSrcweir //______________________________________________________________________________
163cdf0e10cSrcweir Sequence< Reference<deployment::XPackageTypeInfo> >
getSupportedPackageTypes()164cdf0e10cSrcweir BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
165cdf0e10cSrcweir {
166cdf0e10cSrcweir     return m_typeInfos;
167cdf0e10cSrcweir }
168cdf0e10cSrcweir 
packageRemoved(OUString const & url,OUString const &)169cdf0e10cSrcweir void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
170cdf0e10cSrcweir         throw (deployment::DeploymentException,
171cdf0e10cSrcweir                uno::RuntimeException)
172cdf0e10cSrcweir {
173cdf0e10cSrcweir     if (m_backendDb.get())
174cdf0e10cSrcweir         m_backendDb->removeEntry(url);
175cdf0e10cSrcweir }
176cdf0e10cSrcweir 
177cdf0e10cSrcweir // PackageRegistryBackend
178cdf0e10cSrcweir //______________________________________________________________________________
bindPackage_(OUString const & url,OUString const & mediaType_,sal_Bool bRemoved,OUString const & identifier,Reference<XCommandEnvironment> const & xCmdEnv)179cdf0e10cSrcweir Reference<deployment::XPackage> BackendImpl::bindPackage_(
180cdf0e10cSrcweir     OUString const & url, OUString const & mediaType_,
181cdf0e10cSrcweir     sal_Bool bRemoved, OUString const & identifier,
182cdf0e10cSrcweir     Reference<XCommandEnvironment> const & xCmdEnv )
183cdf0e10cSrcweir {
184cdf0e10cSrcweir 	// we don't support auto detection:
185cdf0e10cSrcweir     if (mediaType_.getLength() == 0)
186cdf0e10cSrcweir         throw lang::IllegalArgumentException(
187cdf0e10cSrcweir             StrCannotDetectMediaType::get() + url,
188cdf0e10cSrcweir             static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
189cdf0e10cSrcweir 
190cdf0e10cSrcweir     String type, subType;
191cdf0e10cSrcweir     INetContentTypeParameterList params;
192cdf0e10cSrcweir 	if (INetContentTypes::parse( mediaType_, type, subType, &params ))
193cdf0e10cSrcweir     {
194cdf0e10cSrcweir         if (type.EqualsIgnoreCaseAscii("application"))
195cdf0e10cSrcweir         {
196cdf0e10cSrcweir             OUString name;
197cdf0e10cSrcweir             if (!bRemoved)
198cdf0e10cSrcweir             {
199cdf0e10cSrcweir                 ::ucbhelper::Content ucbContent( url, xCmdEnv );
200cdf0e10cSrcweir                 name = ucbContent.getPropertyValue(
201cdf0e10cSrcweir                     StrTitle::get() ).get<OUString>();
202cdf0e10cSrcweir             }
203cdf0e10cSrcweir 
204cdf0e10cSrcweir             if (subType.EqualsIgnoreCaseAscii(
205cdf0e10cSrcweir                     "vnd.sun.star.help"))
206cdf0e10cSrcweir 			{
207cdf0e10cSrcweir                 return new PackageImpl(
208cdf0e10cSrcweir                     this, url, name, m_xHelpTypeInfo, bRemoved,
209cdf0e10cSrcweir                     identifier);
210cdf0e10cSrcweir             }
211cdf0e10cSrcweir         }
212cdf0e10cSrcweir     }
213cdf0e10cSrcweir     throw lang::IllegalArgumentException(
214cdf0e10cSrcweir         StrUnsupportedMediaType::get() + mediaType_,
215cdf0e10cSrcweir         static_cast<OWeakObject *>(this),
216cdf0e10cSrcweir         static_cast<sal_Int16>(-1) );
217cdf0e10cSrcweir }
218cdf0e10cSrcweir 
addDataToDb(OUString const & url,HelpBackendDb::Data const & data)219cdf0e10cSrcweir void BackendImpl::addDataToDb(
220cdf0e10cSrcweir     OUString const & url, HelpBackendDb::Data const & data)
221cdf0e10cSrcweir {
222cdf0e10cSrcweir     if (m_backendDb.get())
223cdf0e10cSrcweir         m_backendDb->addEntry(url, data);
224cdf0e10cSrcweir }
225cdf0e10cSrcweir 
readDataFromDb(OUString const & url)226cdf0e10cSrcweir ::boost::optional<HelpBackendDb::Data> BackendImpl::readDataFromDb(
227cdf0e10cSrcweir     OUString const & url)
228cdf0e10cSrcweir {
229cdf0e10cSrcweir     ::boost::optional<HelpBackendDb::Data> data;
230cdf0e10cSrcweir     if (m_backendDb.get())
231cdf0e10cSrcweir         data = m_backendDb->getEntry(url);
232cdf0e10cSrcweir     return data;
233cdf0e10cSrcweir }
234cdf0e10cSrcweir 
hasActiveEntry(OUString const & url)235cdf0e10cSrcweir bool BackendImpl::hasActiveEntry(OUString const & url)
236cdf0e10cSrcweir {
237cdf0e10cSrcweir     if (m_backendDb.get())
238cdf0e10cSrcweir         return m_backendDb->hasActiveEntry(url);
239cdf0e10cSrcweir     return false;
240cdf0e10cSrcweir }
241cdf0e10cSrcweir 
revokeEntryFromDb(OUString const & url)242cdf0e10cSrcweir void BackendImpl::revokeEntryFromDb(OUString const & url)
243cdf0e10cSrcweir {
244cdf0e10cSrcweir     if (m_backendDb.get())
245cdf0e10cSrcweir         m_backendDb->revokeEntry(url);
246cdf0e10cSrcweir }
247cdf0e10cSrcweir 
activateEntry(OUString const & url)248cdf0e10cSrcweir bool BackendImpl::activateEntry(OUString const & url)
249cdf0e10cSrcweir {
250cdf0e10cSrcweir     if (m_backendDb.get())
251cdf0e10cSrcweir         return m_backendDb->activateEntry(url);
252cdf0e10cSrcweir     return false;
253cdf0e10cSrcweir }
254cdf0e10cSrcweir 
255cdf0e10cSrcweir 
256cdf0e10cSrcweir //##############################################################################
PackageImpl(::rtl::Reference<PackageRegistryBackend> const & myBackend,OUString const & url,OUString const & name,Reference<deployment::XPackageTypeInfo> const & xPackageType,bool bRemoved,OUString const & identifier)257cdf0e10cSrcweir BackendImpl::PackageImpl::PackageImpl(
258cdf0e10cSrcweir     ::rtl::Reference<PackageRegistryBackend> const & myBackend,
259cdf0e10cSrcweir     OUString const & url, OUString const & name,
260cdf0e10cSrcweir     Reference<deployment::XPackageTypeInfo> const & xPackageType,
261cdf0e10cSrcweir     bool bRemoved, OUString const & identifier)
262cdf0e10cSrcweir     : Package( myBackend, url, name, name, xPackageType, bRemoved,
263cdf0e10cSrcweir                identifier)
264cdf0e10cSrcweir {
265cdf0e10cSrcweir }
266cdf0e10cSrcweir 
267cdf0e10cSrcweir // Package
getMyBackend() const268cdf0e10cSrcweir BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
269cdf0e10cSrcweir {
270cdf0e10cSrcweir     BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
271cdf0e10cSrcweir     if (NULL == pBackend)
272cdf0e10cSrcweir     {
273cdf0e10cSrcweir         //May throw a DisposedException
274cdf0e10cSrcweir         check();
275cdf0e10cSrcweir         //We should never get here...
276cdf0e10cSrcweir         throw RuntimeException(
277cdf0e10cSrcweir             OUSTR("Failed to get the BackendImpl"),
278cdf0e10cSrcweir             static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
279cdf0e10cSrcweir     }
280cdf0e10cSrcweir     return pBackend;
281cdf0e10cSrcweir }
282cdf0e10cSrcweir 
extensionContainsCompiledHelp()283cdf0e10cSrcweir bool BackendImpl::PackageImpl::extensionContainsCompiledHelp()
284cdf0e10cSrcweir {
285cdf0e10cSrcweir     bool bCompiled = true;
286cdf0e10cSrcweir     rtl::OUString aExpandedHelpURL = dp_misc::expandUnoRcUrl(getURL());
287cdf0e10cSrcweir 
288cdf0e10cSrcweir     ::osl::Directory helpFolder(aExpandedHelpURL);
289cdf0e10cSrcweir     if ( helpFolder.open() == ::osl::File::E_None)
290cdf0e10cSrcweir     {
291cdf0e10cSrcweir         //iterate over the contents of the help folder
292*07a3d7f1SPedro Giffuni         //We assume that all folders within the help folder contain language specific
293cdf0e10cSrcweir         //help files. If just one of them does not contain compiled help then this
294cdf0e10cSrcweir         //function returns false.
295cdf0e10cSrcweir         ::osl::DirectoryItem item;
296cdf0e10cSrcweir         ::osl::File::RC errorNext = ::osl::File::E_None;
297cdf0e10cSrcweir         while ((errorNext = helpFolder.getNextItem(item)) == ::osl::File::E_None)
298cdf0e10cSrcweir         {
299cdf0e10cSrcweir             //No find the language folders
300cdf0e10cSrcweir             ::osl::FileStatus stat(FileStatusMask_Type | FileStatusMask_FileName |FileStatusMask_FileURL);
301cdf0e10cSrcweir             if (item.getFileStatus(stat) == ::osl::File::E_None)
302cdf0e10cSrcweir             {
303cdf0e10cSrcweir                 if (stat.getFileType() != ::osl::FileStatus::Directory)
304cdf0e10cSrcweir                     continue;
305cdf0e10cSrcweir 
306cdf0e10cSrcweir                 //look if there is the folder help.idxl in the language folder
307cdf0e10cSrcweir                 OUString compUrl(stat.getFileURL() + OUSTR("/help.idxl"));
308cdf0e10cSrcweir                 ::osl::Directory compiledFolder(compUrl);
309cdf0e10cSrcweir                 if (compiledFolder.open() != ::osl::File::E_None)
310cdf0e10cSrcweir                 {
311cdf0e10cSrcweir                     bCompiled = false;
312cdf0e10cSrcweir                     break;
313cdf0e10cSrcweir                 }
314cdf0e10cSrcweir             }
315cdf0e10cSrcweir             else
316cdf0e10cSrcweir             {
317cdf0e10cSrcweir                 //Error
318cdf0e10cSrcweir                 OSL_ASSERT(0);
319cdf0e10cSrcweir                 bCompiled = false;
320cdf0e10cSrcweir                 break;
321cdf0e10cSrcweir             }
322cdf0e10cSrcweir         }
323cdf0e10cSrcweir         if (errorNext != ::osl::File::E_NOENT
324cdf0e10cSrcweir             && errorNext != ::osl::File::E_None)
325cdf0e10cSrcweir         {
326cdf0e10cSrcweir             //Error
327cdf0e10cSrcweir             OSL_ASSERT(0);
328cdf0e10cSrcweir             bCompiled = false;
329cdf0e10cSrcweir         }
330cdf0e10cSrcweir     }
331cdf0e10cSrcweir     return bCompiled;
332cdf0e10cSrcweir }
333cdf0e10cSrcweir 
334cdf0e10cSrcweir //______________________________________________________________________________
335cdf0e10cSrcweir beans::Optional< beans::Ambiguous<sal_Bool> >
isRegistered_(::osl::ResettableMutexGuard &,::rtl::Reference<AbortChannel> const &,Reference<XCommandEnvironment> const &)336cdf0e10cSrcweir BackendImpl::PackageImpl::isRegistered_(
337cdf0e10cSrcweir     ::osl::ResettableMutexGuard &,
338cdf0e10cSrcweir     ::rtl::Reference<AbortChannel> const &,
339cdf0e10cSrcweir     Reference<XCommandEnvironment> const & )
340cdf0e10cSrcweir {
341cdf0e10cSrcweir     BackendImpl * that = getMyBackend();
342cdf0e10cSrcweir 
343cdf0e10cSrcweir 	bool bReg = false;
344cdf0e10cSrcweir     if (that->hasActiveEntry(getURL()))
345cdf0e10cSrcweir         bReg = true;
346cdf0e10cSrcweir 
347cdf0e10cSrcweir 	return beans::Optional< beans::Ambiguous<sal_Bool> >( true, beans::Ambiguous<sal_Bool>( bReg, false ) );
348cdf0e10cSrcweir }
349cdf0e10cSrcweir 
350cdf0e10cSrcweir //______________________________________________________________________________
processPackage_(::osl::ResettableMutexGuard &,bool doRegisterPackage,bool,::rtl::Reference<AbortChannel> const & abortChannel,Reference<XCommandEnvironment> const & xCmdEnv)351cdf0e10cSrcweir void BackendImpl::PackageImpl::processPackage_(
352cdf0e10cSrcweir     ::osl::ResettableMutexGuard &,
353cdf0e10cSrcweir     bool doRegisterPackage,
354cdf0e10cSrcweir     bool /* startup */,
355cdf0e10cSrcweir     ::rtl::Reference<AbortChannel> const & abortChannel,
356cdf0e10cSrcweir     Reference<XCommandEnvironment> const & xCmdEnv )
357cdf0e10cSrcweir {
358cdf0e10cSrcweir 	(void)doRegisterPackage;
359cdf0e10cSrcweir 	(void)abortChannel;
360cdf0e10cSrcweir 	(void)xCmdEnv;
361cdf0e10cSrcweir 
362cdf0e10cSrcweir     BackendImpl* that = getMyBackend();
363cdf0e10cSrcweir 	that->implProcessHelp( this, doRegisterPackage, xCmdEnv);
364cdf0e10cSrcweir }
365cdf0e10cSrcweir 
getRegistrationDataURL()366cdf0e10cSrcweir beans::Optional< OUString > BackendImpl::PackageImpl::getRegistrationDataURL()
367cdf0e10cSrcweir     throw (deployment::ExtensionRemovedException,
368cdf0e10cSrcweir            css::uno::RuntimeException)
369cdf0e10cSrcweir {
370cdf0e10cSrcweir     if (m_bRemoved)
371cdf0e10cSrcweir         throw deployment::ExtensionRemovedException();
372cdf0e10cSrcweir 
373cdf0e10cSrcweir     ::boost::optional<HelpBackendDb::Data> data =
374cdf0e10cSrcweir           getMyBackend()->readDataFromDb(getURL());
375cdf0e10cSrcweir 
376cdf0e10cSrcweir     if (data && getMyBackend()->hasActiveEntry(getURL()))
377cdf0e10cSrcweir         return beans::Optional<OUString>(true, data->dataUrl);
378cdf0e10cSrcweir 
379cdf0e10cSrcweir     return beans::Optional<OUString>(true, OUString());
380cdf0e10cSrcweir }
381cdf0e10cSrcweir 
382cdf0e10cSrcweir 
383cdf0e10cSrcweir //##############################################################################
384cdf0e10cSrcweir 
385cdf0e10cSrcweir static rtl::OUString aSlash( rtl::OUString::createFromAscii( "/" ) );
386cdf0e10cSrcweir static rtl::OUString aHelpStr( rtl::OUString::createFromAscii( "help" ) );
387cdf0e10cSrcweir 
388cdf0e10cSrcweir 
implProcessHelp(PackageImpl * package,bool doRegisterPackage,Reference<ucb::XCommandEnvironment> const & xCmdEnv)389cdf0e10cSrcweir void BackendImpl::implProcessHelp(
390cdf0e10cSrcweir     PackageImpl * package, bool doRegisterPackage,
391cdf0e10cSrcweir     Reference<ucb::XCommandEnvironment> const & xCmdEnv)
392cdf0e10cSrcweir {
393cdf0e10cSrcweir     Reference< deployment::XPackage > xPackage(package);
394cdf0e10cSrcweir     OSL_ASSERT(xPackage.is());
395cdf0e10cSrcweir     if (doRegisterPackage)
396cdf0e10cSrcweir     {
397cdf0e10cSrcweir         //revive already processed help if possible
398cdf0e10cSrcweir         if ( !activateEntry(xPackage->getURL()))
399cdf0e10cSrcweir         {
400cdf0e10cSrcweir             HelpBackendDb::Data data;
401cdf0e10cSrcweir             data.dataUrl = xPackage->getURL();
402cdf0e10cSrcweir             if (!package->extensionContainsCompiledHelp())
403cdf0e10cSrcweir             {
404cdf0e10cSrcweir                 const OUString sHelpFolder = createFolder(OUString(), xCmdEnv);
405cdf0e10cSrcweir                 data.dataUrl = sHelpFolder;
406cdf0e10cSrcweir 
407cdf0e10cSrcweir                 Reference< ucb::XSimpleFileAccess > xSFA = getFileAccess();
408cdf0e10cSrcweir                 rtl::OUString aHelpURL = xPackage->getURL();
409cdf0e10cSrcweir                 rtl::OUString aExpandedHelpURL = dp_misc::expandUnoRcUrl( aHelpURL );
410cdf0e10cSrcweir                 rtl::OUString aName = xPackage->getName();
411cdf0e10cSrcweir                 if( !xSFA->isFolder( aExpandedHelpURL ) )
412cdf0e10cSrcweir                 {
413cdf0e10cSrcweir                     rtl::OUString aErrStr = getResourceString( RID_STR_HELPPROCESSING_GENERAL_ERROR );
414cdf0e10cSrcweir                     aErrStr += rtl::OUString::createFromAscii( "No help folder" );
415cdf0e10cSrcweir                     OWeakObject* oWeakThis = static_cast<OWeakObject *>(this);
416cdf0e10cSrcweir                     throw deployment::DeploymentException( rtl::OUString(), oWeakThis,
417cdf0e10cSrcweir                                                            makeAny( uno::Exception( aErrStr, oWeakThis ) ) );
418cdf0e10cSrcweir                 }
419cdf0e10cSrcweir 
420cdf0e10cSrcweir                 Reference<XComponentContext> const & xContext = getComponentContext();
421cdf0e10cSrcweir                 Reference< script::XInvocation > xInvocation;
422cdf0e10cSrcweir                 if( xContext.is() )
423cdf0e10cSrcweir                 {
424cdf0e10cSrcweir                     try
425cdf0e10cSrcweir                     {
426cdf0e10cSrcweir                         xInvocation = Reference< script::XInvocation >(
427cdf0e10cSrcweir                             xContext->getServiceManager()->createInstanceWithContext( rtl::OUString::createFromAscii(
428cdf0e10cSrcweir                                                                                           "com.sun.star.help.HelpIndexer" ), xContext ) , UNO_QUERY );
429cdf0e10cSrcweir                     }
430cdf0e10cSrcweir                     catch (Exception &)
431cdf0e10cSrcweir                     {
432cdf0e10cSrcweir                         // i98680: Survive missing lucene
433cdf0e10cSrcweir                     }
434cdf0e10cSrcweir                 }
435cdf0e10cSrcweir 
436cdf0e10cSrcweir                 // Scan languages
437cdf0e10cSrcweir                 Sequence< rtl::OUString > aLanguageFolderSeq = xSFA->getFolderContents( aExpandedHelpURL, true );
438cdf0e10cSrcweir                 sal_Int32 nLangCount = aLanguageFolderSeq.getLength();
439cdf0e10cSrcweir                 const rtl::OUString* pSeq = aLanguageFolderSeq.getConstArray();
440cdf0e10cSrcweir                 for( sal_Int32 iLang = 0 ; iLang < nLangCount ; ++iLang )
441cdf0e10cSrcweir                 {
442cdf0e10cSrcweir                     rtl::OUString aLangURL = pSeq[iLang];
443cdf0e10cSrcweir                     if( xSFA->isFolder( aLangURL ) )
444cdf0e10cSrcweir                     {
445cdf0e10cSrcweir                         std::vector< rtl::OUString > aXhpFileVector;
446cdf0e10cSrcweir 
447cdf0e10cSrcweir                         // calculate jar file URL
448cdf0e10cSrcweir                         sal_Int32 indexStartSegment = aLangURL.lastIndexOf('/');
449cdf0e10cSrcweir                         // for example "/en"
450cdf0e10cSrcweir                         OUString langFolderURLSegment(
451cdf0e10cSrcweir                             aLangURL.copy(
452cdf0e10cSrcweir                                 indexStartSegment + 1, aLangURL.getLength() - indexStartSegment - 1));
453cdf0e10cSrcweir 
454cdf0e10cSrcweir                         //create the folder in the "temporary folder"
455cdf0e10cSrcweir                         ::ucbhelper::Content langFolderContent;
456cdf0e10cSrcweir                         const OUString langFolderDest = makeURL(sHelpFolder, langFolderURLSegment);
457cdf0e10cSrcweir                         const OUString langFolderDestExpanded = ::dp_misc::expandUnoRcUrl(langFolderDest);
458cdf0e10cSrcweir                         ::dp_misc::create_folder(
459cdf0e10cSrcweir                             &langFolderContent,
460cdf0e10cSrcweir                             langFolderDest, xCmdEnv);
461cdf0e10cSrcweir 
462cdf0e10cSrcweir                         rtl::OUString aJarFile(
463cdf0e10cSrcweir                             makeURL(sHelpFolder, langFolderURLSegment + aSlash + aHelpStr +
464cdf0e10cSrcweir                                     OUSTR(".jar")));
465cdf0e10cSrcweir                         aJarFile = ::dp_misc::expandUnoRcUrl(aJarFile);
466cdf0e10cSrcweir 
467cdf0e10cSrcweir                         rtl::OUString aEncodedJarFilePath = rtl::Uri::encode(
468cdf0e10cSrcweir                             aJarFile, rtl_UriCharClassPchar,
469cdf0e10cSrcweir                             rtl_UriEncodeIgnoreEscapes,
470cdf0e10cSrcweir                             RTL_TEXTENCODING_UTF8 );
471cdf0e10cSrcweir                         rtl::OUString aDestBasePath = rtl::OUString::createFromAscii( "vnd.sun.star.zip://" );
472cdf0e10cSrcweir                         aDestBasePath += aEncodedJarFilePath;
473cdf0e10cSrcweir                         aDestBasePath += rtl::OUString::createFromAscii( "/" );
474cdf0e10cSrcweir 
475cdf0e10cSrcweir                         sal_Int32 nLenLangFolderURL = aLangURL.getLength() + 1;
476cdf0e10cSrcweir 
477cdf0e10cSrcweir                         Sequence< rtl::OUString > aSubLangSeq = xSFA->getFolderContents( aLangURL, true );
478cdf0e10cSrcweir                         sal_Int32 nSubLangCount = aSubLangSeq.getLength();
479cdf0e10cSrcweir                         const rtl::OUString* pSubLangSeq = aSubLangSeq.getConstArray();
480cdf0e10cSrcweir                         for( sal_Int32 iSubLang = 0 ; iSubLang < nSubLangCount ; ++iSubLang )
481cdf0e10cSrcweir                         {
482cdf0e10cSrcweir                             rtl::OUString aSubFolderURL = pSubLangSeq[iSubLang];
483cdf0e10cSrcweir                             if( !xSFA->isFolder( aSubFolderURL ) )
484cdf0e10cSrcweir                                 continue;
485cdf0e10cSrcweir 
486cdf0e10cSrcweir                             implCollectXhpFiles( aSubFolderURL, aXhpFileVector );
487cdf0e10cSrcweir 
488cdf0e10cSrcweir                             // Copy to package (later: move?)
489cdf0e10cSrcweir                             rtl::OUString aDestPath = aDestBasePath;
490cdf0e10cSrcweir                             rtl::OUString aPureFolderName = aSubFolderURL.copy( nLenLangFolderURL );
491cdf0e10cSrcweir                             aDestPath += aPureFolderName;
492cdf0e10cSrcweir                             xSFA->copy( aSubFolderURL, aDestPath );
493cdf0e10cSrcweir                         }
494cdf0e10cSrcweir 
495cdf0e10cSrcweir                         // Call compiler
496cdf0e10cSrcweir                         sal_Int32 nXhpFileCount = aXhpFileVector.size();
497cdf0e10cSrcweir                         rtl::OUString* pXhpFiles = new rtl::OUString[nXhpFileCount];
498cdf0e10cSrcweir                         for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp )
499cdf0e10cSrcweir                         {
500cdf0e10cSrcweir                             rtl::OUString aXhpFile = aXhpFileVector[iXhp];
501cdf0e10cSrcweir                             rtl::OUString aXhpRelFile = aXhpFile.copy( nLenLangFolderURL );
502cdf0e10cSrcweir                             pXhpFiles[iXhp] = aXhpRelFile;
503cdf0e10cSrcweir                         }
504cdf0e10cSrcweir 
505cdf0e10cSrcweir                         rtl::OUString aOfficeHelpPath( SvtPathOptions().GetHelpPath() );
506cdf0e10cSrcweir                         rtl::OUString aOfficeHelpPathFileURL;
507cdf0e10cSrcweir                         ::osl::File::getFileURLFromSystemPath( aOfficeHelpPath, aOfficeHelpPathFileURL );
508cdf0e10cSrcweir 
509cdf0e10cSrcweir                         HelpProcessingErrorInfo aErrorInfo;
510cdf0e10cSrcweir                         bool bSuccess = compileExtensionHelp(
511cdf0e10cSrcweir                             aOfficeHelpPathFileURL, aHelpStr, aLangURL,
512cdf0e10cSrcweir                             nXhpFileCount, pXhpFiles,
513cdf0e10cSrcweir                             langFolderDestExpanded, aErrorInfo );
514cdf0e10cSrcweir 
515cdf0e10cSrcweir                         if( bSuccess && xInvocation.is() )
516cdf0e10cSrcweir                         {
517cdf0e10cSrcweir                             Sequence<uno::Any> aParamsSeq( 6 );
518cdf0e10cSrcweir 
519cdf0e10cSrcweir                             aParamsSeq[0] = uno::makeAny( rtl::OUString::createFromAscii( "-lang" ) );
520cdf0e10cSrcweir 
521cdf0e10cSrcweir                             rtl::OUString aLang;
522cdf0e10cSrcweir                             sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' );
523cdf0e10cSrcweir                             if( nLastSlash != -1 )
524cdf0e10cSrcweir                                 aLang = aLangURL.copy( nLastSlash + 1 );
525cdf0e10cSrcweir                             else
526cdf0e10cSrcweir                                 aLang = rtl::OUString::createFromAscii( "en" );
527cdf0e10cSrcweir                             aParamsSeq[1] = uno::makeAny( aLang );
528cdf0e10cSrcweir 
529cdf0e10cSrcweir                             aParamsSeq[2] = uno::makeAny( rtl::OUString::createFromAscii( "-mod" ) );
530cdf0e10cSrcweir                             aParamsSeq[3] = uno::makeAny( rtl::OUString::createFromAscii( "help" ) );
531cdf0e10cSrcweir 
532cdf0e10cSrcweir                             aParamsSeq[4] = uno::makeAny( rtl::OUString::createFromAscii( "-zipdir" ) );
533cdf0e10cSrcweir                             rtl::OUString aSystemPath;
534cdf0e10cSrcweir                             osl::FileBase::getSystemPathFromFileURL(
535cdf0e10cSrcweir                                 langFolderDestExpanded, aSystemPath );
536cdf0e10cSrcweir                             aParamsSeq[5] = uno::makeAny( aSystemPath );
537cdf0e10cSrcweir 
538cdf0e10cSrcweir                             Sequence< sal_Int16 > aOutParamIndex;
539cdf0e10cSrcweir                             Sequence< uno::Any > aOutParam;
540cdf0e10cSrcweir                             uno::Any aRet = xInvocation->invoke( rtl::OUString::createFromAscii( "createIndex" ),
541cdf0e10cSrcweir                                                                  aParamsSeq, aOutParamIndex, aOutParam );
542cdf0e10cSrcweir                         }
543cdf0e10cSrcweir 
544cdf0e10cSrcweir                         if( !bSuccess )
545cdf0e10cSrcweir                         {
546cdf0e10cSrcweir                             sal_uInt16 nErrStrId = 0;
547cdf0e10cSrcweir                             switch( aErrorInfo.m_eErrorClass )
548cdf0e10cSrcweir                             {
549cdf0e10cSrcweir                             case HELPPROCESSING_GENERAL_ERROR:
550cdf0e10cSrcweir                             case HELPPROCESSING_INTERNAL_ERROR:		nErrStrId = RID_STR_HELPPROCESSING_GENERAL_ERROR; break;
551cdf0e10cSrcweir                             case HELPPROCESSING_XMLPARSING_ERROR:	nErrStrId = RID_STR_HELPPROCESSING_XMLPARSING_ERROR; break;
552cdf0e10cSrcweir                             default: ;
553cdf0e10cSrcweir                             };
554cdf0e10cSrcweir 
555cdf0e10cSrcweir                             rtl::OUString aErrStr;
556cdf0e10cSrcweir                             if( nErrStrId != 0 )
557cdf0e10cSrcweir                             {
558cdf0e10cSrcweir                                 aErrStr = getResourceString( nErrStrId );
559cdf0e10cSrcweir 
560cdf0e10cSrcweir                                 // Remoce CR/LF
561cdf0e10cSrcweir                                 rtl::OUString aErrMsg( aErrorInfo.m_aErrorMsg );
562cdf0e10cSrcweir                                 sal_Unicode nCR = 13, nLF = 10;
563cdf0e10cSrcweir                                 sal_Int32 nSearchCR = aErrMsg.indexOf( nCR );
564cdf0e10cSrcweir                                 sal_Int32 nSearchLF = aErrMsg.indexOf( nLF );
565cdf0e10cSrcweir                                 sal_Int32 nCopy;
566cdf0e10cSrcweir                                 if( nSearchCR != -1 || nSearchLF != -1 )
567cdf0e10cSrcweir                                 {
568cdf0e10cSrcweir                                     if( nSearchCR == -1 )
569cdf0e10cSrcweir                                         nCopy = nSearchLF;
570cdf0e10cSrcweir                                     else if( nSearchLF == -1 )
571cdf0e10cSrcweir                                         nCopy = nSearchCR;
572cdf0e10cSrcweir                                     else
573cdf0e10cSrcweir                                         nCopy = ( nSearchCR < nSearchLF ) ? nSearchCR : nSearchLF;
574cdf0e10cSrcweir 
575cdf0e10cSrcweir                                     aErrMsg = aErrMsg.copy( 0, nCopy );
576cdf0e10cSrcweir                                 }
577cdf0e10cSrcweir                                 aErrStr += aErrMsg;
578cdf0e10cSrcweir                                 if( nErrStrId == RID_STR_HELPPROCESSING_XMLPARSING_ERROR && aErrorInfo.m_aXMLParsingFile.getLength() )
579cdf0e10cSrcweir                                 {
580cdf0e10cSrcweir                                     aErrStr += rtl::OUString::createFromAscii( " in " );
581cdf0e10cSrcweir 
582cdf0e10cSrcweir                                     rtl::OUString aDecodedFile = rtl::Uri::decode( aErrorInfo.m_aXMLParsingFile,
583cdf0e10cSrcweir                                                                                    rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
584cdf0e10cSrcweir                                     aErrStr += aDecodedFile;
585cdf0e10cSrcweir                                     if( aErrorInfo.m_nXMLParsingLine != -1 )
586cdf0e10cSrcweir                                     {
587cdf0e10cSrcweir                                         aErrStr += rtl::OUString::createFromAscii( ", line " );
588cdf0e10cSrcweir                                         aErrStr += ::rtl::OUString::valueOf( aErrorInfo.m_nXMLParsingLine );
589cdf0e10cSrcweir                                     }
590cdf0e10cSrcweir                                 }
591cdf0e10cSrcweir                             }
592cdf0e10cSrcweir 
593cdf0e10cSrcweir                             OWeakObject* oWeakThis = static_cast<OWeakObject *>(this);
594cdf0e10cSrcweir                             throw deployment::DeploymentException( rtl::OUString(), oWeakThis,
595cdf0e10cSrcweir                                                                    makeAny( uno::Exception( aErrStr, oWeakThis ) ) );
596cdf0e10cSrcweir                         }
597cdf0e10cSrcweir                     }
598cdf0e10cSrcweir                 }
599cdf0e10cSrcweir             }
600cdf0e10cSrcweir                 //Writing the data entry replaces writing the flag file. If we got to this
601cdf0e10cSrcweir                 //point the registration was successful.
602cdf0e10cSrcweir             addDataToDb(xPackage->getURL(), data);
603cdf0e10cSrcweir         }
604cdf0e10cSrcweir     } //if (doRegisterPackage)
605cdf0e10cSrcweir     else
606cdf0e10cSrcweir     {
607cdf0e10cSrcweir         revokeEntryFromDb(xPackage->getURL());
608cdf0e10cSrcweir     }
609cdf0e10cSrcweir }
610cdf0e10cSrcweir 
611cdf0e10cSrcweir 
implCollectXhpFiles(const rtl::OUString & aDir,std::vector<rtl::OUString> & o_rXhpFileVector)612cdf0e10cSrcweir void BackendImpl::implCollectXhpFiles( const rtl::OUString& aDir,
613cdf0e10cSrcweir 	std::vector< rtl::OUString >& o_rXhpFileVector )
614cdf0e10cSrcweir {
615cdf0e10cSrcweir 	Reference< ucb::XSimpleFileAccess > xSFA = getFileAccess();
616cdf0e10cSrcweir 
617cdf0e10cSrcweir 	// Scan xhp files recursively
618cdf0e10cSrcweir     Sequence< rtl::OUString > aSeq = xSFA->getFolderContents( aDir, true );
619cdf0e10cSrcweir     sal_Int32 nCount = aSeq.getLength();
620cdf0e10cSrcweir 	const rtl::OUString* pSeq = aSeq.getConstArray();
621cdf0e10cSrcweir 	for( sal_Int32 i = 0 ; i < nCount ; ++i )
622cdf0e10cSrcweir 	{
623cdf0e10cSrcweir 		rtl::OUString aURL = pSeq[i];
624cdf0e10cSrcweir 		if( xSFA->isFolder( aURL ) )
625cdf0e10cSrcweir 		{
626cdf0e10cSrcweir 			implCollectXhpFiles( aURL, o_rXhpFileVector );
627cdf0e10cSrcweir 		}
628cdf0e10cSrcweir 		else
629cdf0e10cSrcweir 		{
630cdf0e10cSrcweir 			sal_Int32 nLastDot = aURL.lastIndexOf( '.' );
631cdf0e10cSrcweir 			if( nLastDot != -1 )
632cdf0e10cSrcweir 			{
633cdf0e10cSrcweir 				rtl::OUString aExt = aURL.copy( nLastDot + 1 );
634cdf0e10cSrcweir 				if( aExt.equalsIgnoreAsciiCase( rtl::OUString::createFromAscii( "xhp" ) ) )
635cdf0e10cSrcweir 					o_rXhpFileVector.push_back( aURL );
636cdf0e10cSrcweir 			}
637cdf0e10cSrcweir 		}
638cdf0e10cSrcweir 	}
639cdf0e10cSrcweir }
640cdf0e10cSrcweir 
getFileAccess(void)641cdf0e10cSrcweir Reference< ucb::XSimpleFileAccess > BackendImpl::getFileAccess( void )
642cdf0e10cSrcweir {
643cdf0e10cSrcweir 	if( !m_xSFA.is() )
644cdf0e10cSrcweir 	{
645cdf0e10cSrcweir 		Reference<XComponentContext> const & xContext = getComponentContext();
646cdf0e10cSrcweir 		if( xContext.is() )
647cdf0e10cSrcweir 		{
648cdf0e10cSrcweir 			m_xSFA = Reference< ucb::XSimpleFileAccess >(
649cdf0e10cSrcweir 				xContext->getServiceManager()->createInstanceWithContext(
650cdf0e10cSrcweir 					rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ),
651cdf0e10cSrcweir 					xContext ), UNO_QUERY );
652cdf0e10cSrcweir 		}
653cdf0e10cSrcweir 		if( !m_xSFA.is() )
654cdf0e10cSrcweir 		{
655cdf0e10cSrcweir 			throw RuntimeException(
656cdf0e10cSrcweir 				::rtl::OUString::createFromAscii(
657cdf0e10cSrcweir 				"dp_registry::backend::help::BackendImpl::getFileAccess(), "
658cdf0e10cSrcweir 				"could not instatiate SimpleFileAccess." ),
659cdf0e10cSrcweir 				Reference< XInterface >() );
660cdf0e10cSrcweir 		}
661cdf0e10cSrcweir 	}
662cdf0e10cSrcweir 	return m_xSFA;
663cdf0e10cSrcweir }
664cdf0e10cSrcweir 
665cdf0e10cSrcweir } // anon namespace
666cdf0e10cSrcweir 
667cdf0e10cSrcweir namespace sdecl = comphelper::service_decl;
668cdf0e10cSrcweir sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
669cdf0e10cSrcweir extern sdecl::ServiceDecl const serviceDecl(
670cdf0e10cSrcweir     serviceBI,
671cdf0e10cSrcweir     "com.sun.star.comp.deployment.help.PackageRegistryBackend",
672cdf0e10cSrcweir     BACKEND_SERVICE_NAME );
673cdf0e10cSrcweir 
674cdf0e10cSrcweir } // namespace help
675cdf0e10cSrcweir } // namespace backend
676cdf0e10cSrcweir } // namespace dp_registry
677cdf0e10cSrcweir 
678