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