| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_desktop.hxx" |
| |
| #include "oo3extensionmigration.hxx" |
| #include <rtl/instance.hxx> |
| #include <osl/file.hxx> |
| #include <osl/thread.h> |
| #include <tools/urlobj.hxx> |
| #include <unotools/bootstrap.hxx> |
| #include <unotools/ucbstreamhelper.hxx> |
| #include <unotools/textsearch.hxx> |
| #include <comphelper/sequence.hxx> |
| #include <comphelper/processfactory.hxx> |
| #include <ucbhelper/content.hxx> |
| |
| #include <com/sun/star/task/XInteractionApprove.hpp> |
| #include <com/sun/star/task/XInteractionAbort.hpp> |
| #include <com/sun/star/ucb/XCommandInfo.hpp> |
| #include <com/sun/star/ucb/TransferInfo.hpp> |
| #include <com/sun/star/ucb/NameClash.hpp> |
| #include <com/sun/star/ucb/XCommandEnvironment.hpp> |
| #include <com/sun/star/xml/xpath/XXPathAPI.hpp> |
| #include <com/sun/star/beans/NamedValue.hpp> |
| #include <com/sun/star/deployment/ExtensionManager.hpp> |
| |
| #include <com/sun/star/deployment/VersionException.hpp> |
| #include <dp_gui_handleversionexception.hxx> |
| #include <com/sun/star/deployment/DeploymentException.hpp> |
| |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| |
| namespace migration |
| { |
| |
| static ::rtl::OUString sExtensionSubDir = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/uno_packages/" ) ); |
| static ::rtl::OUString sSubDirName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cache" ) ); |
| static ::rtl::OUString sConfigDir = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/registry/data" ) ); |
| static ::rtl::OUString sOrgDir = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/registry/data/org" ) ); |
| static ::rtl::OUString sExcludeDir1 = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/registry/data/org" ) ); |
| static ::rtl::OUString sExcludeDir2 = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/registry/data/org/openoffice" ) ); |
| static ::rtl::OUString sDescriptionXmlFile = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/description.xml" ) ); |
| static ::rtl::OUString sExtensionRootSubDirName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/uno_packages" ) ); |
| |
| static ::rtl::OUString sConfigurationDataType = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/vnd.sun.star.configuration-data")); |
| static ::rtl::OUString sConfigurationSchemaType = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/vnd.sun.star.configuration-schema")); |
| |
| // ============================================================================= |
| // component operations |
| // ============================================================================= |
| |
| ::rtl::OUString OO3ExtensionMigration_getImplementationName() |
| { |
| static ::rtl::OUString* pImplName = 0; |
| if ( !pImplName ) |
| { |
| ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); |
| if ( !pImplName ) |
| { |
| static ::rtl::OUString aImplName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.desktop.migration.OOo3Extensions" ) ); |
| pImplName = &aImplName; |
| } |
| } |
| return *pImplName; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Sequence< ::rtl::OUString > OO3ExtensionMigration_getSupportedServiceNames() |
| { |
| static Sequence< ::rtl::OUString >* pNames = 0; |
| if ( !pNames ) |
| { |
| ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); |
| if ( !pNames ) |
| { |
| static Sequence< ::rtl::OUString > aNames(1); |
| aNames.getArray()[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.migration.Extensions" ) ); |
| pNames = &aNames; |
| } |
| } |
| return *pNames; |
| } |
| |
| // ============================================================================= |
| // ExtensionMigration |
| // ============================================================================= |
| |
| OO3ExtensionMigration::OO3ExtensionMigration(Reference< XComponentContext > const & ctx) : |
| m_ctx(ctx) |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| OO3ExtensionMigration::~OO3ExtensionMigration() |
| { |
| } |
| |
| ::osl::FileBase::RC OO3ExtensionMigration::checkAndCreateDirectory( INetURLObject& rDirURL ) |
| { |
| ::osl::FileBase::RC aResult = ::osl::Directory::create( rDirURL.GetMainURL( INetURLObject::DECODE_TO_IURI ) ); |
| if ( aResult == ::osl::FileBase::E_NOENT ) |
| { |
| INetURLObject aBaseURL( rDirURL ); |
| aBaseURL.removeSegment(); |
| checkAndCreateDirectory( aBaseURL ); |
| return ::osl::Directory::create( rDirURL.GetMainURL( INetURLObject::DECODE_TO_IURI ) ); |
| } |
| else |
| { |
| return aResult; |
| } |
| } |
| |
| void OO3ExtensionMigration::scanUserExtensions( const ::rtl::OUString& sSourceDir, TStringVector& aMigrateExtensions ) |
| { |
| osl::Directory aScanRootDir( sSourceDir ); |
| osl::FileStatus fs(FileStatusMask_Type | FileStatusMask_FileURL); |
| osl::FileBase::RC nRetCode = aScanRootDir.open(); |
| if ( nRetCode == osl::Directory::E_None ) |
| { |
| sal_uInt32 nHint( 0 ); |
| osl::DirectoryItem aItem; |
| while ( aScanRootDir.getNextItem( aItem, nHint ) == osl::Directory::E_None ) |
| { |
| if (( aItem.getFileStatus(fs) == osl::FileBase::E_None ) && |
| ( fs.getFileType() == osl::FileStatus::Directory )) |
| { |
| //Check next folder as the "real" extension folder is below a temp folder! |
| ::rtl::OUString sExtensionFolderURL = fs.getFileURL(); |
| |
| osl::DirectoryItem aExtDirItem; |
| osl::Directory aExtensionRootDir( sExtensionFolderURL ); |
| |
| nRetCode = aExtensionRootDir.open(); |
| if (( nRetCode == osl::Directory::E_None ) && |
| ( aExtensionRootDir.getNextItem( aExtDirItem, nHint ) == osl::Directory::E_None )) |
| { |
| bool bFileStatus = aExtDirItem.getFileStatus(fs) == osl::FileBase::E_None; |
| bool bIsDir = fs.getFileType() == osl::FileStatus::Directory; |
| |
| if ( bFileStatus && bIsDir ) |
| { |
| sExtensionFolderURL = fs.getFileURL(); |
| ScanResult eResult = scanExtensionFolder( sExtensionFolderURL ); |
| if ( eResult == SCANRESULT_MIGRATE_EXTENSION ) |
| aMigrateExtensions.push_back( sExtensionFolderURL ); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| OO3ExtensionMigration::ScanResult OO3ExtensionMigration::scanExtensionFolder( const ::rtl::OUString& sExtFolder ) |
| { |
| ScanResult aResult = SCANRESULT_NOTFOUND; |
| osl::Directory aDir(sExtFolder); |
| |
| // get sub dirs |
| if (aDir.open() == osl::FileBase::E_None) |
| { |
| // work through directory contents... |
| osl::DirectoryItem item; |
| osl::FileStatus fs(FileStatusMask_Type | FileStatusMask_FileURL); |
| TStringVector aDirectories; |
| while ((aDir.getNextItem(item) == osl::FileBase::E_None ) && |
| ( aResult == SCANRESULT_NOTFOUND )) |
| { |
| if (item.getFileStatus(fs) == osl::FileBase::E_None) |
| { |
| ::rtl::OUString aDirEntryURL; |
| if (fs.getFileType() == osl::FileStatus::Directory) |
| aDirectories.push_back( fs.getFileURL() ); |
| else |
| { |
| aDirEntryURL = fs.getFileURL(); |
| if ( aDirEntryURL.indexOf( sDescriptionXmlFile ) > 0 ) |
| aResult = scanDescriptionXml( aDirEntryURL ) ? SCANRESULT_MIGRATE_EXTENSION : SCANRESULT_DONTMIGRATE_EXTENSION; |
| } |
| } |
| } |
| |
| TStringVector::const_iterator pIter = aDirectories.begin(); |
| while ( pIter != aDirectories.end() && aResult == SCANRESULT_NOTFOUND ) |
| { |
| aResult = scanExtensionFolder( *pIter ); |
| ++pIter; |
| } |
| } |
| return aResult; |
| } |
| |
| bool OO3ExtensionMigration::scanDescriptionXml( const ::rtl::OUString& sDescriptionXmlURL ) |
| { |
| if ( !m_xDocBuilder.is() ) |
| { |
| m_xDocBuilder = uno::Reference< xml::dom::XDocumentBuilder >( |
| m_ctx->getServiceManager()->createInstanceWithContext( |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.dom.DocumentBuilder")), |
| m_ctx ), uno::UNO_QUERY ); |
| } |
| |
| if ( !m_xSimpleFileAccess.is() ) |
| { |
| m_xSimpleFileAccess = uno::Reference< ucb::XSimpleFileAccess >( |
| m_ctx->getServiceManager()->createInstanceWithContext( |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SimpleFileAccess")), |
| m_ctx ), uno::UNO_QUERY ); |
| } |
| |
| ::rtl::OUString aExtIdentifier; |
| if ( m_xDocBuilder.is() && m_xSimpleFileAccess.is() ) |
| { |
| try |
| { |
| uno::Reference< io::XInputStream > xIn = |
| m_xSimpleFileAccess->openFileRead( sDescriptionXmlURL ); |
| |
| if ( xIn.is() ) |
| { |
| uno::Reference< xml::dom::XDocument > xDoc = m_xDocBuilder->parse( xIn ); |
| if ( xDoc.is() ) |
| { |
| uno::Reference< xml::dom::XElement > xRoot = xDoc->getDocumentElement(); |
| if ( xRoot.is() && |
| xRoot->getTagName().equals(::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("description"))) ) |
| { |
| uno::Reference< xml::xpath::XXPathAPI > xPath( |
| m_ctx->getServiceManager()->createInstanceWithContext( |
| ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.xpath.XPathAPI")), |
| m_ctx), |
| uno::UNO_QUERY); |
| |
| xPath->registerNS( |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc")), |
| xRoot->getNamespaceURI()); |
| xPath->registerNS( |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xlink")), |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("http://www.w3.org/1999/xlink"))); |
| |
| try |
| { |
| uno::Reference< xml::dom::XNode > xRootNode( xRoot, uno::UNO_QUERY ); |
| uno::Reference< xml::dom::XNode > xNode( |
| xPath->selectSingleNode( |
| xRootNode, |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:identifier/@value")) )); |
| if ( xNode.is() ) |
| aExtIdentifier = xNode->getNodeValue(); |
| } |
| catch ( xml::xpath::XPathException& ) |
| { |
| } |
| catch ( xml::dom::DOMException& ) |
| { |
| } |
| } |
| } |
| } |
| |
| if ( aExtIdentifier.getLength() > 0 ) |
| { |
| // scan extension identifier and try to match with our black list entries |
| for ( sal_uInt32 i = 0; i < m_aBlackList.size(); i++ ) |
| { |
| utl::SearchParam param(m_aBlackList[i], utl::SearchParam::SRCH_REGEXP); |
| utl::TextSearch ts(param, LANGUAGE_DONTKNOW); |
| |
| xub_StrLen start = 0; |
| xub_StrLen end = static_cast<sal_uInt16>(aExtIdentifier.getLength()); |
| if (ts.SearchFrwrd(aExtIdentifier, &start, &end)) |
| return false; |
| } |
| } |
| } |
| catch ( ucb::CommandAbortedException& ) |
| { |
| } |
| catch ( uno::RuntimeException& ) |
| { |
| } |
| |
| if ( aExtIdentifier.getLength() == 0 ) |
| { |
| // Fallback: |
| // Try to use the folder name to match our black list |
| // as some extensions don't provide an identifier in the |
| // description.xml! |
| for ( sal_uInt32 i = 0; i < m_aBlackList.size(); i++ ) |
| { |
| utl::SearchParam param(m_aBlackList[i], utl::SearchParam::SRCH_REGEXP); |
| utl::TextSearch ts(param, LANGUAGE_DONTKNOW); |
| |
| xub_StrLen start = 0; |
| xub_StrLen end = static_cast<sal_uInt16>(sDescriptionXmlURL.getLength()); |
| if (ts.SearchFrwrd(sDescriptionXmlURL, &start, &end)) |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| bool OO3ExtensionMigration::migrateExtension( const ::rtl::OUString& sSourceDir ) |
| { |
| if ( !m_xExtensionManager.is() ) |
| { |
| try |
| { |
| m_xExtensionManager = deployment::ExtensionManager::get( m_ctx ); |
| } |
| catch ( ucb::CommandFailedException & ){} |
| catch ( uno::RuntimeException & ) {} |
| } |
| |
| if ( m_xExtensionManager.is() ) |
| { |
| try |
| { |
| TmpRepositoryCommandEnv* pCmdEnv = new TmpRepositoryCommandEnv(); |
| |
| uno::Reference< ucb::XCommandEnvironment > xCmdEnv( |
| static_cast< cppu::OWeakObject* >( pCmdEnv ), uno::UNO_QUERY ); |
| uno::Reference< task::XAbortChannel > xAbortChannel; |
| uno::Reference< deployment::XPackage > xPackage = |
| m_xExtensionManager->addExtension( |
| sSourceDir, uno::Sequence<beans::NamedValue>(), |
| ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("user")), xAbortChannel, xCmdEnv ); |
| |
| if ( xPackage.is() ) |
| return true; |
| } |
| catch ( ucb::CommandFailedException& ) |
| { |
| } |
| catch ( ucb::CommandAbortedException& ) |
| { |
| } |
| catch ( lang::IllegalArgumentException& ) |
| { |
| } |
| catch ( deployment::DeploymentException& ) |
| { |
| } |
| catch ( uno::RuntimeException & ) |
| { |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| // ----------------------------------------------------------------------------- |
| // XServiceInfo |
| // ----------------------------------------------------------------------------- |
| |
| ::rtl::OUString OO3ExtensionMigration::getImplementationName() throw (RuntimeException) |
| { |
| return OO3ExtensionMigration_getImplementationName(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool OO3ExtensionMigration::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException) |
| { |
| Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() ); |
| const ::rtl::OUString* pNames = aNames.getConstArray(); |
| const ::rtl::OUString* pEnd = pNames + aNames.getLength(); |
| for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames ) |
| ; |
| |
| return pNames != pEnd; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Sequence< ::rtl::OUString > OO3ExtensionMigration::getSupportedServiceNames() throw (RuntimeException) |
| { |
| return OO3ExtensionMigration_getSupportedServiceNames(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // XInitialization |
| // ----------------------------------------------------------------------------- |
| |
| void OO3ExtensionMigration::initialize( const Sequence< Any >& aArguments ) throw (Exception, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| |
| const Any* pIter = aArguments.getConstArray(); |
| const Any* pEnd = pIter + aArguments.getLength(); |
| for ( ; pIter != pEnd ; ++pIter ) |
| { |
| beans::NamedValue aValue; |
| *pIter >>= aValue; |
| if ( aValue.Name.equalsAscii( "UserData" ) ) |
| { |
| if ( !(aValue.Value >>= m_sSourceDir) ) |
| { |
| OSL_ENSURE( false, "ExtensionMigration::initialize: argument UserData has wrong type!" ); |
| } |
| } |
| else if ( aValue.Name.equalsAscii( "ExtensionBlackList" ) ) |
| { |
| Sequence< ::rtl::OUString > aBlackList; |
| if ( (aValue.Value >>= aBlackList ) && ( aBlackList.getLength() > 0 )) |
| { |
| m_aBlackList.resize( aBlackList.getLength() ); |
| ::comphelper::sequenceToArray< ::rtl::OUString >( &m_aBlackList[0], aBlackList ); |
| } |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| TStringVectorPtr getContent( const ::rtl::OUString& rBaseURL ) |
| { |
| TStringVectorPtr aResult( new TStringVector ); |
| ::osl::Directory aDir( rBaseURL); |
| if ( aDir.open() == ::osl::FileBase::E_None ) |
| { |
| // iterate over directory content |
| TStringVector aSubDirs; |
| ::osl::DirectoryItem aItem; |
| while ( aDir.getNextItem( aItem ) == ::osl::FileBase::E_None ) |
| { |
| ::osl::FileStatus aFileStatus( FileStatusMask_Type | FileStatusMask_FileURL ); |
| if ( aItem.getFileStatus( aFileStatus ) == ::osl::FileBase::E_None ) |
| aResult->push_back( aFileStatus.getFileURL() ); |
| } |
| } |
| |
| return aResult; |
| } |
| |
| Any OO3ExtensionMigration::execute( const Sequence< beans::NamedValue >& ) |
| throw (lang::IllegalArgumentException, Exception, RuntimeException) |
| { |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| |
| ::utl::Bootstrap::PathStatus aStatus = ::utl::Bootstrap::locateUserInstallation( m_sTargetDir ); |
| if ( aStatus == ::utl::Bootstrap::PATH_EXISTS ) |
| { |
| // copy all extensions |
| ::rtl::OUString sSourceDir( m_sSourceDir ); |
| sSourceDir += sExtensionSubDir; |
| sSourceDir += sSubDirName; |
| sSourceDir += sExtensionRootSubDirName; |
| TStringVector aExtensionToMigrate; |
| scanUserExtensions( sSourceDir, aExtensionToMigrate ); |
| if ( aExtensionToMigrate.size() > 0 ) |
| { |
| TStringVector::iterator pIter = aExtensionToMigrate.begin(); |
| while ( pIter != aExtensionToMigrate.end() ) |
| { |
| migrateExtension( *pIter ); |
| ++pIter; |
| } |
| } |
| } |
| |
| return Any(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // TmpRepositoryCommandEnv |
| // ----------------------------------------------------------------------------- |
| |
| TmpRepositoryCommandEnv::TmpRepositoryCommandEnv() |
| { |
| } |
| |
| TmpRepositoryCommandEnv::~TmpRepositoryCommandEnv() |
| { |
| } |
| // XCommandEnvironment |
| //______________________________________________________________________________ |
| uno::Reference< task::XInteractionHandler > TmpRepositoryCommandEnv::getInteractionHandler() |
| throw ( uno::RuntimeException ) |
| { |
| return this; |
| } |
| |
| //______________________________________________________________________________ |
| uno::Reference< ucb::XProgressHandler > TmpRepositoryCommandEnv::getProgressHandler() |
| throw ( uno::RuntimeException ) |
| { |
| return this; |
| } |
| |
| // XInteractionHandler |
| void TmpRepositoryCommandEnv::handle( |
| uno::Reference< task::XInteractionRequest> const & xRequest ) |
| throw ( uno::RuntimeException ) |
| { |
| uno::Any request( xRequest->getRequest() ); |
| OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); |
| |
| bool approve = true; |
| bool abort = false; |
| |
| deployment::VersionException verExc; |
| if ( xRequest->getRequest() >>= verExc ) |
| { |
| // choose newest version, if an extension is already been installed. |
| const bool bChooseNewestVersion = true; |
| approve = handleVersionException( verExc, 0, bChooseNewestVersion ); |
| abort = !approve; |
| } |
| |
| // select: |
| uno::Sequence< Reference< task::XInteractionContinuation > > conts( |
| xRequest->getContinuations() ); |
| Reference< task::XInteractionContinuation > const * pConts = |
| conts.getConstArray(); |
| sal_Int32 len = conts.getLength(); |
| for ( sal_Int32 pos = 0; pos < len; ++pos ) |
| { |
| if (approve) { |
| uno::Reference< task::XInteractionApprove > xInteractionApprove( |
| pConts[ pos ], uno::UNO_QUERY ); |
| if (xInteractionApprove.is()) { |
| xInteractionApprove->select(); |
| // don't query again for ongoing continuations: |
| approve = false; |
| } |
| } |
| else if (abort) { |
| uno::Reference< task::XInteractionAbort > xInteractionAbort( |
| pConts[ pos ], uno::UNO_QUERY ); |
| if (xInteractionAbort.is()) { |
| xInteractionAbort->select(); |
| // don't query again for ongoing continuations: |
| abort = false; |
| } |
| } |
| } |
| } |
| |
| // XProgressHandler |
| void TmpRepositoryCommandEnv::push( uno::Any const & /*Status*/ ) |
| throw (uno::RuntimeException) |
| { |
| } |
| |
| |
| void TmpRepositoryCommandEnv::update( uno::Any const & /*Status */) |
| throw (uno::RuntimeException) |
| { |
| } |
| |
| void TmpRepositoryCommandEnv::pop() throw (uno::RuntimeException) |
| { |
| } |
| |
| // ============================================================================= |
| // component operations |
| // ============================================================================= |
| |
| Reference< XInterface > SAL_CALL OO3ExtensionMigration_create( |
| Reference< XComponentContext > const & ctx ) |
| SAL_THROW( () ) |
| { |
| return static_cast< lang::XTypeProvider * >( new OO3ExtensionMigration( |
| ctx) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| } // namespace migration |