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