1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/log.hxx>
23 #include <osl/file.hxx>
24 #include <comphelper/diagnose_ex.hxx>
25 #include <unotools/bootstrap.hxx>
26 #include <unotools/textsearch.hxx>
27 #include <comphelper/sequence.hxx>
28 #include <cppuhelper/supportsservice.hxx>
29 #include <rtl/ref.hxx>
31 #include <com/sun/star/task/XInteractionApprove.hpp>
32 #include <com/sun/star/ucb/CommandAbortedException.hpp>
33 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
34 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
35 #include <com/sun/star/xml/xpath/XPathException.hpp>
36 #include <com/sun/star/xml/dom/DOMException.hpp>
37 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
38 #include <com/sun/star/beans/NamedValue.hpp>
39 #include <com/sun/star/deployment/ExtensionManager.hpp>
40 #include <com/sun/star/deployment/XExtensionManager.hpp>
42 using namespace ::com::sun::star
;
43 using namespace ::com::sun::star::uno
;
51 OO3ExtensionMigration::OO3ExtensionMigration(Reference
< XComponentContext
> const & ctx
) :
57 OO3ExtensionMigration::~OO3ExtensionMigration()
61 void OO3ExtensionMigration::scanUserExtensions( const OUString
& sSourceDir
, TStringVector
& aMigrateExtensions
)
63 osl::Directory
aScanRootDir( sSourceDir
);
64 osl::FileStatus
fs(osl_FileStatus_Mask_Type
| osl_FileStatus_Mask_FileURL
);
65 osl::FileBase::RC nRetCode
= aScanRootDir
.open();
66 if ( nRetCode
!= osl::Directory::E_None
)
69 sal_uInt32
nHint( 0 );
70 osl::DirectoryItem aItem
;
71 while ( aScanRootDir
.getNextItem( aItem
, nHint
) == osl::Directory::E_None
)
73 if (( aItem
.getFileStatus(fs
) == osl::FileBase::E_None
) &&
74 ( fs
.getFileType() == osl::FileStatus::Directory
))
76 //Check next folder as the "real" extension folder is below a temp folder!
77 OUString sExtensionFolderURL
= fs
.getFileURL();
79 osl::Directory
aExtensionRootDir( sExtensionFolderURL
);
81 nRetCode
= aExtensionRootDir
.open();
82 if ( nRetCode
== osl::Directory::E_None
)
84 osl::DirectoryItem aExtDirItem
;
85 while ( aExtensionRootDir
.getNextItem( aExtDirItem
, nHint
) == osl::Directory::E_None
)
87 bool bFileStatus
= aExtDirItem
.getFileStatus(fs
) == osl::FileBase::E_None
;
88 bool bIsDir
= fs
.getFileType() == osl::FileStatus::Directory
;
90 if ( bFileStatus
&& bIsDir
)
92 sExtensionFolderURL
= fs
.getFileURL();
93 ScanResult eResult
= scanExtensionFolder( sExtensionFolderURL
);
94 if ( eResult
== SCANRESULT_MIGRATE_EXTENSION
)
95 aMigrateExtensions
.push_back( sExtensionFolderURL
);
104 OO3ExtensionMigration::ScanResult
OO3ExtensionMigration::scanExtensionFolder( const OUString
& sExtFolder
)
106 ScanResult aResult
= SCANRESULT_NOTFOUND
;
107 osl::Directory
aDir(sExtFolder
);
110 if (aDir
.open() == osl::FileBase::E_None
)
112 // work through directory contents...
113 osl::DirectoryItem item
;
114 osl::FileStatus
fs(osl_FileStatus_Mask_Type
| osl_FileStatus_Mask_FileURL
);
115 TStringVector aDirectories
;
116 while ((aDir
.getNextItem(item
) == osl::FileBase::E_None
) &&
117 ( aResult
== SCANRESULT_NOTFOUND
))
119 if (item
.getFileStatus(fs
) == osl::FileBase::E_None
)
121 if (fs
.getFileType() == osl::FileStatus::Directory
)
122 aDirectories
.push_back( fs
.getFileURL() );
125 OUString aDirEntryURL
= fs
.getFileURL();
126 if ( aDirEntryURL
.indexOf( "/description.xml" ) > 0 )
127 aResult
= scanDescriptionXml( aDirEntryURL
) ? SCANRESULT_MIGRATE_EXTENSION
: SCANRESULT_DONTMIGRATE_EXTENSION
;
132 for (auto const& directory
: aDirectories
)
134 aResult
= scanExtensionFolder(directory
);
135 if (aResult
!= SCANRESULT_NOTFOUND
)
142 bool OO3ExtensionMigration::scanDescriptionXml( const OUString
& sDescriptionXmlURL
)
144 if ( !m_xDocBuilder
.is() )
146 m_xDocBuilder
.set( xml::dom::DocumentBuilder::create(m_ctx
) );
149 if ( !m_xSimpleFileAccess
.is() )
151 m_xSimpleFileAccess
= ucb::SimpleFileAccess::create(m_ctx
);
154 OUString aExtIdentifier
;
157 uno::Reference
< io::XInputStream
> xIn
=
158 m_xSimpleFileAccess
->openFileRead( sDescriptionXmlURL
);
162 uno::Reference
< xml::dom::XDocument
> xDoc
= m_xDocBuilder
->parse( xIn
);
165 uno::Reference
< xml::dom::XElement
> xRoot
= xDoc
->getDocumentElement();
166 if ( xRoot
.is() && xRoot
->getTagName() == "description" )
168 uno::Reference
< xml::xpath::XXPathAPI
> xPath
= xml::xpath::XPathAPI::create(m_ctx
);
170 xPath
->registerNS(u
"desc"_ustr
, xRoot
->getNamespaceURI());
171 xPath
->registerNS(u
"xlink"_ustr
, u
"http://www.w3.org/1999/xlink"_ustr
);
175 uno::Reference
< xml::dom::XNode
> xNode(
176 xPath
->selectSingleNode(
177 xRoot
, u
"desc:identifier/@value"_ustr
));
179 aExtIdentifier
= xNode
->getNodeValue();
181 catch ( const xml::xpath::XPathException
& )
184 catch ( const xml::dom::DOMException
& )
191 if ( !aExtIdentifier
.isEmpty() )
193 // scan extension identifier and try to match with our black list entries
194 for (const OUString
& i
: m_aDenyList
)
196 utl::SearchParam
param(i
, utl::SearchParam::SearchType::Regexp
);
197 utl::TextSearch
ts(param
, LANGUAGE_DONTKNOW
);
200 sal_Int32 end
= aExtIdentifier
.getLength();
201 if (ts
.SearchForward(aExtIdentifier
, &start
, &end
))
206 catch ( const ucb::CommandAbortedException
& )
209 catch ( const uno::RuntimeException
& )
213 if ( aExtIdentifier
.isEmpty() )
216 // Try to use the folder name to match our black list
217 // as some extensions don't provide an identifier in the
219 for (const OUString
& i
: m_aDenyList
)
221 utl::SearchParam
param(i
, utl::SearchParam::SearchType::Regexp
);
222 utl::TextSearch
ts(param
, LANGUAGE_DONTKNOW
);
225 sal_Int32 end
= sDescriptionXmlURL
.getLength();
226 if (ts
.SearchForward(sDescriptionXmlURL
, &start
, &end
))
234 void OO3ExtensionMigration::migrateExtension( const OUString
& sSourceDir
)
236 css::uno::Reference
< css::deployment::XExtensionManager
> extMgr(
237 deployment::ExtensionManager::get( m_ctx
) );
240 rtl::Reference
<TmpRepositoryCommandEnv
> pCmdEnv
= new TmpRepositoryCommandEnv();
242 uno::Reference
< task::XAbortChannel
> xAbortChannel
;
243 extMgr
->addExtension(
244 sSourceDir
, uno::Sequence
<beans::NamedValue
>(), u
"user"_ustr
,
245 xAbortChannel
, pCmdEnv
);
247 catch ( css::uno::Exception
& )
249 TOOLS_WARN_EXCEPTION(
251 "Ignoring UNO Exception while migrating extension from <" << sSourceDir
<< ">");
259 OUString
OO3ExtensionMigration::getImplementationName()
261 return u
"com.sun.star.comp.desktop.migration.OOo3Extensions"_ustr
;
265 sal_Bool
OO3ExtensionMigration::supportsService(OUString
const & ServiceName
)
267 return cppu::supportsService(this, ServiceName
);
271 Sequence
< OUString
> OO3ExtensionMigration::getSupportedServiceNames()
273 return { u
"com.sun.star.migration.Extensions"_ustr
};
280 void OO3ExtensionMigration::initialize( const Sequence
< Any
>& aArguments
)
282 ::osl::MutexGuard
aGuard( m_aMutex
);
284 const Any
* pIter
= aArguments
.getConstArray();
285 const Any
* pEnd
= pIter
+ aArguments
.getLength();
286 for ( ; pIter
!= pEnd
; ++pIter
)
288 beans::NamedValue aValue
;
290 if ( aValue
.Name
== "UserData" )
292 if ( !(aValue
.Value
>>= m_sSourceDir
) )
294 OSL_FAIL( "ExtensionMigration::initialize: argument UserData has wrong type!" );
297 else if ( aValue
.Name
== "ExtensionDenyList" )
299 Sequence
< OUString
> aDenyList
;
300 if ( (aValue
.Value
>>= aDenyList
) && aDenyList
.hasElements())
302 m_aDenyList
.resize( aDenyList
.getLength() );
303 ::comphelper::sequenceToArray
< OUString
>( m_aDenyList
.data(), aDenyList
);
309 Any
OO3ExtensionMigration::execute( const Sequence
< beans::NamedValue
>& )
311 ::osl::MutexGuard
aGuard( m_aMutex
);
313 ::utl::Bootstrap::PathStatus aStatus
= ::utl::Bootstrap::locateUserInstallation( m_sTargetDir
);
314 if ( aStatus
== ::utl::Bootstrap::PATH_EXISTS
)
316 // copy all extensions
317 OUString sSourceDir
= m_sSourceDir
+
318 "/user/uno_packages/cache/uno_packages";
319 TStringVector aExtensionToMigrate
;
320 scanUserExtensions( sSourceDir
, aExtensionToMigrate
);
321 for (auto const& extensionToMigrate
: aExtensionToMigrate
)
323 migrateExtension(extensionToMigrate
);
331 // TmpRepositoryCommandEnv
334 TmpRepositoryCommandEnv::TmpRepositoryCommandEnv()
338 TmpRepositoryCommandEnv::~TmpRepositoryCommandEnv()
341 // XCommandEnvironment
343 uno::Reference
< task::XInteractionHandler
> TmpRepositoryCommandEnv::getInteractionHandler()
349 uno::Reference
< ucb::XProgressHandler
> TmpRepositoryCommandEnv::getProgressHandler()
354 // XInteractionHandler
355 void TmpRepositoryCommandEnv::handle(
356 uno::Reference
< task::XInteractionRequest
> const & xRequest
)
358 OSL_ASSERT( xRequest
->getRequest().getValueTypeClass() == uno::TypeClass_EXCEPTION
);
363 uno::Sequence
< Reference
< task::XInteractionContinuation
> > conts(
364 xRequest
->getContinuations() );
365 Reference
< task::XInteractionContinuation
> const * pConts
=
366 conts
.getConstArray();
367 sal_Int32 len
= conts
.getLength();
368 for ( sal_Int32 pos
= 0; pos
< len
; ++pos
)
371 uno::Reference
< task::XInteractionApprove
> xInteractionApprove(
372 pConts
[ pos
], uno::UNO_QUERY
);
373 if (xInteractionApprove
.is()) {
374 xInteractionApprove
->select();
375 // don't query again for ongoing continuations:
383 void TmpRepositoryCommandEnv::push( uno::Any
const & /*Status*/ )
388 void TmpRepositoryCommandEnv::update( uno::Any
const & /*Status */)
392 void TmpRepositoryCommandEnv::pop()
397 } // namespace migration
400 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
401 desktop_OO3ExtensionMigration_get_implementation(
402 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
404 return cppu::acquire(new migration::OO3ExtensionMigration(context
));
408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */