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