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 : //TODO: Large parts of this file were copied from dp_component.cxx; those parts
22 : // should be consolidated.
23 :
24 : #include "dp_configuration.hrc"
25 : #include "dp_backend.h"
26 : #if !defined(ANDROID) && !defined(IOS)
27 : #include "dp_persmap.h"
28 : #endif
29 : #include "dp_ucb.h"
30 : #include "rtl/string.hxx"
31 : #include "rtl/ustrbuf.hxx"
32 : #include "rtl/uri.hxx"
33 : #include "osl/file.hxx"
34 : #include "cppuhelper/exc_hlp.hxx"
35 : #include "ucbhelper/content.hxx"
36 : #include "unotools/ucbhelper.hxx"
37 : #include "comphelper/anytostring.hxx"
38 : #include "comphelper/servicedecl.hxx"
39 : #include "xmlscript/xml_helper.hxx"
40 : #include "svl/inettype.hxx"
41 : #include "com/sun/star/configuration/Update.hpp"
42 : #include "com/sun/star/ucb/NameClash.hpp"
43 : #include "com/sun/star/io/XActiveDataSink.hpp"
44 : #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
45 : #include "com/sun/star/util/XRefreshable.hpp"
46 : #include <list>
47 : #include <memory>
48 :
49 : #include "dp_configurationbackenddb.hxx"
50 :
51 : using namespace ::dp_misc;
52 : using namespace ::com::sun::star;
53 : using namespace ::com::sun::star::uno;
54 : using namespace ::com::sun::star::ucb;
55 : using ::rtl::OUString;
56 :
57 : namespace dp_registry {
58 : namespace backend {
59 : namespace configuration {
60 : namespace {
61 :
62 : typedef ::std::list<OUString> t_stringlist;
63 :
64 : //==============================================================================
65 6 : class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend
66 : {
67 100 : class PackageImpl : public ::dp_registry::backend::Package
68 : {
69 : BackendImpl * getMyBackend() const ;
70 :
71 : const bool m_isSchema;
72 :
73 : // Package
74 : virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
75 : ::osl::ResettableMutexGuard & guard,
76 : ::rtl::Reference<AbortChannel> const & abortChannel,
77 : Reference<XCommandEnvironment> const & xCmdEnv );
78 : virtual void processPackage_(
79 : ::osl::ResettableMutexGuard & guard,
80 : bool registerPackage,
81 : bool startup,
82 : ::rtl::Reference<AbortChannel> const & abortChannel,
83 : Reference<XCommandEnvironment> const & xCmdEnv );
84 :
85 : public:
86 50 : inline PackageImpl(
87 : ::rtl::Reference<PackageRegistryBackend> const & myBackend,
88 : OUString const & url, OUString const & name,
89 : Reference<deployment::XPackageTypeInfo> const & xPackageType,
90 : bool isSchema, bool bRemoved, OUString const & identifier)
91 : : Package( myBackend, url, name, name /* display-name */,
92 : xPackageType, bRemoved, identifier),
93 50 : m_isSchema( isSchema )
94 50 : {}
95 : };
96 : friend class PackageImpl;
97 :
98 : t_stringlist m_xcs_files;
99 : t_stringlist m_xcu_files;
100 0 : t_stringlist & getFiles( bool xcs ) {
101 0 : return xcs ? m_xcs_files : m_xcu_files;
102 : }
103 :
104 : bool m_configmgrini_inited;
105 : bool m_configmgrini_modified;
106 : std::auto_ptr<ConfigurationBackendDb> m_backendDb;
107 :
108 : // PackageRegistryBackend
109 : virtual Reference<deployment::XPackage> bindPackage_(
110 : OUString const & url, OUString const & mediaType, sal_Bool bRemoved,
111 : OUString const & identifier,
112 : Reference<XCommandEnvironment> const & xCmdEnv );
113 : #if !defined(ANDROID) && !defined(IOS)
114 : // for backwards compatibility - nil if no (compatible) back-compat db present
115 : ::std::auto_ptr<PersistentMap> m_registeredPackages;
116 : #endif
117 : virtual void SAL_CALL disposing();
118 :
119 : const Reference<deployment::XPackageTypeInfo> m_xConfDataTypeInfo;
120 : const Reference<deployment::XPackageTypeInfo> m_xConfSchemaTypeInfo;
121 : Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
122 :
123 : void configmgrini_verify_init(
124 : Reference<XCommandEnvironment> const & xCmdEnv );
125 : void configmgrini_flush( Reference<XCommandEnvironment> const & xCmdEnv );
126 :
127 : /* The paramter isURL is false in the case of adding the conf:ini-entry
128 : value from the backend db. This entry already contains the path as it
129 : is used in the configmgr.ini.
130 : */
131 : bool addToConfigmgrIni( bool isSchema, bool isURL, OUString const & url,
132 : Reference<XCommandEnvironment> const & xCmdEnv );
133 : bool removeFromConfigmgrIni( bool isSchema, OUString const & url,
134 : Reference<XCommandEnvironment> const & xCmdEnv );
135 :
136 : void addDataToDb(OUString const & url, ConfigurationBackendDb::Data const & data);
137 : ::boost::optional<ConfigurationBackendDb::Data> readDataFromDb(OUString const & url);
138 : void revokeEntryFromDb(OUString const & url);
139 : bool hasActiveEntry(OUString const & url);
140 : bool activateEntry(OUString const & url);
141 :
142 : public:
143 : BackendImpl( Sequence<Any> const & args,
144 : Reference<XComponentContext> const & xComponentContext );
145 :
146 : // XPackageRegistry
147 : virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
148 : getSupportedPackageTypes() throw (RuntimeException);
149 : virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
150 : throw (deployment::DeploymentException,
151 : uno::RuntimeException);
152 :
153 : using PackageRegistryBackend::disposing;
154 : };
155 :
156 : //______________________________________________________________________________
157 6 : void BackendImpl::disposing()
158 : {
159 : try {
160 6 : configmgrini_flush( Reference<XCommandEnvironment>() );
161 :
162 6 : PackageRegistryBackend::disposing();
163 : }
164 0 : catch (const RuntimeException &) {
165 0 : throw;
166 : }
167 0 : catch (const Exception &) {
168 0 : Any exc( ::cppu::getCaughtException() );
169 : throw lang::WrappedTargetRuntimeException(
170 : OUSTR("caught unexpected exception while disposing..."),
171 0 : static_cast<OWeakObject *>(this), exc );
172 : }
173 6 : }
174 :
175 : //______________________________________________________________________________
176 6 : BackendImpl::BackendImpl(
177 : Sequence<Any> const & args,
178 : Reference<XComponentContext> const & xComponentContext )
179 : : PackageRegistryBackend( args, xComponentContext ),
180 : m_configmgrini_inited( false ),
181 : m_configmgrini_modified( false ),
182 : m_xConfDataTypeInfo( new Package::TypeInfo(
183 : OUSTR("application/"
184 : "vnd.sun.star.configuration-data"),
185 : OUSTR("*.xcu"),
186 : getResourceString(RID_STR_CONF_DATA),
187 6 : RID_IMG_CONF_XML ) ),
188 : m_xConfSchemaTypeInfo( new Package::TypeInfo(
189 : OUSTR("application/"
190 : "vnd.sun.star.configuration-schema"),
191 : OUSTR("*.xcs"),
192 : getResourceString(RID_STR_CONF_SCHEMA),
193 6 : RID_IMG_CONF_XML ) ),
194 18 : m_typeInfos( 2 )
195 : {
196 6 : m_typeInfos[ 0 ] = m_xConfDataTypeInfo;
197 6 : m_typeInfos[ 1 ] = m_xConfSchemaTypeInfo;
198 :
199 6 : const Reference<XCommandEnvironment> xCmdEnv;
200 :
201 6 : if (transientMode())
202 : {
203 : // TODO
204 : }
205 : else
206 : {
207 6 : OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml"));
208 : m_backendDb.reset(
209 6 : new ConfigurationBackendDb(getComponentContext(), dbFile));
210 : //clean up data folders which are no longer used.
211 : //This must not be done in the same process where the help files
212 : //are still registers. Only after revoking and restarting OOo the folders
213 : //can be removed. This works now, because the extension manager is a singleton
214 : //and the backends are only create once per process.
215 6 : ::std::list<OUString> folders = m_backendDb->getAllDataUrls();
216 6 : deleteUnusedFolders(OUString(), folders);
217 :
218 6 : configmgrini_verify_init( xCmdEnv );
219 :
220 : #if !defined(ANDROID) && !defined(IOS)
221 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
222 6 : ::std::auto_ptr<PersistentMap> pMap;
223 : SAL_WNODEPRECATED_DECLARATIONS_POP
224 6 : rtl::OUString aCompatURL( makeURL( getCachePath(), OUSTR("registered_packages.pmap") ) );
225 :
226 : // Don't create it if it doesn't exist already
227 6 : if ( ::utl::UCBContentHelper::Exists( expandUnoRcUrl( aCompatURL ) ) )
228 : {
229 : try
230 : {
231 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
232 0 : pMap = ::std::auto_ptr<PersistentMap>( new PersistentMap( aCompatURL, false ) );
233 : SAL_WNODEPRECATED_DECLARATIONS_POP
234 : }
235 0 : catch (const Exception &e)
236 : {
237 0 : rtl::OUStringBuffer aStr( "Exception loading legacy package database: '" );
238 0 : aStr.append( e.Message );
239 0 : aStr.append( "' - ignoring file, please remove it.\n" );
240 0 : dp_misc::writeConsole( aStr.getStr() );
241 : }
242 : }
243 6 : m_registeredPackages = pMap;
244 : #endif
245 6 : }
246 6 : }
247 :
248 0 : void BackendImpl::addDataToDb(
249 : OUString const & url, ConfigurationBackendDb::Data const & data)
250 : {
251 0 : if (m_backendDb.get())
252 0 : m_backendDb->addEntry(url, data);
253 0 : }
254 :
255 0 : ::boost::optional<ConfigurationBackendDb::Data> BackendImpl::readDataFromDb(
256 : OUString const & url)
257 : {
258 0 : ::boost::optional<ConfigurationBackendDb::Data> data;
259 0 : if (m_backendDb.get())
260 0 : data = m_backendDb->getEntry(url);
261 0 : return data;
262 : }
263 :
264 0 : void BackendImpl::revokeEntryFromDb(OUString const & url)
265 : {
266 0 : if (m_backendDb.get())
267 0 : m_backendDb->revokeEntry(url);
268 0 : }
269 :
270 100 : bool BackendImpl::hasActiveEntry(OUString const & url)
271 : {
272 100 : if (m_backendDb.get())
273 100 : return m_backendDb->hasActiveEntry(url);
274 0 : return false;
275 : }
276 :
277 0 : bool BackendImpl::activateEntry(OUString const & url)
278 : {
279 0 : if (m_backendDb.get())
280 0 : return m_backendDb->activateEntry(url);
281 0 : return false;
282 : }
283 :
284 :
285 :
286 : // XPackageRegistry
287 : //______________________________________________________________________________
288 : Sequence< Reference<deployment::XPackageTypeInfo> >
289 6 : BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
290 : {
291 6 : return m_typeInfos;
292 : }
293 0 : void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
294 : throw (deployment::DeploymentException,
295 : uno::RuntimeException)
296 : {
297 0 : if (m_backendDb.get())
298 0 : m_backendDb->removeEntry(url);
299 0 : }
300 :
301 : // PackageRegistryBackend
302 : //______________________________________________________________________________
303 50 : Reference<deployment::XPackage> BackendImpl::bindPackage_(
304 : OUString const & url, OUString const & mediaType_,
305 : sal_Bool bRemoved, OUString const & identifier,
306 : Reference<XCommandEnvironment> const & xCmdEnv )
307 : {
308 50 : OUString mediaType( mediaType_ );
309 50 : if (mediaType.isEmpty())
310 : {
311 : // detect media-type:
312 0 : ::ucbhelper::Content ucbContent;
313 0 : if (create_ucb_content( &ucbContent, url, xCmdEnv ))
314 : {
315 0 : const OUString title( StrTitle::getTitle( ucbContent ) );
316 0 : if (title.endsWithIgnoreAsciiCaseAsciiL(
317 : RTL_CONSTASCII_STRINGPARAM(".xcu") )) {
318 0 : mediaType = OUSTR("application/"
319 0 : "vnd.sun.star.configuration-data");
320 : }
321 0 : if (title.endsWithIgnoreAsciiCaseAsciiL(
322 : RTL_CONSTASCII_STRINGPARAM(".xcs") )) {
323 0 : mediaType = OUSTR("application/"
324 0 : "vnd.sun.star.configuration-schema");
325 0 : }
326 : }
327 0 : if (mediaType.isEmpty())
328 : throw lang::IllegalArgumentException(
329 0 : StrCannotDetectMediaType::get() + url,
330 0 : static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
331 : }
332 :
333 50 : OUString type, subType;
334 50 : INetContentTypeParameterList params;
335 50 : if (INetContentTypes::parse( mediaType, type, subType, ¶ms ))
336 : {
337 50 : if (type.equalsIgnoreAsciiCaseAscii("application"))
338 : {
339 50 : OUString name;
340 50 : if (!bRemoved)
341 : {
342 50 : ::ucbhelper::Content ucbContent( url, xCmdEnv, m_xComponentContext );
343 50 : name = StrTitle::getTitle( ucbContent );
344 : }
345 :
346 50 : ::ucbhelper::Content ucbContent( url, xCmdEnv, m_xComponentContext );
347 50 : if (subType.equalsIgnoreAsciiCaseAscii( "vnd.sun.star.configuration-data"))
348 : {
349 : return new PackageImpl(
350 : this, url, name, m_xConfDataTypeInfo, false /* data file */,
351 40 : bRemoved, identifier);
352 : }
353 10 : else if (subType.equalsIgnoreAsciiCaseAscii( "vnd.sun.star.configuration-schema")) {
354 : return new PackageImpl(
355 : this, url, name, m_xConfSchemaTypeInfo, true /* schema file */,
356 10 : bRemoved, identifier);
357 50 : }
358 : }
359 : }
360 : throw lang::IllegalArgumentException(
361 0 : StrUnsupportedMediaType::get() + mediaType,
362 : static_cast<OWeakObject *>(this),
363 50 : static_cast<sal_Int16>(-1) );
364 : }
365 :
366 :
367 : //______________________________________________________________________________
368 6 : void BackendImpl::configmgrini_verify_init(
369 : Reference<XCommandEnvironment> const & xCmdEnv )
370 : {
371 6 : if (transientMode())
372 6 : return;
373 6 : const ::osl::MutexGuard guard( getMutex() );
374 6 : if (! m_configmgrini_inited)
375 : {
376 : // common rc:
377 6 : ::ucbhelper::Content ucb_content;
378 12 : if (create_ucb_content(
379 : &ucb_content,
380 6 : makeURL( getCachePath(), OUSTR("configmgr.ini") ),
381 18 : xCmdEnv, false /* no throw */ ))
382 : {
383 2 : OUString line;
384 4 : if (readLine( &line, OUSTR("SCHEMA="), ucb_content,
385 4 : RTL_TEXTENCODING_UTF8 ))
386 : {
387 2 : sal_Int32 index = RTL_CONSTASCII_LENGTH("SCHEMA=");
388 10 : do {
389 10 : OUString token( line.getToken( 0, ' ', index ).trim() );
390 10 : if (!token.isEmpty()) {
391 : //The file may not exist anymore if a shared or bundled
392 : //extension was removed, but it can still be in the configmgrini.
393 : //After running XExtensionManager::synchronize, the configmgrini is
394 : //cleaned up
395 10 : m_xcs_files.push_back( token );
396 10 : }
397 : }
398 : while (index >= 0);
399 : }
400 4 : if (readLine( &line, OUSTR("DATA="), ucb_content,
401 4 : RTL_TEXTENCODING_UTF8 )) {
402 2 : sal_Int32 index = RTL_CONSTASCII_LENGTH("DATA=");
403 40 : do {
404 40 : OUString token( line.getToken( 0, ' ', index ).trim() );
405 40 : if (!token.isEmpty())
406 : {
407 40 : if (token[ 0 ] == '?')
408 0 : token = token.copy( 1 );
409 : //The file may not exist anymore if a shared or bundled
410 : //extension was removed, but it can still be in the configmgrini.
411 : //After running XExtensionManager::synchronize, the configmgrini is
412 : //cleaned up
413 40 : m_xcu_files.push_back( token );
414 40 : }
415 : }
416 : while (index >= 0);
417 2 : }
418 : }
419 6 : m_configmgrini_modified = false;
420 6 : m_configmgrini_inited = true;
421 6 : }
422 : }
423 :
424 : //______________________________________________________________________________
425 6 : void BackendImpl::configmgrini_flush(
426 : Reference<XCommandEnvironment> const & xCmdEnv )
427 : {
428 6 : if (transientMode())
429 : return;
430 6 : if (!m_configmgrini_inited || !m_configmgrini_modified)
431 : return;
432 :
433 0 : ::rtl::OStringBuffer buf;
434 0 : if (! m_xcs_files.empty())
435 : {
436 0 : t_stringlist::const_iterator iPos( m_xcs_files.begin() );
437 0 : t_stringlist::const_iterator const iEnd( m_xcs_files.end() );
438 0 : buf.append( RTL_CONSTASCII_STRINGPARAM("SCHEMA=") );
439 0 : while (iPos != iEnd) {
440 : // encoded ASCII file-urls:
441 : const ::rtl::OString item(
442 0 : ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) );
443 0 : buf.append( item );
444 0 : ++iPos;
445 0 : if (iPos != iEnd)
446 0 : buf.append( ' ' );
447 0 : }
448 0 : buf.append(LF);
449 : }
450 0 : if (! m_xcu_files.empty())
451 : {
452 0 : t_stringlist::const_iterator iPos( m_xcu_files.begin() );
453 0 : t_stringlist::const_iterator const iEnd( m_xcu_files.end() );
454 0 : buf.append( RTL_CONSTASCII_STRINGPARAM("DATA=") );
455 0 : while (iPos != iEnd) {
456 : // encoded ASCII file-urls:
457 : const ::rtl::OString item(
458 0 : ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) );
459 0 : buf.append( item );
460 0 : ++iPos;
461 0 : if (iPos != iEnd)
462 0 : buf.append( ' ' );
463 0 : }
464 0 : buf.append(LF);
465 : }
466 :
467 : // write configmgr.ini:
468 : const Reference<io::XInputStream> xData(
469 : ::xmlscript::createInputStream(
470 : ::rtl::ByteSequence(
471 0 : reinterpret_cast<sal_Int8 const *>(buf.getStr()),
472 0 : buf.getLength() ) ) );
473 : ::ucbhelper::Content ucb_content(
474 0 : makeURL( getCachePath(), OUSTR("configmgr.ini") ), xCmdEnv, m_xComponentContext );
475 0 : ucb_content.writeStream( xData, true /* replace existing */ );
476 :
477 0 : m_configmgrini_modified = false;
478 : }
479 :
480 : //______________________________________________________________________________
481 0 : bool BackendImpl::addToConfigmgrIni( bool isSchema, bool isURL, OUString const & url_,
482 : Reference<XCommandEnvironment> const & xCmdEnv )
483 : {
484 0 : const OUString rcterm( isURL ? dp_misc::makeRcTerm(url_) : url_ );
485 0 : const ::osl::MutexGuard guard( getMutex() );
486 0 : configmgrini_verify_init( xCmdEnv );
487 0 : t_stringlist & rSet = getFiles(isSchema);
488 0 : if (::std::find( rSet.begin(), rSet.end(), rcterm ) == rSet.end()) {
489 0 : rSet.push_front( rcterm ); // prepend to list, thus overriding
490 : // write immediately:
491 0 : m_configmgrini_modified = true;
492 0 : configmgrini_flush( xCmdEnv );
493 0 : return true;
494 : }
495 : else
496 0 : return false;
497 : }
498 :
499 : //______________________________________________________________________________
500 0 : bool BackendImpl::removeFromConfigmgrIni(
501 : bool isSchema, OUString const & url_,
502 : Reference<XCommandEnvironment> const & xCmdEnv )
503 : {
504 0 : const OUString rcterm( dp_misc::makeRcTerm(url_) );
505 0 : const ::osl::MutexGuard guard( getMutex() );
506 0 : configmgrini_verify_init( xCmdEnv );
507 0 : t_stringlist & rSet = getFiles(isSchema);
508 0 : t_stringlist::iterator i(std::find(rSet.begin(), rSet.end(), rcterm));
509 0 : if (i == rSet.end() && !isSchema)
510 : {
511 : //in case the xcu contained %origin% then the configmr.ini contains the
512 : //url to the file in the user installation (e.g. $BUNDLED_EXTENSIONS_USER)
513 : //However, m_url (getURL()) contains the URL for the file in the actual
514 : //extension installatation.
515 0 : ::boost::optional<ConfigurationBackendDb::Data> data = readDataFromDb(url_);
516 0 : if (data)
517 0 : i = std::find(rSet.begin(), rSet.end(), data->iniEntry);
518 : }
519 0 : if (i == rSet.end()) {
520 0 : return false;
521 : }
522 0 : rSet.erase(i);
523 : // write immediately:
524 0 : m_configmgrini_modified = true;
525 0 : configmgrini_flush( xCmdEnv );
526 0 : return true;
527 : }
528 :
529 :
530 : // Package
531 : //______________________________________________________________________________
532 :
533 100 : BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
534 : {
535 100 : BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
536 100 : if (NULL == pBackend)
537 : {
538 : //May throw a DisposedException
539 0 : check();
540 : //We should never get here...
541 : throw RuntimeException(
542 : OUSTR("Failed to get the BackendImpl"),
543 0 : static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
544 : }
545 100 : return pBackend;
546 : }
547 :
548 : beans::Optional< beans::Ambiguous<sal_Bool> >
549 100 : BackendImpl::PackageImpl::isRegistered_(
550 : ::osl::ResettableMutexGuard &,
551 : ::rtl::Reference<AbortChannel> const &,
552 : Reference<XCommandEnvironment> const & )
553 : {
554 100 : BackendImpl * that = getMyBackend();
555 100 : const rtl::OUString url(getURL());
556 :
557 100 : bool bReg = false;
558 100 : if (that->hasActiveEntry(getURL()))
559 100 : bReg = true;
560 : #if !defined(ANDROID) && !defined(IOS)
561 100 : if (!bReg && that->m_registeredPackages.get())
562 : {
563 : // fallback for user extension registered in berkeley DB
564 : bReg = that->m_registeredPackages->has(
565 0 : rtl::OUStringToOString( url, RTL_TEXTENCODING_UTF8 ));
566 : }
567 : #endif
568 : return beans::Optional< beans::Ambiguous<sal_Bool> >(
569 100 : true, beans::Ambiguous<sal_Bool>( bReg, false ) );
570 : }
571 :
572 : //------------------------------------------------------------------------------
573 0 : OUString encodeForXml( OUString const & text )
574 : {
575 : // encode conforming xml:
576 0 : sal_Int32 len = text.getLength();
577 0 : ::rtl::OUStringBuffer buf;
578 0 : for ( sal_Int32 pos = 0; pos < len; ++pos )
579 : {
580 0 : sal_Unicode c = text[ pos ];
581 0 : switch (c) {
582 : case '<':
583 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("<") );
584 0 : break;
585 : case '>':
586 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(">") );
587 0 : break;
588 : case '&':
589 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("&") );
590 0 : break;
591 : case '\'':
592 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("'") );
593 0 : break;
594 : case '\"':
595 0 : buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(""") );
596 0 : break;
597 : default:
598 0 : buf.append( c );
599 0 : break;
600 : }
601 : }
602 0 : return buf.makeStringAndClear();
603 : }
604 :
605 : //______________________________________________________________________________
606 0 : OUString replaceOrigin(
607 : OUString const & url, OUString const & destFolder, Reference< XCommandEnvironment > const & xCmdEnv, Reference< XComponentContext > const & xContext, bool & out_replaced)
608 : {
609 : // looking for %origin%:
610 0 : ::ucbhelper::Content ucb_content( url, xCmdEnv, xContext );
611 0 : ::rtl::ByteSequence bytes( readFile( ucb_content ) );
612 0 : ::rtl::ByteSequence filtered( bytes.getLength() * 2,
613 0 : ::rtl::BYTESEQ_NODEFAULT );
614 0 : bool use_filtered = false;
615 0 : ::rtl::OString origin;
616 : sal_Char const * pBytes = reinterpret_cast<sal_Char const *>(
617 0 : bytes.getConstArray());
618 0 : sal_Size nBytes = bytes.getLength();
619 0 : sal_Int32 write_pos = 0;
620 0 : while (nBytes > 0)
621 : {
622 0 : sal_Int32 index = rtl_str_indexOfChar_WithLength( pBytes, nBytes, '%' );
623 0 : if (index < 0) {
624 0 : if (! use_filtered) // opt
625 0 : break;
626 0 : index = nBytes;
627 : }
628 :
629 0 : if ((write_pos + index) > filtered.getLength())
630 0 : filtered.realloc( (filtered.getLength() + index) * 2 );
631 0 : memcpy( filtered.getArray() + write_pos, pBytes, index );
632 0 : write_pos += index;
633 0 : pBytes += index;
634 0 : nBytes -= index;
635 0 : if (nBytes == 0)
636 0 : break;
637 :
638 : // consume %:
639 0 : ++pBytes;
640 0 : --nBytes;
641 0 : sal_Char const * pAdd = "%";
642 0 : sal_Int32 nAdd = 1;
643 0 : if (nBytes > 1 && pBytes[ 0 ] == '%')
644 : {
645 : // %% => %
646 0 : ++pBytes;
647 0 : --nBytes;
648 0 : use_filtered = true;
649 : }
650 0 : else if (rtl_str_shortenedCompare_WithLength(
651 : pBytes, nBytes,
652 : RTL_CONSTASCII_STRINGPARAM("origin%"),
653 0 : RTL_CONSTASCII_LENGTH("origin%")) == 0)
654 : {
655 0 : if (origin.isEmpty()) {
656 : // encode only once
657 : origin = ::rtl::OUStringToOString(
658 : encodeForXml( url.copy( 0, url.lastIndexOf( '/' ) ) ),
659 : // xxx todo: encode always for UTF-8? => lookup doc-header?
660 0 : RTL_TEXTENCODING_UTF8 );
661 : }
662 0 : pAdd = origin.getStr();
663 0 : nAdd = origin.getLength();
664 0 : pBytes += RTL_CONSTASCII_LENGTH("origin%");
665 0 : nBytes -= RTL_CONSTASCII_LENGTH("origin%");
666 0 : use_filtered = true;
667 : }
668 0 : if ((write_pos + nAdd) > filtered.getLength())
669 0 : filtered.realloc( (filtered.getLength() + nAdd) * 2 );
670 0 : memcpy( filtered.getArray() + write_pos, pAdd, nAdd );
671 0 : write_pos += nAdd;
672 : }
673 0 : if (!use_filtered)
674 0 : return url;
675 0 : if (write_pos < filtered.getLength())
676 0 : filtered.realloc( write_pos );
677 0 : rtl::OUString newUrl(url);
678 0 : if (!destFolder.isEmpty())
679 : {
680 : //get the file name of the xcu and add it to the url of the temporary folder
681 0 : sal_Int32 i = url.lastIndexOf('/');
682 0 : newUrl = destFolder + url.copy(i);
683 : }
684 :
685 : ucbhelper::Content(newUrl, xCmdEnv, xContext).writeStream(
686 0 : xmlscript::createInputStream(filtered), true);
687 0 : out_replaced = true;
688 0 : return newUrl;
689 : }
690 :
691 : //______________________________________________________________________________
692 0 : void BackendImpl::PackageImpl::processPackage_(
693 : ::osl::ResettableMutexGuard &,
694 : bool doRegisterPackage,
695 : bool startup,
696 : ::rtl::Reference<AbortChannel> const &,
697 : Reference<XCommandEnvironment> const & xCmdEnv )
698 : {
699 0 : BackendImpl * that = getMyBackend();
700 0 : OUString url( getURL() );
701 :
702 0 : if (doRegisterPackage)
703 : {
704 0 : if (getMyBackend()->activateEntry(getURL()))
705 : {
706 0 : ::boost::optional<ConfigurationBackendDb::Data> data = that->readDataFromDb(url);
707 : OSL_ASSERT(data);
708 0 : that->addToConfigmgrIni( m_isSchema, false, data->iniEntry, xCmdEnv );
709 : }
710 : else
711 : {
712 0 : ConfigurationBackendDb::Data data;
713 0 : if (!m_isSchema)
714 : {
715 0 : const OUString sModFolder = that->createFolder(OUString(), xCmdEnv);
716 0 : bool out_replaced = false;
717 0 : url = replaceOrigin(url, sModFolder, xCmdEnv, that->getComponentContext(), out_replaced);
718 0 : if (out_replaced)
719 0 : data.dataUrl = sModFolder;
720 : else
721 0 : deleteTempFolder(sModFolder);
722 : }
723 : //No need for live-deployment for bundled extension, because OOo
724 : //restarts after installation
725 0 : if (that->m_eContext != CONTEXT_BUNDLED
726 0 : && !startup)
727 : {
728 0 : if (m_isSchema)
729 : {
730 : com::sun::star::configuration::Update::get(
731 0 : that->m_xComponentContext)->insertExtensionXcsFile(
732 0 : that->m_eContext == CONTEXT_SHARED, expandUnoRcUrl(url));
733 : }
734 : else
735 : {
736 : com::sun::star::configuration::Update::get(
737 0 : that->m_xComponentContext)->insertExtensionXcuFile(
738 0 : that->m_eContext == CONTEXT_SHARED, expandUnoRcUrl(url));
739 : }
740 : }
741 0 : that->addToConfigmgrIni( m_isSchema, true, url, xCmdEnv );
742 0 : data.iniEntry = dp_misc::makeRcTerm(url);
743 0 : that->addDataToDb(getURL(), data);
744 : }
745 : }
746 : else // revoke
747 : {
748 : #if !defined(ANDROID) && !defined(IOS)
749 0 : if (!that->removeFromConfigmgrIni(m_isSchema, url, xCmdEnv) &&
750 0 : that->m_registeredPackages.get()) {
751 : // Obsolete package database handling - should be removed for LibreOffice 4.0
752 : t_string2string_map entries(
753 0 : that->m_registeredPackages->getEntries());
754 0 : for (t_string2string_map::iterator i(entries.begin());
755 0 : i != entries.end(); ++i)
756 : {
757 : //If the xcu file was installed before the configmgr was chaned
758 : //to use the configmgr.ini, one needed to rebuild to whole directory
759 : //structur containing the xcu, xcs files from all extensions. Now,
760 : //we just add all other xcu/xcs files to the configmgr.ini instead of
761 : //rebuilding the directory structure.
762 : rtl::OUString url2(
763 0 : rtl::OStringToOUString(i->first, RTL_TEXTENCODING_UTF8));
764 0 : if (url2 != url) {
765 0 : bool schema = i->second.equalsIgnoreAsciiCase(
766 0 : "vnd.sun.star.configuration-schema");
767 0 : OUString url_replaced(url2);
768 0 : ConfigurationBackendDb::Data data;
769 0 : if (!schema)
770 : {
771 0 : const OUString sModFolder = that->createFolder(OUString(), xCmdEnv);
772 0 : bool out_replaced = false;
773 : url_replaced = replaceOrigin(
774 0 : url2, sModFolder, xCmdEnv, that->getComponentContext(), out_replaced);
775 0 : if (out_replaced)
776 0 : data.dataUrl = sModFolder;
777 : else
778 0 : deleteTempFolder(sModFolder);
779 : }
780 0 : that->addToConfigmgrIni(schema, true, url_replaced, xCmdEnv);
781 0 : data.iniEntry = dp_misc::makeRcTerm(url_replaced);
782 0 : that->addDataToDb(url2, data);
783 : }
784 0 : that->m_registeredPackages->erase(i->first);
785 0 : }
786 : try
787 : {
788 : ::ucbhelper::Content(
789 0 : makeURL( that->getCachePath(), OUSTR("registry") ),
790 0 : xCmdEnv, that->getComponentContext() ).executeCommand(
791 0 : OUSTR("delete"), Any( true /* delete physically */ ) );
792 : }
793 0 : catch(const Exception&)
794 : {
795 : OSL_ASSERT(0);
796 0 : }
797 : }
798 : #endif
799 0 : ::boost::optional<ConfigurationBackendDb::Data> data = that->readDataFromDb(url);
800 : //If an xcu file was life deployed then always a data entry is written.
801 : //If the xcu file was already in the configmr.ini then there is also
802 : //a data entry
803 0 : if (!m_isSchema && data)
804 : {
805 : com::sun::star::configuration::Update::get(
806 0 : that->m_xComponentContext)->removeExtensionXcuFile(expandUnoRcTerm(data->iniEntry));
807 : }
808 0 : that->revokeEntryFromDb(url);
809 0 : }
810 0 : }
811 :
812 : } // anon namespace
813 :
814 : namespace sdecl = comphelper::service_decl;
815 4 : sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI;
816 4 : extern sdecl::ServiceDecl const serviceDecl(
817 : serviceBI,
818 : "com.sun.star.comp.deployment.configuration.PackageRegistryBackend",
819 : BACKEND_SERVICE_NAME );
820 :
821 : } // namespace configuration
822 : } // namespace backend
823 12 : } // namespace dp_registry
824 :
825 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|