1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <strings.hrc>
23 #include <dp_backend.h>
24 #include <dp_ucb.h>
25 #include "dp_parceldesc.hxx"
26 #include <rtl/uri.hxx>
27 #include <ucbhelper/content.hxx>
28 #include <svl/inettype.hxx>
29 #include <com/sun/star/container/XNameContainer.hpp>
30 #include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
31 #include <com/sun/star/xml/sax/Parser.hpp>
32 #include <cppuhelper/supportsservice.hxx>
33 
34 
35 using namespace ::dp_misc;
36 using namespace ::com::sun::star;
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star::ucb;
39 using namespace ::com::sun::star::script;
40 
41 
42 namespace dp_registry::backend::sfwk
43 {
44 
45 namespace {
46 
47 class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend
48 {
49     class PackageImpl : public ::dp_registry::backend::Package
50     {
51         BackendImpl * getMyBackend() const;
52 
53         Reference< container::XNameContainer > m_xNameCntrPkgHandler;
54         OUString m_descr;
55 
56         void initPackageHandler();
57 
58         // Package
59         virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
60             ::osl::ResettableMutexGuard & guard,
61             ::rtl::Reference<AbortChannel> const & abortChannel,
62             Reference<XCommandEnvironment> const & xCmdEnv ) override;
63         virtual void processPackage_(
64             ::osl::ResettableMutexGuard & guard,
65             bool registerPackage,
66             bool startup,
67             ::rtl::Reference<AbortChannel> const & abortChannel,
68             Reference<XCommandEnvironment> const & xCmdEnv ) override;
69 
70     public:
71         PackageImpl(
72             ::rtl::Reference<BackendImpl> const & myBackend,
73             OUString const & url, OUString const & libType, bool bRemoved,
74             OUString const & identifier);
75         // XPackage
76         virtual OUString SAL_CALL getDescription() override;
77         virtual OUString SAL_CALL getLicenseText() override;
78     };
79     friend class PackageImpl;
80 
81     // PackageRegistryBackend
82     virtual Reference<deployment::XPackage> bindPackage_(
83         OUString const & url, OUString const & mediaType,
84         bool bRemoved, OUString const & identifier,
85         Reference<XCommandEnvironment> const & xCmdEnv ) override;
86 
87     const Reference<deployment::XPackageTypeInfo> m_xTypeInfo;
88 
89 
90 public:
91     BackendImpl(
92         Sequence<Any> const & args,
93         Reference<XComponentContext> const & xComponentContext );
94 
95     // XServiceInfo
96     virtual OUString SAL_CALL getImplementationName() override;
97     virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
98     virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
99 
100     // XPackageRegistry
101     virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
102     getSupportedPackageTypes() override;
103     virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType) override;
104 };
105 
106 }
107 
getMyBackend() const108 BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
109 {
110     BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
111     if (nullptr == pBackend)
112     {
113         //May throw a DisposedException
114         check();
115         //We should never get here...
116         throw RuntimeException("Failed to get the BackendImpl",
117             static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
118     }
119     return pBackend;
120 }
121 
getDescription()122 OUString BackendImpl::PackageImpl::getDescription()
123 {
124     if (m_descr.isEmpty())
125         return Package::getDescription();
126     else
127         return m_descr;
128 }
129 
getLicenseText()130 OUString BackendImpl::PackageImpl::getLicenseText()
131 {
132     return Package::getDescription();
133 }
134 
PackageImpl(::rtl::Reference<BackendImpl> const & myBackend,OUString const & url,OUString const & libType,bool bRemoved,OUString const & identifier)135 BackendImpl::PackageImpl::PackageImpl(
136     ::rtl::Reference<BackendImpl> const & myBackend,
137     OUString const & url, OUString const & libType, bool bRemoved,
138     OUString const & identifier)
139     : Package( myBackend, url, OUString(), OUString(),
140                myBackend->m_xTypeInfo, bRemoved, identifier),
141       m_descr(libType)
142 {
143     initPackageHandler();
144 
145     sal_Int32 segmEnd = url.getLength();
146     if ( url.endsWith("/") )
147         --segmEnd;
148     sal_Int32 segmStart = url.lastIndexOf( '/', segmEnd ) + 1;
149     if (segmStart < 0)
150         segmStart = 0;
151     // name and display name default the same:
152     m_displayName = ::rtl::Uri::decode(
153         url.copy( segmStart, segmEnd - segmStart ),
154         rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
155     m_name = m_displayName;
156 
157     dp_misc::TRACE("PackageImpl displayName is " + m_displayName);
158 }
159 
160 
BackendImpl(Sequence<Any> const & args,Reference<XComponentContext> const & xComponentContext)161 BackendImpl::BackendImpl(
162     Sequence<Any> const & args,
163     Reference<XComponentContext> const & xComponentContext )
164     : PackageRegistryBackend( args, xComponentContext ),
165       m_xTypeInfo( new Package::TypeInfo(
166                        "application/vnd.sun.star.framework-script",
167                        OUString() /* no file filter */,
168                        "Scripting Framework Script Library"
169                        ) )
170 {
171 }
172 
173 
174 // XServiceInfo
getImplementationName()175 OUString BackendImpl::getImplementationName()
176 {
177     return "com.sun.star.comp.deployment.sfwk.PackageRegistryBackend";
178 }
179 
supportsService(const OUString & ServiceName)180 sal_Bool BackendImpl::supportsService( const OUString& ServiceName )
181 {
182     return cppu::supportsService(this, ServiceName);
183 }
184 
getSupportedServiceNames()185 css::uno::Sequence< OUString > BackendImpl::getSupportedServiceNames()
186 {
187     return { BACKEND_SERVICE_NAME };
188 }
189 
190 // XPackageRegistry
191 
192 Sequence< Reference<deployment::XPackageTypeInfo> >
getSupportedPackageTypes()193 BackendImpl::getSupportedPackageTypes()
194 {
195     return Sequence< Reference<deployment::XPackageTypeInfo> >(&m_xTypeInfo, 1);
196 }
197 
packageRemoved(OUString const &,OUString const &)198 void BackendImpl::packageRemoved(OUString const & /*url*/, OUString const & /*mediaType*/)
199 {
200 }
201 
202 // PackageRegistryBackend
203 
bindPackage_(OUString const & url,OUString const & mediaType_,bool bRemoved,OUString const & identifier,Reference<XCommandEnvironment> const & xCmdEnv)204 Reference<deployment::XPackage> BackendImpl::bindPackage_(
205     OUString const & url, OUString const & mediaType_, bool bRemoved,
206     OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv )
207 {
208     OUString mediaType( mediaType_ );
209     if (mediaType.isEmpty())
210     {
211         // detect media-type:
212         ::ucbhelper::Content ucbContent;
213         if (create_ucb_content( &ucbContent, url, xCmdEnv ) &&
214             ucbContent.isFolder())
215         {
216             // probe for parcel-descriptor.xml:
217             if (create_ucb_content(
218                     nullptr, makeURL( url, "parcel-descriptor.xml" ),
219                     xCmdEnv, false /* no throw */ ))
220             {
221                 mediaType = "application/vnd.sun.star.framework-script";
222             }
223         }
224         if (mediaType.isEmpty())
225             throw lang::IllegalArgumentException(
226                 StrCannotDetectMediaType() + url,
227                 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
228     }
229 
230     OUString type, subType;
231     INetContentTypeParameterList params;
232     if (INetContentTypes::parse( mediaType, type, subType, &params ))
233     {
234         if (type.equalsIgnoreAsciiCase("application"))
235         {
236             if (subType.equalsIgnoreAsciiCase("vnd.sun.star.framework-script"))
237             {
238                 OUString lang = "Script";
239                 OUString sParcelDescURL = makeURL(
240                     url, "parcel-descriptor.xml" );
241 
242                 ::ucbhelper::Content ucb_content;
243 
244                 if (create_ucb_content( &ucb_content, sParcelDescURL,
245                         xCmdEnv, false /* no throw */ ))
246                 {
247                     rtl::Reference<ParcelDescDocHandler> pHandler =
248                         new ParcelDescDocHandler();
249 
250                     Reference<XComponentContext>
251                         xContext( getComponentContext() );
252 
253                     Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(xContext);
254 
255                     xParser->setDocumentHandler( pHandler );
256                     xml::sax::InputSource source;
257                     source.aInputStream = ucb_content.openStream();
258                     source.sSystemId = ucb_content.getURL();
259                     xParser->parseStream( source );
260 
261                     if ( pHandler->isParsed() )
262                     {
263                         lang = pHandler->getParcelLanguage();
264                     }
265                 }
266 
267                 OUString sfwkLibType = DpResId( RID_STR_SFWK_LIB );
268                 // replace %MACRONAME placeholder with language name
269                 OUString MACRONAME( "%MACROLANG" );
270                 sal_Int32 startOfReplace = sfwkLibType.indexOf( MACRONAME );
271                 sal_Int32 charsToReplace = MACRONAME.getLength();
272                 sfwkLibType = sfwkLibType.replaceAt( startOfReplace, charsToReplace, lang );
273                 dp_misc::TRACE("******************************\n");
274                 dp_misc::TRACE(" BackEnd detected lang = " + lang + "\n");
275                 dp_misc::TRACE(" for url " + sParcelDescURL + "\n");
276                 dp_misc::TRACE("******************************\n");
277                 return new PackageImpl( this, url, sfwkLibType, bRemoved, identifier);
278             }
279         }
280     }
281     throw lang::IllegalArgumentException(
282         StrUnsupportedMediaType() + mediaType,
283         static_cast<OWeakObject *>(this),
284         static_cast<sal_Int16>(-1) );
285 }
286 
287 
initPackageHandler()288 void BackendImpl::PackageImpl:: initPackageHandler()
289 {
290     if (m_xNameCntrPkgHandler.is())
291         return;
292 
293     BackendImpl * that = getMyBackend();
294     Any aContext;
295 
296     if ( that->m_eContext == Context::User )
297     {
298         aContext  <<= OUString("user");
299     }
300     else if ( that->m_eContext == Context::Shared )
301     {
302         aContext  <<= OUString("share");
303     }
304     else if ( that->m_eContext == Context::Bundled )
305     {
306         aContext  <<= OUString("bundled");
307     }
308     else
309     {
310         OSL_ASSERT( false );
311         // NOT supported at the moment // TODO
312     }
313 
314     Reference< provider::XScriptProviderFactory > xFac =
315         provider::theMasterScriptProviderFactory::get( that->getComponentContext() );
316 
317     Reference< container::XNameContainer > xName( xFac->createScriptProvider( aContext ), UNO_QUERY );
318     if ( xName.is() )
319     {
320         m_xNameCntrPkgHandler.set( xName );
321     }
322     // TODO what happens if above fails??
323 }
324 
325 // Package
326 
327 beans::Optional< beans::Ambiguous<sal_Bool> >
isRegistered_(::osl::ResettableMutexGuard &,::rtl::Reference<AbortChannel> const &,Reference<XCommandEnvironment> const &)328 BackendImpl::PackageImpl::isRegistered_(
329     ::osl::ResettableMutexGuard &,
330     ::rtl::Reference<AbortChannel> const &,
331     Reference<XCommandEnvironment> const & )
332 {
333     return beans::Optional< beans::Ambiguous<sal_Bool> >(
334         true /* IsPresent */,
335         beans::Ambiguous<sal_Bool>(
336             m_xNameCntrPkgHandler.is() && m_xNameCntrPkgHandler->hasByName(
337                 m_url ),
338             false /* IsAmbiguous */ ) );
339 }
340 
341 
processPackage_(::osl::ResettableMutexGuard &,bool doRegisterPackage,bool,::rtl::Reference<AbortChannel> const &,Reference<XCommandEnvironment> const &)342 void BackendImpl::PackageImpl::processPackage_(
343     ::osl::ResettableMutexGuard &,
344     bool doRegisterPackage,
345     bool /* startup */,
346     ::rtl::Reference<AbortChannel> const &,
347     Reference<XCommandEnvironment> const & )
348 {
349     if ( !m_xNameCntrPkgHandler.is() )
350     {
351         dp_misc::TRACE("no package handler!!!!\n");
352         throw RuntimeException( "No package Handler " );
353     }
354 
355     if (doRegisterPackage)
356     {
357         // will throw if it fails
358         m_xNameCntrPkgHandler->insertByName( m_url, makeAny( Reference< XPackage >(this) ) );
359 
360     }
361     else // revokePackage()
362     {
363         m_xNameCntrPkgHandler->removeByName( m_url );
364     }
365 }
366 
367 } // namespace dp_registry::backend::sfwk
368 
369 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
com_sun_star_comp_deployment_sfwk_PackageRegistryBackend_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const & args)370 com_sun_star_comp_deployment_sfwk_PackageRegistryBackend_get_implementation(
371     css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args)
372 {
373     return cppu::acquire(new dp_registry::backend::sfwk::BackendImpl(args, context));
374 }
375 
376 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
377