diff options
-rw-r--r-- | libcmis/UnpackedTarball_cmis.mk | 1 | ||||
-rw-r--r-- | libcmis/libcmis-0.3.0-lotus-live-fix.patch | 122 | ||||
-rw-r--r-- | sfx2/source/view/sfxbasecontroller.cxx | 2 | ||||
-rw-r--r-- | ucb/source/ucp/cmis/cmis_content.cxx | 138 | ||||
-rw-r--r-- | ucb/source/ucp/cmis/cmis_content.hxx | 2 | ||||
-rw-r--r-- | ucb/source/ucp/cmis/cmis_url.cxx | 29 |
6 files changed, 259 insertions, 35 deletions
diff --git a/libcmis/UnpackedTarball_cmis.mk b/libcmis/UnpackedTarball_cmis.mk index a25c3164fd7e..0a9f9f8ad2f2 100644 --- a/libcmis/UnpackedTarball_cmis.mk +++ b/libcmis/UnpackedTarball_cmis.mk @@ -18,6 +18,7 @@ $(eval $(call gb_UnpackedTarball_add_patches,cmis, \ libcmis/libcmis-0.3.0-win.patch \ libcmis/libcmis-0.3.0.patch \ libcmis/libcmis-0.3.0-proxy.patch \ + libcmis/libcmis-0.3.0-lotus-live-fix.patch \ )) ifeq ($(OS)$(COM),WNTMSC) diff --git a/libcmis/libcmis-0.3.0-lotus-live-fix.patch b/libcmis/libcmis-0.3.0-lotus-live-fix.patch new file mode 100644 index 000000000000..2aca934df806 --- /dev/null +++ b/libcmis/libcmis-0.3.0-lotus-live-fix.patch @@ -0,0 +1,122 @@ +diff --git src/libcmis/atom-folder.cxx src/libcmis/atom-folder.cxx +index 68fb124..2756a5d 100644 +--- src/libcmis/atom-folder.cxx ++++ src/libcmis/atom-folder.cxx +@@ -57,8 +57,11 @@ vector< libcmis::ObjectPtr > AtomFolder::getChildren( ) throw ( libcmis::Excepti + { + AtomLink* childrenLink = getLink( "down", "application/atom+xml;type=feed" ); + ++ // Some servers aren't giving the GetChildren properly... if not defined, we need to try ++ // as we may have the right to proceed. + if ( ( NULL == childrenLink ) || ( getAllowableActions( ).get() && +- !getAllowableActions()->isAllowed( libcmis::ObjectAction::GetChildren ) ) ) ++ ( !getAllowableActions()->isAllowed( libcmis::ObjectAction::GetChildren ) && ++ getAllowableActions()->isDefined( libcmis::ObjectAction::GetChildren ) ) ) ) + throw libcmis::Exception( string( "GetChildren not allowed on node " ) + getId() ); + + vector< libcmis::ObjectPtr > children; +@@ -182,7 +185,8 @@ libcmis::DocumentPtr AtomFolder::createDocument( const map< string, libcmis::Pro + AtomLink* childrenLink = getLink( "down", "application/atom+xml;type=feed" ); + + if ( ( NULL == childrenLink ) || ( getAllowableActions( ).get() && +- !getAllowableActions()->isAllowed( libcmis::ObjectAction::CreateDocument ) ) ) ++ !getAllowableActions()->isAllowed( libcmis::ObjectAction::CreateDocument ) && ++ getAllowableActions()->isDefined( libcmis::ObjectAction::CreateDocument ) ) ) + throw libcmis::Exception( string( "CreateDocument not allowed on folder " ) + getId() ); + + xmlBufferPtr buf = xmlBufferCreate( ); +@@ -210,9 +214,37 @@ libcmis::DocumentPtr AtomFolder::createDocument( const map< string, libcmis::Pro + } + + string respBuf = response->getStream( )->str( ); +- xmlDocPtr doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL, 0 ); ++ xmlDocPtr doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL, XML_PARSE_NOERROR ); + if ( NULL == doc ) +- throw libcmis::Exception( "Failed to parse object infos" ); ++ { ++ // We may not have the created document entry in the response body: this is ++ // the behaviour of some servers, but the standard says we need to look for ++ // the Location header. ++ map< string, string >& headers = response->getHeaders( ); ++ map< string, string >::iterator it = headers.find( "Location" ); ++ ++ // Some servers like Lotus Live aren't sending Location header, but Content-Location ++ if ( it == headers.end( ) ) ++ it = headers.find( "Content-Location" ); ++ ++ if ( it != headers.end() ) ++ { ++ try ++ { ++ response = getSession( )->httpGetRequest( it->second ); ++ respBuf = response->getStream( )->str( ); ++ doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL, XML_PARSE_NOERROR ); ++ } ++ catch ( const CurlException& e ) ++ { ++ throw e.getCmisException( ); ++ } ++ } ++ ++ // if doc is still NULL after that, then throw an exception ++ if ( NULL == doc ) ++ throw libcmis::Exception( "Missing expected response from server" ); ++ } + + libcmis::ObjectPtr created = getSession( )->createObjectFromEntryDoc( doc ); + xmlFreeDoc( doc ); +diff --git src/libcmis/atom-object.cxx src/libcmis/atom-object.cxx +index b7b3b4a..812951d 100644 +--- src/libcmis/atom-object.cxx ++++ src/libcmis/atom-object.cxx +@@ -140,6 +140,34 @@ libcmis::ObjectPtr AtomObject::updateProperties( const map< string, libcmis::Pro + return updated; + } + ++libcmis::AllowableActionsPtr AtomObject::getAllowableActions( ) ++{ ++ if ( !m_allowableActions ) ++ { ++ // For some reason we had no allowable actions before, get them now. ++ AtomLink* link = getLink( "http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions", "application/cmisallowableactions+xml" ); ++ if ( link ) ++ { ++ try ++ { ++ libcmis::HttpResponsePtr response = getSession()->httpGetRequest( link->getHref() ); ++ string buf = response->getStream()->str(); ++ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), link->getHref().c_str(), NULL, 0 ); ++ xmlNodePtr actionsNode = xmlDocGetRootElement( doc ); ++ if ( actionsNode ) ++ m_allowableActions.reset( new libcmis::AllowableActions( actionsNode ) ); ++ ++ xmlFreeDoc( doc ); ++ } ++ catch ( libcmis::Exception& ) ++ { ++ } ++ } ++ } ++ ++ return libcmis::Object::getAllowableActions(); ++} ++ + void AtomObject::refreshImpl( xmlDocPtr doc ) throw ( libcmis::Exception ) + { + bool createdDoc = ( NULL == doc ); +diff --git src/libcmis/atom-object.hxx src/libcmis/atom-object.hxx +index 2d1761d..452b4f5 100644 +--- src/libcmis/atom-object.hxx ++++ src/libcmis/atom-object.hxx +@@ -69,6 +69,8 @@ class AtomObject : public virtual libcmis::Object + virtual libcmis::ObjectPtr updateProperties( + const std::map< std::string, libcmis::PropertyPtr >& properties ) throw ( libcmis::Exception ); + ++ virtual libcmis::AllowableActionsPtr getAllowableActions( ); ++ + /** Reload the data from the server. + */ + virtual void refresh( ) throw ( libcmis::Exception ) { refreshImpl( NULL ); } +-- +1.7.10.4 + diff --git a/sfx2/source/view/sfxbasecontroller.cxx b/sfx2/source/view/sfxbasecontroller.cxx index f1b2b01bf73b..c97d014aaa2d 100644 --- a/sfx2/source/view/sfxbasecontroller.cxx +++ b/sfx2/source/view/sfxbasecontroller.cxx @@ -1439,7 +1439,7 @@ void SfxBaseController::ShowInfoBars( ) { // CMIS verifications REFERENCE< document::XCmisDocument > xCmisDoc( m_pData->m_pViewShell->GetObjectShell()->GetModel(), uno::UNO_QUERY ); - if ( xCmisDoc.is( ) ) + if ( xCmisDoc.is( ) && xCmisDoc->canCheckOut( ) ) { beans::PropertyValues aCmisProperties = xCmisDoc->getCmisPropertiesValues( ); diff --git a/ucb/source/ucp/cmis/cmis_content.cxx b/ucb/source/ucp/cmis/cmis_content.cxx index 5f94d7a8d51e..2a78b4e03898 100644 --- a/ucb/source/ucp/cmis/cmis_content.cxx +++ b/ucb/source/ucp/cmis/cmis_content.cxx @@ -307,7 +307,46 @@ namespace cmis if ( NULL == m_pObjectType.get( ) && m_bTransient ) { string typeId = m_bIsFolder ? "cmis:folder" : "cmis:document"; - m_pObjectType = getSession( xEnv )->getType( typeId ); + // The type to create needs to be fetched from the possible children types + // defined in the parent folder. Then, we'll pick up the first one we find matching + // cmis:folder or cmis:document (depending what we need to create). + // The easy case will work in most cases, but not on some servers (like Lotus Live) + libcmis::Folder* pParent = NULL; + bool bTypeRestricted = false; + try + { + pParent = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get( ) ); + } + catch ( const libcmis::Exception& ) + { + } + + if ( pParent ) + { + map< string, libcmis::PropertyPtr >& aProperties = pParent->getProperties( ); + map< string, libcmis::PropertyPtr >::iterator it = aProperties.find( "cmis:allowedChildObjectTypeIds" ); + if ( it != aProperties.end( ) ) + { + libcmis::PropertyPtr pProperty = it->second; + if ( pProperty ) + { + vector< string > typesIds = pProperty->getStrings( ); + for ( vector< string >::iterator typeIt = typesIds.begin(); + typeIt != typesIds.end() && !m_pObjectType; ++typeIt ) + { + bTypeRestricted = true; + libcmis::ObjectTypePtr type = getSession( xEnv )->getType( *typeIt ); + + // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis + if ( type->getBaseType( )->getId( ) == typeId ) + m_pObjectType = type; + } + } + } + } + + if ( !bTypeRestricted ) + m_pObjectType = getSession( xEnv )->getType( typeId ); } return m_pObjectType; } @@ -318,7 +357,39 @@ namespace cmis if ( !m_pObject.get() ) { if ( !m_sObjectPath.isEmpty( ) ) - m_pObject = getSession( xEnv )->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath ) ); + { + try + { + m_pObject = getSession( xEnv )->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath ) ); + } + catch ( const libcmis::Exception& ) + { + // In some cases, getting the object from the path doesn't work, + // but getting the parent from its path and the get the child in the list is OK. + // It's weird, but needed to handle case where the path isn't the folders/files + // names separated by '/' (as in Lotus Live) + INetURLObject aParentUrl( m_sURL ); + string sName = OUSTR_TO_STDSTR( aParentUrl.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ) ); + aParentUrl.removeSegment( ); + rtl::OUString sParentUrl = aParentUrl.GetMainURL( INetURLObject::NO_DECODE ); + + Content aParent( m_xContext, m_pProvider, new ucbhelper::ContentIdentifier( sParentUrl ) ); + libcmis::FolderPtr pParentFolder = boost::dynamic_pointer_cast< libcmis::Folder >( aParent.getObject( xEnv ) ); + if ( pParentFolder ) + { + vector< libcmis::ObjectPtr > children = pParentFolder->getChildren( ); + for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( ); + it != children.end() && !m_pObject; ++it ) + { + if ( ( *it )->getName( ) == sName ) + m_pObject = *it; + } + } + + if ( !m_pObject ) + throw libcmis::Exception( "Object not found" ); + } + } else if (!m_sObjectId.isEmpty( ) ) m_pObject = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId ) ); else @@ -643,25 +714,6 @@ namespace cmis return uno::Reference< sdbc::XRow >( xRow.get() ); } - bool Content::exists( const uno::Reference< ucb::XCommandEnvironment >& xEnv ) - { - bool bExists = true; - try - { - if ( !m_sObjectPath.isEmpty( ) ) - m_pSession->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath ) ); - else if ( !m_sObjectId.isEmpty( ) ) - getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId ) ); - // No need to handle the root folder case... how can it not exists? - } - catch ( const libcmis::Exception& ) - { - bExists = false; - } - - return bExists; - } - uno::Any Content::open(const ucb::OpenCommandArgument2 & rOpenCommand, const uno::Reference< ucb::XCommandEnvironment > & xEnv ) throw( uno::Exception ) @@ -669,7 +721,7 @@ namespace cmis bool bIsFolder = isFolder( xEnv ); // Handle the case of the non-existing file - if ( !exists( xEnv ) ) + if ( !getObject( xEnv ) ) { uno::Sequence< uno::Any > aArgs( 1 ); aArgs[ 0 ] <<= m_xIdentifier->getContentIdentifier(); @@ -992,7 +1044,17 @@ namespace cmis boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) ); uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut ); copyData( xInputStream, xOutput ); - document->setContentStream( pOut, OUSTR_TO_STDSTR( rMimeType ), string( ), bReplaceExisting ); + try + { + document->setContentStream( pOut, OUSTR_TO_STDSTR( rMimeType ), string( ), bReplaceExisting ); + } + catch ( const libcmis::Exception& ) + { + ucbhelper::cancelCommandExecution( uno::makeAny + ( uno::RuntimeException( "Error when setting document content", + static_cast< cppu::OWeakObject * >( this ) ) ), + xEnv ); + } } } else @@ -1003,16 +1065,36 @@ namespace cmis if ( bIsFolder ) { - libcmis::FolderPtr pNew = pFolder->createFolder( m_pObjectProps ); - sNewPath = STD_TO_OUSTR( newPath ); + try + { + libcmis::FolderPtr pNew = pFolder->createFolder( m_pObjectProps ); + sNewPath = STD_TO_OUSTR( newPath ); + } + catch ( const libcmis::Exception& ) + { + ucbhelper::cancelCommandExecution( uno::makeAny + ( uno::RuntimeException( "Error when creating folder", + static_cast< cppu::OWeakObject * >( this ) ) ), + xEnv ); + } } else { boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) ); uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut ); copyData( xInputStream, xOutput ); - pFolder->createDocument( m_pObjectProps, pOut, OUSTR_TO_STDSTR( rMimeType ), string() ); - sNewPath = STD_TO_OUSTR( newPath ); + try + { + pFolder->createDocument( m_pObjectProps, pOut, OUSTR_TO_STDSTR( rMimeType ), string() ); + sNewPath = STD_TO_OUSTR( newPath ); + } + catch ( const libcmis::Exception& ) + { + ucbhelper::cancelCommandExecution( uno::makeAny + ( uno::RuntimeException( "Error when creating document", + static_cast< cppu::OWeakObject * >( this ) ) ), + xEnv ); + } } } @@ -1336,7 +1418,7 @@ namespace cmis { URL aCmisUrl( m_sURL ); aUrl.removeSegment( ); - aCmisUrl.setObjectPath( aUrl.GetURLPath( INetURLObject::NO_DECODE ) ); + aCmisUrl.setObjectPath( aUrl.GetURLPath( INetURLObject::DECODE_WITH_CHARSET ) ); sRet = aCmisUrl.asString( ); } } diff --git a/ucb/source/ucp/cmis/cmis_content.hxx b/ucb/source/ucp/cmis/cmis_content.hxx index b28c3011ae68..7260cb38517a 100644 --- a/ucb/source/ucp/cmis/cmis_content.hxx +++ b/ucb/source/ucp/cmis/cmis_content.hxx @@ -99,8 +99,6 @@ private: libcmis::Session* getSession( const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv ); libcmis::ObjectTypePtr getObjectType( const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv ); - bool exists( const com::sun::star::uno::Reference< com::sun::star::ucb::XCommandEnvironment >& xEnv ); - private: typedef rtl::Reference< Content > ContentRef; typedef std::list< ContentRef > ContentRefList; diff --git a/ucb/source/ucp/cmis/cmis_url.cxx b/ucb/source/ucp/cmis/cmis_url.cxx index 40d7a2580001..dc23c9e04f1c 100644 --- a/ucb/source/ucp/cmis/cmis_url.cxx +++ b/ucb/source/ucp/cmis/cmis_url.cxx @@ -107,13 +107,34 @@ namespace cmis if ( !m_sPath.isEmpty( ) ) { - if ( m_sPath[0] != '/' ) - sUrl += "/"; - sUrl += m_sPath; + sal_Int32 nPos = -1; + rtl::OUString sEncodedPath; + do + { + sal_Int32 nStartPos = nPos + 1; + nPos = m_sPath.indexOf( '/', nStartPos ); + sal_Int32 nLen = nPos - nStartPos; + if ( nPos == -1 ) + nLen = m_sPath.getLength( ) - nStartPos; + rtl::OUString sSegment = m_sPath.copy( nStartPos, nLen ); + + if ( !sSegment.isEmpty( ) ) + { + sEncodedPath += "/" + rtl::Uri::encode( sSegment, + rtl_UriCharClassRelSegment, + rtl_UriEncodeKeepEscapes, + RTL_TEXTENCODING_UTF8 ); + } + } + while ( nPos != -1 ); + sUrl += sEncodedPath; } else if ( !m_sId.isEmpty( ) ) { - sUrl += "#" + m_sId; + sUrl += "#" + rtl::Uri::encode( m_sId, + rtl_UriCharClassRelSegment, + rtl_UriEncodeKeepEscapes, + RTL_TEXTENCODING_UTF8 ); } return sUrl; |