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