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