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