LibreOffice Module desktop (master) 1
oo3extensionmigration.cxx
Go to the documentation of this file.
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
22#include <sal/log.hxx>
23#include <osl/file.hxx>
29#include <rtl/ref.hxx>
30
31#include <com/sun/star/task/XInteractionApprove.hpp>
32#include <com/sun/star/ucb/CommandAbortedException.hpp>
33#include <com/sun/star/ucb/XCommandEnvironment.hpp>
34#include <com/sun/star/ucb/SimpleFileAccess.hpp>
35#include <com/sun/star/xml/xpath/XPathAPI.hpp>
36#include <com/sun/star/xml/xpath/XPathException.hpp>
37#include <com/sun/star/xml/dom/DOMException.hpp>
38#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
39#include <com/sun/star/beans/NamedValue.hpp>
40#include <com/sun/star/deployment/ExtensionManager.hpp>
41#include <com/sun/star/deployment/XExtensionManager.hpp>
42
43using namespace ::com::sun::star;
44using namespace ::com::sun::star::uno;
45
46namespace migration
47{
48
49// ExtensionMigration
50
51
52OO3ExtensionMigration::OO3ExtensionMigration(Reference< XComponentContext > const & ctx) :
53m_ctx(ctx)
54{
55}
56
57
59{
60}
61
62void OO3ExtensionMigration::scanUserExtensions( const OUString& sSourceDir, TStringVector& aMigrateExtensions )
63{
64 osl::Directory aScanRootDir( sSourceDir );
65 osl::FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL);
66 osl::FileBase::RC nRetCode = aScanRootDir.open();
67 if ( nRetCode != osl::Directory::E_None )
68 return;
69
70 sal_uInt32 nHint( 0 );
71 osl::DirectoryItem aItem;
72 while ( aScanRootDir.getNextItem( aItem, nHint ) == osl::Directory::E_None )
73 {
74 if (( aItem.getFileStatus(fs) == osl::FileBase::E_None ) &&
75 ( fs.getFileType() == osl::FileStatus::Directory ))
76 {
77 //Check next folder as the "real" extension folder is below a temp folder!
78 OUString sExtensionFolderURL = fs.getFileURL();
79
80 osl::Directory aExtensionRootDir( sExtensionFolderURL );
81
82 nRetCode = aExtensionRootDir.open();
83 if ( nRetCode == osl::Directory::E_None )
84 {
85 osl::DirectoryItem aExtDirItem;
86 while ( aExtensionRootDir.getNextItem( aExtDirItem, nHint ) == osl::Directory::E_None )
87 {
88 bool bFileStatus = aExtDirItem.getFileStatus(fs) == osl::FileBase::E_None;
89 bool bIsDir = fs.getFileType() == osl::FileStatus::Directory;
90
91 if ( bFileStatus && bIsDir )
92 {
93 sExtensionFolderURL = fs.getFileURL();
94 ScanResult eResult = scanExtensionFolder( sExtensionFolderURL );
95 if ( eResult == SCANRESULT_MIGRATE_EXTENSION )
96 aMigrateExtensions.push_back( sExtensionFolderURL );
97 break;
98 }
99 }
100 }
101 }
102 }
103}
104
106{
108 osl::Directory aDir(sExtFolder);
109
110 // get sub dirs
111 if (aDir.open() == osl::FileBase::E_None)
112 {
113 // work through directory contents...
114 osl::DirectoryItem item;
115 osl::FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL);
116 TStringVector aDirectories;
117 while ((aDir.getNextItem(item) == osl::FileBase::E_None ) &&
118 ( aResult == SCANRESULT_NOTFOUND ))
119 {
120 if (item.getFileStatus(fs) == osl::FileBase::E_None)
121 {
122 if (fs.getFileType() == osl::FileStatus::Directory)
123 aDirectories.push_back( fs.getFileURL() );
124 else
125 {
126 OUString aDirEntryURL = fs.getFileURL();
127 if ( aDirEntryURL.indexOf( "/description.xml" ) > 0 )
129 }
130 }
131 }
132
133 for (auto const& directory : aDirectories)
134 {
135 aResult = scanExtensionFolder(directory);
136 if (aResult != SCANRESULT_NOTFOUND)
137 break;
138 }
139 }
140 return aResult;
141}
142
143bool OO3ExtensionMigration::scanDescriptionXml( const OUString& sDescriptionXmlURL )
144{
145 if ( !m_xDocBuilder.is() )
146 {
148 }
149
150 if ( !m_xSimpleFileAccess.is() )
151 {
153 }
154
155 OUString aExtIdentifier;
156 try
157 {
159 m_xSimpleFileAccess->openFileRead( sDescriptionXmlURL );
160
161 if ( xIn.is() )
162 {
164 if ( xDoc.is() )
165 {
166 uno::Reference< xml::dom::XElement > xRoot = xDoc->getDocumentElement();
167 if ( xRoot.is() && xRoot->getTagName() == "description" )
168 {
170
171 xPath->registerNS("desc", xRoot->getNamespaceURI());
172 xPath->registerNS("xlink", "http://www.w3.org/1999/xlink");
173
174 try
175 {
177 xPath->selectSingleNode(
178 xRoot, "desc:identifier/@value" ));
179 if ( xNode.is() )
180 aExtIdentifier = xNode->getNodeValue();
181 }
182 catch ( const xml::xpath::XPathException& )
183 {
184 }
185 catch ( const xml::dom::DOMException& )
186 {
187 }
188 }
189 }
190 }
191
192 if ( !aExtIdentifier.isEmpty() )
193 {
194 // scan extension identifier and try to match with our black list entries
195 for (const OUString & i : m_aDenyList)
196 {
199
200 sal_Int32 start = 0;
201 sal_Int32 end = aExtIdentifier.getLength();
202 if (ts.SearchForward(aExtIdentifier, &start, &end))
203 return false;
204 }
205 }
206 }
207 catch ( const ucb::CommandAbortedException& )
208 {
209 }
210 catch ( const uno::RuntimeException& )
211 {
212 }
213
214 if ( aExtIdentifier.isEmpty() )
215 {
216 // Fallback:
217 // Try to use the folder name to match our black list
218 // as some extensions don't provide an identifier in the
219 // description.xml!
220 for (const OUString & i : m_aDenyList)
221 {
224
225 sal_Int32 start = 0;
226 sal_Int32 end = sDescriptionXmlURL.getLength();
227 if (ts.SearchForward(sDescriptionXmlURL, &start, &end))
228 return false;
229 }
230 }
231
232 return true;
233}
234
235void OO3ExtensionMigration::migrateExtension( const OUString& sSourceDir )
236{
237 css::uno::Reference< css::deployment::XExtensionManager > extMgr(
238 deployment::ExtensionManager::get( m_ctx ) );
239 try
240 {
242
244 extMgr->addExtension(
245 sSourceDir, uno::Sequence<beans::NamedValue>(), "user",
246 xAbortChannel, pCmdEnv );
247 }
248 catch ( css::uno::Exception & )
249 {
251 "desktop.migration",
252 "Ignoring UNO Exception while migrating extension from <" << sSourceDir << ">");
253 }
254}
255
256
257// XServiceInfo
258
259
261{
262 return "com.sun.star.comp.desktop.migration.OOo3Extensions";
263}
264
265
267{
269}
270
271
273{
274 return { "com.sun.star.migration.Extensions" };
275}
276
277
278// XInitialization
279
280
281void OO3ExtensionMigration::initialize( const Sequence< Any >& aArguments )
282{
283 ::osl::MutexGuard aGuard( m_aMutex );
284
285 const Any* pIter = aArguments.getConstArray();
286 const Any* pEnd = pIter + aArguments.getLength();
287 for ( ; pIter != pEnd ; ++pIter )
288 {
289 beans::NamedValue aValue;
290 *pIter >>= aValue;
291 if ( aValue.Name == "UserData" )
292 {
293 if ( !(aValue.Value >>= m_sSourceDir) )
294 {
295 OSL_FAIL( "ExtensionMigration::initialize: argument UserData has wrong type!" );
296 }
297 }
298 else if ( aValue.Name == "ExtensionDenyList" )
299 {
300 Sequence< OUString > aDenyList;
301 if ( (aValue.Value >>= aDenyList ) && aDenyList.hasElements())
302 {
303 m_aDenyList.resize( aDenyList.getLength() );
304 ::comphelper::sequenceToArray< OUString >( m_aDenyList.data(), aDenyList );
305 }
306 }
307 }
308}
309
311{
312 ::osl::MutexGuard aGuard( m_aMutex );
313
315 if ( aStatus == ::utl::Bootstrap::PATH_EXISTS )
316 {
317 // copy all extensions
318 OUString sSourceDir = m_sSourceDir +
319 "/user/uno_packages/cache/uno_packages";
320 TStringVector aExtensionToMigrate;
321 scanUserExtensions( sSourceDir, aExtensionToMigrate );
322 for (auto const& extensionToMigrate : aExtensionToMigrate)
323 {
324 migrateExtension(extensionToMigrate);
325 }
326 }
327
328 return Any();
329}
330
331
332// TmpRepositoryCommandEnv
333
334
336{
337}
338
340{
341}
342// XCommandEnvironment
343
345{
346 return this;
347}
348
349
351{
352 return this;
353}
354
355// XInteractionHandler
358{
359 OSL_ASSERT( xRequest->getRequest().getValueTypeClass() == uno::TypeClass_EXCEPTION );
360
361 bool approve = true;
362
363 // select:
365 xRequest->getContinuations() );
366 Reference< task::XInteractionContinuation > const * pConts =
367 conts.getConstArray();
368 sal_Int32 len = conts.getLength();
369 for ( sal_Int32 pos = 0; pos < len; ++pos )
370 {
371 if (approve) {
373 pConts[ pos ], uno::UNO_QUERY );
374 if (xInteractionApprove.is()) {
375 xInteractionApprove->select();
376 // don't query again for ongoing continuations:
377 approve = false;
378 }
379 }
380 }
381}
382
383// XProgressHandler
384void TmpRepositoryCommandEnv::push( uno::Any const & /*Status*/ )
385{
386}
387
388
389void TmpRepositoryCommandEnv::update( uno::Any const & /*Status */)
390{
391}
392
394{
395}
396
397
398} // namespace migration
399
400
401extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
403 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
404{
405 return cppu::acquire(new migration::OO3ExtensionMigration(context));
406}
407
408
409/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::uno::XComponentContext > m_ctx
virtual sal_Bool SAL_CALL supportsService(const OUString &rServiceName) override
css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSimpleFileAccess
void migrateExtension(const OUString &sSourceDir)
ScanResult scanExtensionFolder(const OUString &sExtFolder)
css::uno::Reference< css::xml::dom::XDocumentBuilder > m_xDocBuilder
virtual OUString SAL_CALL getImplementationName() override
void scanUserExtensions(const OUString &sSourceDir, TStringVector &aMigrateExtensions)
OO3ExtensionMigration(css::uno::Reference< css::uno::XComponentContext > const &ctx)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
bool scanDescriptionXml(const OUString &sDescriptionXmlFilePath)
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &aArguments) override
virtual css::uno::Any SAL_CALL execute(const css::uno::Sequence< css::beans::NamedValue > &Arguments) override
virtual css::uno::Reference< css::task::XInteractionHandler > SAL_CALL getInteractionHandler() override
virtual void SAL_CALL push(css::uno::Any const &Status) override
virtual void SAL_CALL pop() override
virtual void SAL_CALL handle(css::uno::Reference< css::task::XInteractionRequest > const &xRequest) override
virtual void SAL_CALL update(css::uno::Any const &Status) override
virtual css::uno::Reference< css::ucb::XProgressHandler > SAL_CALL getProgressHandler() override
static PathStatus locateUserInstallation(OUString &_rURL)
bool SearchForward(const OUString &rStr, sal_Int32 *pStart, sal_Int32 *pEnd, css::util::SearchResult *pRes=nullptr)
#define TOOLS_WARN_EXCEPTION(area, stream)
Sequence< PropertyValue > aArguments
#define LANGUAGE_DONTKNOW
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
int i
ctx
std::vector< OUString > TStringVector
Definition: misc.hxx:32
end
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * desktop_OO3ExtensionMigration_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
unsigned char sal_Bool
size_t pos