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