Line data Source code
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 :
21 : #include "dp_script.hrc"
22 : #include "dp_lib_container.h"
23 : #include "dp_backend.h"
24 : #include "dp_ucb.h"
25 : #include "rtl/uri.hxx"
26 : #include "ucbhelper/content.hxx"
27 : #include "cppuhelper/exc_hlp.hxx"
28 : #include "cppuhelper/implbase1.hxx"
29 : #include "comphelper/servicedecl.hxx"
30 : #include "svl/inettype.hxx"
31 : #include "com/sun/star/util/XUpdatable.hpp"
32 : #include "com/sun/star/script/XLibraryContainer3.hpp"
33 : #include <com/sun/star/util/XMacroExpander.hpp>
34 : #include <com/sun/star/uri/XUriReferenceFactory.hpp>
35 : #include <memory>
36 : #include "dp_scriptbackenddb.hxx"
37 :
38 : using namespace ::dp_misc;
39 : using namespace ::com::sun::star;
40 : using namespace ::com::sun::star::uno;
41 : using namespace ::com::sun::star::ucb;
42 : using ::rtl::OUString;
43 :
44 : namespace dp_registry {
45 : namespace backend {
46 : namespace script {
47 : namespace {
48 :
49 : typedef ::cppu::ImplInheritanceHelper1<
50 : ::dp_registry::backend::PackageRegistryBackend, util::XUpdatable > t_helper;
51 :
52 0 : class BackendImpl : public t_helper
53 : {
54 0 : class PackageImpl : public ::dp_registry::backend::Package
55 : {
56 : BackendImpl * getMyBackend() const;
57 :
58 : const OUString m_scriptURL;
59 : const OUString m_dialogURL;
60 : OUString m_dialogName;
61 :
62 : // Package
63 : virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
64 : ::osl::ResettableMutexGuard & guard,
65 : ::rtl::Reference<AbortChannel> const & abortChannel,
66 : Reference<XCommandEnvironment> const & xCmdEnv );
67 : virtual void processPackage_(
68 : ::osl::ResettableMutexGuard & guard,
69 : bool registerPackage,
70 : bool startup,
71 : ::rtl::Reference<AbortChannel> const & abortChannel,
72 : Reference<XCommandEnvironment> const & xCmdEnv );
73 :
74 : public:
75 : PackageImpl(
76 : ::rtl::Reference<BackendImpl> const & myBackend,
77 : OUString const & url,
78 : Reference<XCommandEnvironment> const &xCmdEnv,
79 : OUString const & scriptURL, OUString const & dialogURL,
80 : bool bRemoved, OUString const & identifier);
81 : };
82 : friend class PackageImpl;
83 :
84 : // PackageRegistryBackend
85 : virtual Reference<deployment::XPackage> bindPackage_(
86 : OUString const & url, OUString const & mediaType,
87 : sal_Bool bRemoved, OUString const & identifier,
88 : Reference<XCommandEnvironment> const & xCmdEnv );
89 :
90 : void addDataToDb(OUString const & url);
91 : bool hasActiveEntry(OUString const & url);
92 : void revokeEntryFromDb(OUString const & url);
93 :
94 : const Reference<deployment::XPackageTypeInfo> m_xBasicLibTypeInfo;
95 : const Reference<deployment::XPackageTypeInfo> m_xDialogLibTypeInfo;
96 : Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
97 : std::auto_ptr<ScriptBackendDb> m_backendDb;
98 : public:
99 : BackendImpl( Sequence<Any> const & args,
100 : Reference<XComponentContext> const & xComponentContext );
101 :
102 : // XUpdatable
103 : virtual void SAL_CALL update() throw (RuntimeException);
104 :
105 : // XPackageRegistry
106 : virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
107 : getSupportedPackageTypes() throw (RuntimeException);
108 : virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
109 : throw (deployment::DeploymentException,
110 : uno::RuntimeException);
111 :
112 : };
113 :
114 : //______________________________________________________________________________
115 0 : BackendImpl::PackageImpl::PackageImpl(
116 : ::rtl::Reference<BackendImpl> const & myBackend,
117 : OUString const & url,
118 : Reference<XCommandEnvironment> const &xCmdEnv,
119 : OUString const & scriptURL, OUString const & dialogURL, bool bRemoved,
120 : OUString const & identifier)
121 0 : : Package( myBackend.get(), url,
122 : OUString(), OUString(), // will be late-initialized
123 0 : !scriptURL.isEmpty() ? myBackend->m_xBasicLibTypeInfo
124 0 : : myBackend->m_xDialogLibTypeInfo, bRemoved, identifier),
125 : m_scriptURL( scriptURL ),
126 0 : m_dialogURL( dialogURL )
127 : {
128 : // name, displayName:
129 0 : if (!dialogURL.isEmpty()) {
130 : m_dialogName = LibraryContainer::get_libname(
131 0 : dialogURL, xCmdEnv, myBackend->getComponentContext() );
132 : }
133 0 : if (!scriptURL.isEmpty()) {
134 : m_name = LibraryContainer::get_libname(
135 0 : scriptURL, xCmdEnv, myBackend->getComponentContext() );
136 : }
137 : else
138 0 : m_name = m_dialogName;
139 0 : m_displayName = m_name;
140 0 : }
141 :
142 : //______________________________________________________________________________
143 0 : BackendImpl::BackendImpl(
144 : Sequence<Any> const & args,
145 : Reference<XComponentContext> const & xComponentContext )
146 : : t_helper( args, xComponentContext ),
147 : m_xBasicLibTypeInfo( new Package::TypeInfo(
148 : OUSTR("application/"
149 : "vnd.sun.star.basic-library"),
150 : OUString() /* no file filter */,
151 : getResourceString(RID_STR_BASIC_LIB),
152 0 : RID_IMG_SCRIPTLIB) ),
153 : m_xDialogLibTypeInfo( new Package::TypeInfo(
154 : OUSTR("application/"
155 : "vnd.sun.star.dialog-library"),
156 : OUString() /* no file filter */,
157 : getResourceString(RID_STR_DIALOG_LIB),
158 0 : RID_IMG_DIALOGLIB) ),
159 0 : m_typeInfos( 2 )
160 : {
161 0 : m_typeInfos[ 0 ] = m_xBasicLibTypeInfo;
162 0 : m_typeInfos[ 1 ] = m_xDialogLibTypeInfo;
163 :
164 : OSL_ASSERT( ! transientMode() );
165 :
166 0 : if (!transientMode())
167 : {
168 0 : OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml"));
169 : m_backendDb.reset(
170 0 : new ScriptBackendDb(getComponentContext(), dbFile));
171 : }
172 :
173 0 : }
174 0 : void BackendImpl::addDataToDb(OUString const & url)
175 : {
176 0 : if (m_backendDb.get())
177 0 : m_backendDb->addEntry(url);
178 0 : }
179 :
180 0 : bool BackendImpl::hasActiveEntry(OUString const & url)
181 : {
182 0 : if (m_backendDb.get())
183 0 : return m_backendDb->hasActiveEntry(url);
184 0 : return false;
185 : }
186 :
187 : // XUpdatable
188 : //______________________________________________________________________________
189 0 : void BackendImpl::update() throw (RuntimeException)
190 : {
191 : // Nothing to do here after fixing i70283!?
192 0 : }
193 :
194 : // XPackageRegistry
195 : //______________________________________________________________________________
196 : Sequence< Reference<deployment::XPackageTypeInfo> >
197 0 : BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
198 : {
199 0 : return m_typeInfos;
200 : }
201 0 : void BackendImpl::revokeEntryFromDb(OUString const & url)
202 : {
203 0 : if (m_backendDb.get())
204 0 : m_backendDb->revokeEntry(url);
205 0 : }
206 :
207 0 : void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
208 : throw (deployment::DeploymentException,
209 : uno::RuntimeException)
210 : {
211 0 : if (m_backendDb.get())
212 0 : m_backendDb->removeEntry(url);
213 0 : }
214 :
215 : // PackageRegistryBackend
216 : //______________________________________________________________________________
217 0 : Reference<deployment::XPackage> BackendImpl::bindPackage_(
218 : OUString const & url, OUString const & mediaType_,
219 : sal_Bool bRemoved, OUString const & identifier,
220 : Reference<XCommandEnvironment> const & xCmdEnv )
221 : {
222 0 : OUString mediaType( mediaType_ );
223 0 : if (mediaType.isEmpty())
224 : {
225 : // detect media-type:
226 0 : ::ucbhelper::Content ucbContent;
227 0 : if (create_ucb_content( &ucbContent, url, xCmdEnv ) &&
228 0 : ucbContent.isFolder())
229 : {
230 : // probe for script.xlb:
231 0 : if (create_ucb_content(
232 : 0, makeURL( url, OUSTR("script.xlb") ),
233 0 : xCmdEnv, false /* no throw */ ))
234 0 : mediaType = OUSTR("application/vnd.sun.star.basic-library");
235 : // probe for dialog.xlb:
236 0 : else if (create_ucb_content(
237 : 0, makeURL( url, OUSTR("dialog.xlb") ),
238 0 : xCmdEnv, false /* no throw */ ))
239 0 : mediaType = OUSTR("application/vnd.sun.star.dialog-library");
240 : }
241 0 : if (mediaType.isEmpty())
242 : throw lang::IllegalArgumentException(
243 0 : StrCannotDetectMediaType::get() + url,
244 0 : static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
245 : }
246 :
247 0 : OUString type, subType;
248 0 : INetContentTypeParameterList params;
249 0 : if (INetContentTypes::parse( mediaType, type, subType, ¶ms ))
250 : {
251 0 : if (type.equalsIgnoreAsciiCaseAscii("application"))
252 : {
253 0 : OUString dialogURL( makeURL( url, OUSTR("dialog.xlb") ) );
254 0 : if (! create_ucb_content(
255 0 : 0, dialogURL, xCmdEnv, false /* no throw */ )) {
256 0 : dialogURL = OUString();
257 : }
258 :
259 0 : if (subType.equalsIgnoreAsciiCaseAscii("vnd.sun.star.basic-library"))
260 : {
261 0 : OUString scriptURL( makeURL( url, OUSTR("script.xlb")));
262 0 : if (! create_ucb_content(
263 0 : 0, scriptURL, xCmdEnv, false /* no throw */ )) {
264 0 : scriptURL = OUString();
265 : }
266 :
267 : return new PackageImpl(
268 : this, url, xCmdEnv, scriptURL,
269 0 : dialogURL, bRemoved, identifier);
270 : }
271 0 : else if (subType.equalsIgnoreAsciiCaseAscii(
272 0 : "vnd.sun.star.dialog-library")) {
273 : return new PackageImpl(
274 : this, url, xCmdEnv,
275 : OUString() /* no script lib */,
276 : dialogURL,
277 0 : bRemoved, identifier);
278 0 : }
279 : }
280 : }
281 : throw lang::IllegalArgumentException(
282 0 : StrUnsupportedMediaType::get() + mediaType,
283 : static_cast<OWeakObject *>(this),
284 0 : static_cast<sal_Int16>(-1) );
285 : }
286 :
287 :
288 : // Package
289 0 : BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
290 : {
291 0 : BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
292 0 : if (NULL == pBackend)
293 : {
294 : //May throw a DisposedException
295 0 : check();
296 : //We should never get here...
297 : throw RuntimeException(
298 : OUSTR("Failed to get the BackendImpl"),
299 0 : static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
300 : }
301 0 : return pBackend;
302 : }
303 :
304 : beans::Optional< beans::Ambiguous<sal_Bool> >
305 0 : BackendImpl::PackageImpl::isRegistered_(
306 : ::osl::ResettableMutexGuard & /* guard */,
307 : ::rtl::Reference<AbortChannel> const & /* abortChannel */,
308 : Reference<XCommandEnvironment> const & /* xCmdEnv */ )
309 : {
310 0 : BackendImpl * that = getMyBackend();
311 0 : Reference< deployment::XPackage > xThisPackage( this );
312 :
313 0 : bool registered = that->hasActiveEntry(getURL());
314 : return beans::Optional< beans::Ambiguous<sal_Bool> >(
315 : true /* IsPresent */,
316 0 : beans::Ambiguous<sal_Bool>( registered, false /* IsAmbiguous */ ) );
317 : }
318 :
319 : void
320 0 : lcl_maybeRemoveScript(
321 : bool const bExists,
322 : OUString const& rName,
323 : OUString const& rScriptURL,
324 : Reference<css::script::XLibraryContainer3> const& xScriptLibs)
325 : {
326 0 : if (bExists && xScriptLibs.is() && xScriptLibs->hasByName(rName))
327 : {
328 0 : const OUString sScriptUrl = xScriptLibs->getOriginalLibraryLinkURL(rName);
329 0 : if (sScriptUrl.equals(rScriptURL))
330 0 : xScriptLibs->removeLibrary(rName);
331 : }
332 0 : }
333 :
334 : bool
335 0 : lcl_maybeAddScript(
336 : bool const bExists,
337 : OUString const& rName,
338 : OUString const& rScriptURL,
339 : Reference<css::script::XLibraryContainer3> const& xScriptLibs)
340 : {
341 0 : if (bExists && xScriptLibs.is())
342 : {
343 0 : bool bCanAdd = true;
344 0 : if (xScriptLibs->hasByName(rName))
345 : {
346 0 : const OUString sOriginalUrl = xScriptLibs->getOriginalLibraryLinkURL(rName);
347 : //We assume here that library names in extensions are unique, which may not be the case
348 : //ToDo: If the script exist in another extension, then both extensions must have the
349 : //same id
350 0 : if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE"))
351 0 : || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE"))
352 0 : || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS")))
353 : {
354 0 : xScriptLibs->removeLibrary(rName);
355 0 : bCanAdd = true;
356 : }
357 : else
358 : {
359 0 : bCanAdd = false;
360 0 : }
361 : }
362 :
363 0 : if (bCanAdd)
364 : {
365 0 : xScriptLibs->createLibraryLink(rName, rScriptURL, false);
366 0 : return xScriptLibs->hasByName(rName);
367 : }
368 : }
369 :
370 0 : return false;
371 : }
372 :
373 0 : void BackendImpl::PackageImpl::processPackage_(
374 : ::osl::ResettableMutexGuard & /* guard */,
375 : bool doRegisterPackage,
376 : bool startup,
377 : ::rtl::Reference<AbortChannel> const & /* abortChannel */,
378 : Reference<XCommandEnvironment> const & /* xCmdEnv */ )
379 : {
380 0 : BackendImpl * that = getMyBackend();
381 :
382 0 : Reference< deployment::XPackage > xThisPackage( this );
383 0 : Reference<XComponentContext> const & xComponentContext = that->getComponentContext();
384 :
385 0 : bool bScript = !m_scriptURL.isEmpty();
386 0 : Reference<css::script::XLibraryContainer3> xScriptLibs;
387 :
388 0 : bool bDialog = !m_dialogURL.isEmpty();
389 0 : Reference<css::script::XLibraryContainer3> xDialogLibs;
390 :
391 0 : bool bRunning = !startup && office_is_running();
392 0 : if( bRunning )
393 : {
394 0 : if( bScript )
395 : {
396 : xScriptLibs.set(
397 0 : xComponentContext->getServiceManager()->createInstanceWithContext(
398 : OUSTR("com.sun.star.script.ApplicationScriptLibraryContainer"),
399 0 : xComponentContext ), UNO_QUERY_THROW );
400 : }
401 :
402 0 : if( bDialog )
403 : {
404 : xDialogLibs.set(
405 0 : xComponentContext->getServiceManager()->createInstanceWithContext(
406 : OUSTR("com.sun.star.script.ApplicationDialogLibraryContainer"),
407 0 : xComponentContext ), UNO_QUERY_THROW );
408 : }
409 : }
410 0 : bool bRegistered = getMyBackend()->hasActiveEntry(getURL());
411 0 : if( !doRegisterPackage )
412 : {
413 : //We cannot just call removeLibrary(name) because this could remove a
414 : //script which was added by an extension in a different repository. For
415 : //example, extension foo is contained in the bundled repository and then
416 : //the user adds it it to the user repository. The extension manager will
417 : //then register the new script and revoke the script from the bundled
418 : //extension. removeLibrary(name) would now remove the script from the
419 : //user repository. That is, the script of the newly added user extension does
420 : //not work anymore. Therefore we must check if the currently active
421 : //script comes in fact from the currently processed extension.
422 :
423 0 : if (bRegistered)
424 : {
425 : //we also prevent and live deployment at startup
426 0 : if (!isRemoved() && !startup)
427 : {
428 0 : lcl_maybeRemoveScript(bScript, m_name, m_scriptURL, xScriptLibs);
429 0 : lcl_maybeRemoveScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs);
430 : }
431 0 : getMyBackend()->revokeEntryFromDb(getURL());
432 : return;
433 : }
434 : }
435 0 : if (bRegistered)
436 : return; // Already registered
437 :
438 : // Update LibraryContainer
439 0 : bool bScriptSuccess = false;
440 0 : bool bDialogSuccess = false;
441 0 : if (!startup)
442 : {
443 : //If there is a bundled extension, and the user installes the same extension
444 : //then the script from the bundled extension must be removed. If this does not work
445 : //then live deployment does not work for scripts.
446 0 : bScriptSuccess = lcl_maybeAddScript(bScript, m_name, m_scriptURL, xScriptLibs);
447 0 : bDialogSuccess = lcl_maybeAddScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs);
448 : }
449 0 : bool bSuccess = bScript || bDialog; // Something must have happened
450 0 : if( bRunning )
451 0 : if( (bScript && !bScriptSuccess) || (bDialog && !bDialogSuccess) )
452 0 : bSuccess = false;
453 :
454 0 : if (bSuccess)
455 0 : getMyBackend()->addDataToDb(getURL());
456 : }
457 :
458 : } // anon namespace
459 :
460 : namespace sdecl = comphelper::service_decl;
461 1 : sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
462 1 : extern sdecl::ServiceDecl const serviceDecl(
463 : serviceBI,
464 : "com.sun.star.comp.deployment.script.PackageRegistryBackend",
465 : BACKEND_SERVICE_NAME );
466 :
467 : } // namespace script
468 : } // namespace backend
469 3 : } // namespace dp_registry
470 :
471 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|