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 #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 
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
45 
46 namespace migration
47 {
48 
49 // ExtensionMigration
50 
51 
53 m_ctx(ctx)
54 {
55 }
56 
57 
59 {
60 }
61 
62 void 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 
143 bool 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  {
158  uno::Reference< io::XInputStream > xIn =
159  m_xSimpleFileAccess->openFileRead( sDescriptionXmlURL );
160 
161  if ( xIn.is() )
162  {
163  uno::Reference< xml::dom::XDocument > xDoc = m_xDocBuilder->parse( xIn );
164  if ( xDoc.is() )
165  {
166  uno::Reference< xml::dom::XElement > xRoot = xDoc->getDocumentElement();
167  if ( xRoot.is() && xRoot->getTagName() == "description" )
168  {
169  uno::Reference< xml::xpath::XXPathAPI > xPath = xml::xpath::XPathAPI::create(m_ctx);
170 
171  xPath->registerNS("desc", xRoot->getNamespaceURI());
172  xPath->registerNS("xlink", "http://www.w3.org/1999/xlink");
173 
174  try
175  {
176  uno::Reference< xml::dom::XNode > xNode(
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 
235 void OO3ExtensionMigration::migrateExtension( const OUString& sSourceDir )
236 {
237  css::uno::Reference< css::deployment::XExtensionManager > extMgr(
238  deployment::ExtensionManager::get( m_ctx ) );
239  try
240  {
242 
243  uno::Reference< task::XAbortChannel > xAbortChannel;
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 {
268  return cppu::supportsService(this, ServiceName);
269 }
270 
271 
273 {
274  return { "com.sun.star.migration.Extensions" };
275 }
276 
277 
278 // XInitialization
279 
280 
281 void 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 
344 uno::Reference< task::XInteractionHandler > TmpRepositoryCommandEnv::getInteractionHandler()
345 {
346  return this;
347 }
348 
349 
350 uno::Reference< ucb::XProgressHandler > TmpRepositoryCommandEnv::getProgressHandler()
351 {
352  return this;
353 }
354 
355 // XInteractionHandler
357  uno::Reference< task::XInteractionRequest> const & xRequest )
358 {
359  OSL_ASSERT( xRequest->getRequest().getValueTypeClass() == uno::TypeClass_EXCEPTION );
360 
361  bool approve = true;
362 
363  // select:
364  uno::Sequence< Reference< task::XInteractionContinuation > > conts(
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) {
372  uno::Reference< task::XInteractionApprove > xInteractionApprove(
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
384 void TmpRepositoryCommandEnv::push( uno::Any const & /*Status*/ )
385 {
386 }
387 
388 
389 void TmpRepositoryCommandEnv::update( uno::Any const & /*Status */)
390 {
391 }
392 
394 {
395 }
396 
397 
398 } // namespace migration
399 
400 
401 extern "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: */
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)