lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / desktop / source / migration / services / oo3extensionmigration.cxx
blob7c6d4a28ecfc8196677391b233a1332904191929
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "oo3extensionmigration.hxx"
22 #include <rtl/instance.hxx>
23 #include <sal/log.hxx>
24 #include <osl/file.hxx>
25 #include <osl/thread.h>
26 #include <tools/diagnose_ex.h>
27 #include <tools/urlobj.hxx>
28 #include <unotools/bootstrap.hxx>
29 #include <unotools/textsearch.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <cppuhelper/supportsservice.hxx>
32 #include <ucbhelper/content.hxx>
34 #include <com/sun/star/task/XInteractionApprove.hpp>
35 #include <com/sun/star/task/XInteractionAbort.hpp>
36 #include <com/sun/star/ucb/CommandAbortedException.hpp>
37 #include <com/sun/star/ucb/XCommandInfo.hpp>
38 #include <com/sun/star/ucb/TransferInfo.hpp>
39 #include <com/sun/star/ucb/NameClash.hpp>
40 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
41 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
42 #include <com/sun/star/xml/xpath/XPathException.hpp>
43 #include <com/sun/star/xml/dom/DOMException.hpp>
44 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
45 #include <com/sun/star/beans/NamedValue.hpp>
46 #include <com/sun/star/deployment/ExtensionManager.hpp>
47 #include <com/sun/star/deployment/XExtensionManager.hpp>
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::uno;
52 namespace migration
55 // component operations
58 OUString OO3ExtensionMigration_getImplementationName()
60 return "com.sun.star.comp.desktop.migration.OOo3Extensions";
64 Sequence< OUString > OO3ExtensionMigration_getSupportedServiceNames()
66 return { "com.sun.star.migration.Extensions" };
70 // ExtensionMigration
73 OO3ExtensionMigration::OO3ExtensionMigration(Reference< XComponentContext > const & ctx) :
74 m_ctx(ctx)
79 OO3ExtensionMigration::~OO3ExtensionMigration()
83 void OO3ExtensionMigration::scanUserExtensions( const OUString& sSourceDir, TStringVector& aMigrateExtensions )
85 osl::Directory aScanRootDir( sSourceDir );
86 osl::FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL);
87 osl::FileBase::RC nRetCode = aScanRootDir.open();
88 if ( nRetCode == osl::Directory::E_None )
90 sal_uInt32 nHint( 0 );
91 osl::DirectoryItem aItem;
92 while ( aScanRootDir.getNextItem( aItem, nHint ) == osl::Directory::E_None )
94 if (( aItem.getFileStatus(fs) == osl::FileBase::E_None ) &&
95 ( fs.getFileType() == osl::FileStatus::Directory ))
97 //Check next folder as the "real" extension folder is below a temp folder!
98 OUString sExtensionFolderURL = fs.getFileURL();
100 osl::Directory aExtensionRootDir( sExtensionFolderURL );
102 nRetCode = aExtensionRootDir.open();
103 if ( nRetCode == osl::Directory::E_None )
105 osl::DirectoryItem aExtDirItem;
106 while ( aExtensionRootDir.getNextItem( aExtDirItem, nHint ) == osl::Directory::E_None )
108 bool bFileStatus = aExtDirItem.getFileStatus(fs) == osl::FileBase::E_None;
109 bool bIsDir = fs.getFileType() == osl::FileStatus::Directory;
111 if ( bFileStatus && bIsDir )
113 sExtensionFolderURL = fs.getFileURL();
114 ScanResult eResult = scanExtensionFolder( sExtensionFolderURL );
115 if ( eResult == SCANRESULT_MIGRATE_EXTENSION )
116 aMigrateExtensions.push_back( sExtensionFolderURL );
117 break;
126 OO3ExtensionMigration::ScanResult OO3ExtensionMigration::scanExtensionFolder( const OUString& sExtFolder )
128 ScanResult aResult = SCANRESULT_NOTFOUND;
129 osl::Directory aDir(sExtFolder);
131 // get sub dirs
132 if (aDir.open() == osl::FileBase::E_None)
134 // work through directory contents...
135 osl::DirectoryItem item;
136 osl::FileStatus fs(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL);
137 TStringVector aDirectories;
138 while ((aDir.getNextItem(item) == osl::FileBase::E_None ) &&
139 ( aResult == SCANRESULT_NOTFOUND ))
141 if (item.getFileStatus(fs) == osl::FileBase::E_None)
143 OUString aDirEntryURL;
144 if (fs.getFileType() == osl::FileStatus::Directory)
145 aDirectories.push_back( fs.getFileURL() );
146 else
148 aDirEntryURL = fs.getFileURL();
149 if ( aDirEntryURL.indexOf( "/description.xml" ) > 0 )
150 aResult = scanDescriptionXml( aDirEntryURL ) ? SCANRESULT_MIGRATE_EXTENSION : SCANRESULT_DONTMIGRATE_EXTENSION;
155 for (auto const& directory : aDirectories)
157 aResult = scanExtensionFolder(directory);
158 if (aResult != SCANRESULT_NOTFOUND)
159 break;
162 return aResult;
165 bool OO3ExtensionMigration::scanDescriptionXml( const OUString& sDescriptionXmlURL )
167 if ( !m_xDocBuilder.is() )
169 m_xDocBuilder.set( xml::dom::DocumentBuilder::create(m_ctx) );
172 if ( !m_xSimpleFileAccess.is() )
174 m_xSimpleFileAccess = ucb::SimpleFileAccess::create(m_ctx);
177 OUString aExtIdentifier;
180 uno::Reference< io::XInputStream > xIn =
181 m_xSimpleFileAccess->openFileRead( sDescriptionXmlURL );
183 if ( xIn.is() )
185 uno::Reference< xml::dom::XDocument > xDoc = m_xDocBuilder->parse( xIn );
186 if ( xDoc.is() )
188 uno::Reference< xml::dom::XElement > xRoot = xDoc->getDocumentElement();
189 if ( xRoot.is() && xRoot->getTagName() == "description" )
191 uno::Reference< xml::xpath::XXPathAPI > xPath = xml::xpath::XPathAPI::create(m_ctx);
193 xPath->registerNS("desc", xRoot->getNamespaceURI());
194 xPath->registerNS("xlink", "http://www.w3.org/1999/xlink");
198 uno::Reference< xml::dom::XNode > xRootNode( xRoot, uno::UNO_QUERY );
199 uno::Reference< xml::dom::XNode > xNode(
200 xPath->selectSingleNode(
201 xRootNode, "desc:identifier/@value" ));
202 if ( xNode.is() )
203 aExtIdentifier = xNode->getNodeValue();
205 catch ( const xml::xpath::XPathException& )
208 catch ( const xml::dom::DOMException& )
215 if ( !aExtIdentifier.isEmpty() )
217 // scan extension identifier and try to match with our black list entries
218 for (OUString & i : m_aBlackList)
220 utl::SearchParam param(i, utl::SearchParam::SearchType::Regexp);
221 utl::TextSearch ts(param, LANGUAGE_DONTKNOW);
223 sal_Int32 start = 0;
224 sal_Int32 end = aExtIdentifier.getLength();
225 if (ts.SearchForward(aExtIdentifier, &start, &end))
226 return false;
230 catch ( const ucb::CommandAbortedException& )
233 catch ( const uno::RuntimeException& )
237 if ( aExtIdentifier.isEmpty() )
239 // Fallback:
240 // Try to use the folder name to match our black list
241 // as some extensions don't provide an identifier in the
242 // description.xml!
243 for (OUString & i : m_aBlackList)
245 utl::SearchParam param(i, utl::SearchParam::SearchType::Regexp);
246 utl::TextSearch ts(param, LANGUAGE_DONTKNOW);
248 sal_Int32 start = 0;
249 sal_Int32 end = sDescriptionXmlURL.getLength();
250 if (ts.SearchForward(sDescriptionXmlURL, &start, &end))
251 return false;
255 return true;
258 void OO3ExtensionMigration::migrateExtension( const OUString& sSourceDir )
260 css::uno::Reference< css::deployment::XExtensionManager > extMgr(
261 deployment::ExtensionManager::get( m_ctx ) );
264 TmpRepositoryCommandEnv* pCmdEnv = new TmpRepositoryCommandEnv();
266 uno::Reference< ucb::XCommandEnvironment > xCmdEnv(
267 static_cast< cppu::OWeakObject* >( pCmdEnv ), uno::UNO_QUERY );
268 uno::Reference< task::XAbortChannel > xAbortChannel;
269 extMgr->addExtension(
270 sSourceDir, uno::Sequence<beans::NamedValue>(), "user",
271 xAbortChannel, xCmdEnv );
273 catch ( css::uno::Exception & )
275 TOOLS_WARN_EXCEPTION(
276 "desktop.migration",
277 "Ignoring UNO Exception while migrating extension from <" << sSourceDir << ">");
282 // XServiceInfo
285 OUString OO3ExtensionMigration::getImplementationName()
287 return OO3ExtensionMigration_getImplementationName();
291 sal_Bool OO3ExtensionMigration::supportsService(OUString const & ServiceName)
293 return cppu::supportsService(this, ServiceName);
297 Sequence< OUString > OO3ExtensionMigration::getSupportedServiceNames()
299 return OO3ExtensionMigration_getSupportedServiceNames();
303 // XInitialization
306 void OO3ExtensionMigration::initialize( const Sequence< Any >& aArguments )
308 ::osl::MutexGuard aGuard( m_aMutex );
310 const Any* pIter = aArguments.getConstArray();
311 const Any* pEnd = pIter + aArguments.getLength();
312 for ( ; pIter != pEnd ; ++pIter )
314 beans::NamedValue aValue;
315 *pIter >>= aValue;
316 if ( aValue.Name == "UserData" )
318 if ( !(aValue.Value >>= m_sSourceDir) )
320 OSL_FAIL( "ExtensionMigration::initialize: argument UserData has wrong type!" );
323 else if ( aValue.Name == "ExtensionBlackList" )
325 Sequence< OUString > aBlackList;
326 if ( (aValue.Value >>= aBlackList ) && ( aBlackList.getLength() > 0 ))
328 m_aBlackList.resize( aBlackList.getLength() );
329 ::comphelper::sequenceToArray< OUString >( &m_aBlackList[0], aBlackList );
335 Any OO3ExtensionMigration::execute( const Sequence< beans::NamedValue >& )
337 ::osl::MutexGuard aGuard( m_aMutex );
339 ::utl::Bootstrap::PathStatus aStatus = ::utl::Bootstrap::locateUserInstallation( m_sTargetDir );
340 if ( aStatus == ::utl::Bootstrap::PATH_EXISTS )
342 // copy all extensions
343 OUString sSourceDir( m_sSourceDir );
344 sSourceDir += "/user/uno_packages/cache/uno_packages";
345 TStringVector aExtensionToMigrate;
346 scanUserExtensions( sSourceDir, aExtensionToMigrate );
347 if (!aExtensionToMigrate.empty())
349 for (auto const& extensionToMigrate : aExtensionToMigrate)
351 migrateExtension(extensionToMigrate);
356 return Any();
360 // TmpRepositoryCommandEnv
363 TmpRepositoryCommandEnv::TmpRepositoryCommandEnv()
367 TmpRepositoryCommandEnv::~TmpRepositoryCommandEnv()
370 // XCommandEnvironment
372 uno::Reference< task::XInteractionHandler > TmpRepositoryCommandEnv::getInteractionHandler()
374 return this;
378 uno::Reference< ucb::XProgressHandler > TmpRepositoryCommandEnv::getProgressHandler()
380 return this;
383 // XInteractionHandler
384 void TmpRepositoryCommandEnv::handle(
385 uno::Reference< task::XInteractionRequest> const & xRequest )
387 OSL_ASSERT( xRequest->getRequest().getValueTypeClass() == uno::TypeClass_EXCEPTION );
389 bool approve = true;
391 // select:
392 uno::Sequence< Reference< task::XInteractionContinuation > > conts(
393 xRequest->getContinuations() );
394 Reference< task::XInteractionContinuation > const * pConts =
395 conts.getConstArray();
396 sal_Int32 len = conts.getLength();
397 for ( sal_Int32 pos = 0; pos < len; ++pos )
399 if (approve) {
400 uno::Reference< task::XInteractionApprove > xInteractionApprove(
401 pConts[ pos ], uno::UNO_QUERY );
402 if (xInteractionApprove.is()) {
403 xInteractionApprove->select();
404 // don't query again for ongoing continuations:
405 approve = false;
411 // XProgressHandler
412 void TmpRepositoryCommandEnv::push( uno::Any const & /*Status*/ )
417 void TmpRepositoryCommandEnv::update( uno::Any const & /*Status */)
421 void TmpRepositoryCommandEnv::pop()
426 // component operations
429 Reference< XInterface > OO3ExtensionMigration_create(
430 Reference< XComponentContext > const & ctx )
432 return static_cast< lang::XTypeProvider * >( new OO3ExtensionMigration(
433 ctx) );
437 } // namespace migration
439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */