1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <string_view>
12 #include <boost/make_shared.hpp>
14 #include <com/sun/star/beans/IllegalTypeException.hpp>
15 #include <com/sun/star/beans/PropertyAttribute.hpp>
16 #include <com/sun/star/beans/PropertyValue.hpp>
17 #include <com/sun/star/beans/XPropertySetInfo.hpp>
18 #include <com/sun/star/document/CmisProperty.hpp>
19 #include <com/sun/star/io/XActiveDataSink.hpp>
20 #include <com/sun/star/io/XActiveDataStreamer.hpp>
21 #include <com/sun/star/lang/IllegalAccessException.hpp>
22 #include <com/sun/star/lang/IllegalArgumentException.hpp>
23 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
24 #include <com/sun/star/task/InteractionClassification.hpp>
25 #include <com/sun/star/ucb/ContentInfo.hpp>
26 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
27 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
28 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
29 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
30 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
31 #include <com/sun/star/ucb/OpenMode.hpp>
32 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
33 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
34 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
35 #include <com/sun/star/ucb/XCommandInfo.hpp>
36 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
38 #include <com/sun/star/xml/crypto/XDigestContext.hpp>
39 #include <com/sun/star/xml/crypto/DigestID.hpp>
40 #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
43 #include <comphelper/processfactory.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <cppuhelper/exc_hlp.hxx>
46 #include <cppuhelper/queryinterface.hxx>
47 #include <config_oauth2.h>
48 #include <o3tl/runtimetooustring.hxx>
49 #include <sal/log.hxx>
50 #include <tools/urlobj.hxx>
51 #include <tools/long.hxx>
52 #include <ucbhelper/cancelcommandexecution.hxx>
53 #include <ucbhelper/content.hxx>
54 #include <ucbhelper/contentidentifier.hxx>
55 #include <ucbhelper/propertyvalueset.hxx>
56 #include <ucbhelper/proxydecider.hxx>
57 #include <ucbhelper/macros.hxx>
58 #include <sax/tools/converter.hxx>
59 #include <systools/curlinit.hxx>
63 #include "auth_provider.hxx"
64 #include "certvalidation_handler.hxx"
65 #include "cmis_content.hxx"
66 #include "cmis_provider.hxx"
67 #include "cmis_resultset.hxx"
68 #include "cmis_strings.hxx"
69 #include "std_inputstream.hxx"
70 #include "std_outputstream.hxx"
72 #define OUSTR_TO_STDSTR(s) std::string( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ) )
73 #define STD_TO_OUSTR( str ) OStringToOUString( str, RTL_TEXTENCODING_UTF8 )
75 using namespace com::sun::star
;
79 util::DateTime
lcl_boostToUnoTime(const boost::posix_time::ptime
& boostTime
)
81 util::DateTime unoTime
;
82 unoTime
.Year
= boostTime
.date().year();
83 unoTime
.Month
= boostTime
.date().month();
84 unoTime
.Day
= boostTime
.date().day();
85 unoTime
.Hours
= boostTime
.time_of_day().hours();
86 unoTime
.Minutes
= boostTime
.time_of_day().minutes();
87 unoTime
.Seconds
= boostTime
.time_of_day().seconds();
89 // TODO FIXME maybe we should compile with BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
90 // to actually get nanosecond precision in boostTime?
91 // use this way rather than total_nanos to avoid overflows with 32-bit long
92 const tools::Long ticks
= boostTime
.time_of_day().fractional_seconds();
93 tools::Long nanoSeconds
= ticks
* ( 1000000000 / boost::posix_time::time_duration::ticks_per_second());
95 unoTime
.NanoSeconds
= nanoSeconds
;
100 uno::Any
lcl_cmisPropertyToUno( const libcmis::PropertyPtr
& pProperty
)
103 switch ( pProperty
->getPropertyType( )->getType( ) )
106 case libcmis::PropertyType::String
:
108 auto aCmisStrings
= pProperty
->getStrings( );
109 uno::Sequence
< OUString
> aStrings( aCmisStrings
.size( ) );
110 OUString
* aStringsArr
= aStrings
.getArray( );
112 for ( const auto& rCmisStr
: aCmisStrings
)
114 aStringsArr
[i
++] = STD_TO_OUSTR( rCmisStr
);
119 case libcmis::PropertyType::Integer
:
121 auto aCmisLongs
= pProperty
->getLongs( );
122 uno::Sequence
< sal_Int64
> aLongs( aCmisLongs
.size( ) );
123 sal_Int64
* aLongsArr
= aLongs
.getArray( );
125 for ( const auto& rCmisLong
: aCmisLongs
)
127 aLongsArr
[i
++] = rCmisLong
;
132 case libcmis::PropertyType::Decimal
:
134 auto aCmisDoubles
= pProperty
->getDoubles( );
135 uno::Sequence
< double > aDoubles
= comphelper::containerToSequence(aCmisDoubles
);
139 case libcmis::PropertyType::Bool
:
141 auto aCmisBools
= pProperty
->getBools( );
142 uno::Sequence
< sal_Bool
> aBools( aCmisBools
.size( ) );
143 sal_Bool
* aBoolsArr
= aBools
.getArray( );
145 for ( bool bCmisBool
: aCmisBools
)
147 aBoolsArr
[i
++] = bCmisBool
;
152 case libcmis::PropertyType::DateTime
:
154 auto aCmisTimes
= pProperty
->getDateTimes( );
155 uno::Sequence
< util::DateTime
> aTimes( aCmisTimes
.size( ) );
156 util::DateTime
* aTimesArr
= aTimes
.getArray( );
158 for ( const auto& rCmisTime
: aCmisTimes
)
160 aTimesArr
[i
++] = lcl_boostToUnoTime( rCmisTime
);
169 libcmis::PropertyPtr
lcl_unoToCmisProperty(const document::CmisProperty
& prop
)
171 libcmis::PropertyTypePtr
propertyType( new libcmis::PropertyType( ) );
173 OUString id
= prop
.Id
;
174 OUString name
= prop
.Name
;
175 bool bUpdatable
= prop
.Updatable
;
176 bool bRequired
= prop
.Required
;
177 bool bMultiValued
= prop
.MultiValued
;
178 bool bOpenChoice
= prop
.OpenChoice
;
179 uno::Any value
= prop
.Value
;
180 std::vector
< std::string
> values
;
182 libcmis::PropertyType::Type type
= libcmis::PropertyType::String
;
183 if ( prop
.Type
== CMIS_TYPE_STRING
)
185 uno::Sequence
< OUString
> seqValue
;
187 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
188 [](const OUString
& rValue
) -> std::string
{ return OUSTR_TO_STDSTR( rValue
); });
189 type
= libcmis::PropertyType::String
;
191 else if ( prop
.Type
== CMIS_TYPE_BOOL
)
193 uno::Sequence
< sal_Bool
> seqValue
;
195 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
196 [](const bool nValue
) -> std::string
{ return std::string( OString::boolean( nValue
) ); });
197 type
= libcmis::PropertyType::Bool
;
199 else if ( prop
.Type
== CMIS_TYPE_INTEGER
)
201 uno::Sequence
< sal_Int64
> seqValue
;
203 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
204 [](const sal_Int64 nValue
) -> std::string
{ return std::string( OString::number( nValue
) ); });
205 type
= libcmis::PropertyType::Integer
;
207 else if ( prop
.Type
== CMIS_TYPE_DECIMAL
)
209 uno::Sequence
< double > seqValue
;
211 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
212 [](const double fValue
) -> std::string
{ return std::string( OString::number( fValue
) ); });
213 type
= libcmis::PropertyType::Decimal
;
215 else if ( prop
.Type
== CMIS_TYPE_DATETIME
)
217 uno::Sequence
< util::DateTime
> seqValue
;
219 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
220 [](const util::DateTime
& rValue
) -> std::string
{
221 OUStringBuffer aBuffer
;
222 ::sax::Converter::convertDateTime( aBuffer
, rValue
, nullptr );
223 return OUSTR_TO_STDSTR( aBuffer
);
225 type
= libcmis::PropertyType::DateTime
;
228 propertyType
->setId( OUSTR_TO_STDSTR( id
));
229 propertyType
->setDisplayName( OUSTR_TO_STDSTR( name
) );
230 propertyType
->setUpdatable( bUpdatable
);
231 propertyType
->setRequired( bRequired
);
232 propertyType
->setMultiValued( bMultiValued
);
233 propertyType
->setOpenChoice( bOpenChoice
);
234 propertyType
->setType( type
);
236 libcmis::PropertyPtr
property( new libcmis::Property( propertyType
, std::move(values
) ) );
241 uno::Sequence
< uno::Any
> generateErrorArguments( const cmis::URL
& rURL
)
243 uno::Sequence
< uno::Any
> aArguments
{ uno::Any(beans::PropertyValue(
246 uno::Any( rURL
.getBindingUrl() ),
247 beans::PropertyState_DIRECT_VALUE
)),
248 uno::Any(beans::PropertyValue(
251 uno::Any( rURL
.getUsername() ),
252 beans::PropertyState_DIRECT_VALUE
)),
253 uno::Any(beans::PropertyValue(
256 uno::Any( rURL
.getRepositoryId() ),
257 beans::PropertyState_DIRECT_VALUE
)) };
265 Content::Content( const uno::Reference
< uno::XComponentContext
>& rxContext
,
266 ContentProvider
*pProvider
, const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
267 libcmis::ObjectPtr pObject
)
268 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
269 m_pProvider( pProvider
),
270 m_pSession( nullptr ),
271 m_pObject(std::move( pObject
)),
272 m_sURL( Identifier
->getContentIdentifier( ) ),
273 m_aURL( Identifier
->getContentIdentifier( ) ),
274 m_bTransient( false ),
277 SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL
);
279 m_sObjectPath
= m_aURL
.getObjectPath( );
280 m_sObjectId
= m_aURL
.getObjectId( );
283 Content::Content( const uno::Reference
< uno::XComponentContext
>& rxContext
, ContentProvider
*pProvider
,
284 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
286 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
287 m_pProvider( pProvider
),
288 m_pSession( nullptr ),
289 m_sURL( Identifier
->getContentIdentifier( ) ),
290 m_aURL( Identifier
->getContentIdentifier( ) ),
291 m_bTransient( true ),
292 m_bIsFolder( bIsFolder
)
294 SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL
);
296 m_sObjectPath
= m_aURL
.getObjectPath( );
297 m_sObjectId
= m_aURL
.getObjectId( );
304 libcmis::Session
* Content::getSession( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
306 // Set the proxy if needed. We are doing that all times as the proxy data shouldn't be cached.
307 ucbhelper::InternetProxyDecider
aProxyDecider( m_xContext
);
308 INetURLObject
aBindingUrl( m_aURL
.getBindingUrl( ) );
309 const OUString sProxy
= aProxyDecider
.getProxy(
310 INetURLObject::GetScheme( aBindingUrl
.GetProtocol( ) ), aBindingUrl
.GetHost(), aBindingUrl
.GetPort() );
311 libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy
), std::string(), std::string(), std::string() );
313 // Look for a cached session, key is binding url + repo id
314 OUString sSessionId
= m_aURL
.getBindingUrl( ) + m_aURL
.getRepositoryId( );
315 if ( nullptr == m_pSession
)
316 m_pSession
= m_pProvider
->getSession( sSessionId
, m_aURL
.getUsername( ) );
318 if ( nullptr == m_pSession
)
321 // Initialize NSS library to make sure libcmis (and curl) can access CACERTs using NSS
322 // when using internal libcurl.
323 uno::Reference
< css::xml::crypto::XNSSInitializer
>
324 xNSSInitializer
= css::xml::crypto::NSSInitializer::create( m_xContext
);
326 uno::Reference
< css::xml::crypto::XDigestContext
> xDigestContext(
327 xNSSInitializer
->getDigestContext( css::xml::crypto::DigestID::SHA256
,
328 uno::Sequence
< beans::NamedValue
>() ),
329 uno::UNO_SET_THROW
);
332 // Set the SSL Validation handler
333 libcmis::CertValidationHandlerPtr
certHandler(
334 new CertValidationHandler( xEnv
, m_xContext
, aBindingUrl
.GetHost( ) ) );
335 libcmis::SessionFactory::setCertificateValidationHandler( certHandler
);
337 // init libcurl callback
338 libcmis::SessionFactory::setCurlInitProtocolsFunction(&::InitCurl_easy
);
340 // Get the auth credentials
341 AuthProvider
aAuthProvider(xEnv
, m_xIdentifier
->getContentIdentifier(), m_aURL
.getBindingUrl());
342 AuthProvider::setXEnv( xEnv
);
344 auto rUsername
= OUSTR_TO_STDSTR( m_aURL
.getUsername( ) );
345 auto rPassword
= OUSTR_TO_STDSTR( m_aURL
.getPassword( ) );
347 bool bSkipInitialPWAuth
= false;
348 if (m_aURL
.getBindingUrl() == ONEDRIVE_BASE_URL
349 || m_aURL
.getBindingUrl() == GDRIVE_BASE_URL
)
351 // skip the initial username and pw-auth prompt, the only supported method is the
352 // auth-code-fallback one (login with your browser, copy code into the dialog)
353 // TODO: if LO were to listen on localhost for the request, it would be much nicer
355 bSkipInitialPWAuth
= true;
356 rPassword
= aAuthProvider
.getRefreshToken(rUsername
);
359 bool bIsDone
= false;
363 if (bSkipInitialPWAuth
|| aAuthProvider
.authenticationQuery(rUsername
, rPassword
))
365 // Initiate a CMIS session and register it as we found nothing
366 libcmis::OAuth2DataPtr oauth2Data
;
367 if ( m_aURL
.getBindingUrl( ) == GDRIVE_BASE_URL
)
369 // reset the skip, so user gets a chance to cancel
370 bSkipInitialPWAuth
= false;
371 libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback
);
372 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
373 GDRIVE_AUTH_URL
, GDRIVE_TOKEN_URL
,
374 GDRIVE_SCOPE
, GDRIVE_REDIRECT_URI
,
375 GDRIVE_CLIENT_ID
, GDRIVE_CLIENT_SECRET
);
377 if ( m_aURL
.getBindingUrl().startsWith( ALFRESCO_CLOUD_BASE_URL
) )
378 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
379 ALFRESCO_CLOUD_AUTH_URL
, ALFRESCO_CLOUD_TOKEN_URL
,
380 ALFRESCO_CLOUD_SCOPE
, ALFRESCO_CLOUD_REDIRECT_URI
,
381 ALFRESCO_CLOUD_CLIENT_ID
, ALFRESCO_CLOUD_CLIENT_SECRET
);
382 if ( m_aURL
.getBindingUrl( ) == ONEDRIVE_BASE_URL
)
384 // reset the skip, so user gets a chance to cancel
385 bSkipInitialPWAuth
= false;
386 libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback
);
387 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
388 ONEDRIVE_AUTH_URL
, ONEDRIVE_TOKEN_URL
,
389 ONEDRIVE_SCOPE
, ONEDRIVE_REDIRECT_URI
,
390 ONEDRIVE_CLIENT_ID
, ONEDRIVE_CLIENT_SECRET
);
394 m_pSession
= libcmis::SessionFactory::createSession(
395 OUSTR_TO_STDSTR( m_aURL
.getBindingUrl( ) ),
396 rUsername
, rPassword
, OUSTR_TO_STDSTR( m_aURL
.getRepositoryId( ) ), false, oauth2Data
);
398 if ( m_pSession
== nullptr )
400 // Fail: session was not created
401 ucbhelper::cancelCommandExecution(
402 ucb::IOErrorCode_INVALID_DEVICE
,
403 generateErrorArguments(m_aURL
),
406 else if ( m_pSession
->getRepository() == nullptr )
408 // Fail: no repository or repository is invalid
409 ucbhelper::cancelCommandExecution(
410 ucb::IOErrorCode_INVALID_DEVICE
,
411 generateErrorArguments(m_aURL
),
413 "error accessing a repository");
417 m_pProvider
->registerSession(sSessionId
, m_aURL
.getUsername( ), m_pSession
);
418 if (m_aURL
.getBindingUrl() == ONEDRIVE_BASE_URL
419 || m_aURL
.getBindingUrl() == GDRIVE_BASE_URL
)
421 aAuthProvider
.storeRefreshToken(rUsername
, rPassword
,
422 m_pSession
->getRefreshToken());
428 catch( const libcmis::Exception
& e
)
430 if ( e
.getType() != "permissionDenied" )
432 SAL_INFO("ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what());
439 // Silently fail as the user cancelled the authentication
440 ucbhelper::cancelCommandExecution(
441 ucb::IOErrorCode_ABORT
,
442 uno::Sequence
< uno::Any
>( 0 ),
444 throw uno::RuntimeException( );
451 libcmis::ObjectTypePtr
const & Content::getObjectType( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
453 if ( nullptr == m_pObjectType
.get( ) && m_bTransient
)
455 std::string typeId
= m_bIsFolder
? "cmis:folder" : "cmis:document";
456 // The type to create needs to be fetched from the possible children types
457 // defined in the parent folder. Then, we'll pick up the first one we find matching
458 // cmis:folder or cmis:document (depending what we need to create).
459 // The easy case will work in most cases, but not on some servers (like Lotus Live)
460 libcmis::Folder
* pParent
= nullptr;
461 bool bTypeRestricted
= false;
464 pParent
= dynamic_cast< libcmis::Folder
* >( getObject( xEnv
).get( ) );
466 catch ( const libcmis::Exception
& )
472 std::map
< std::string
, libcmis::PropertyPtr
>& aProperties
= pParent
->getProperties( );
473 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= aProperties
.find( "cmis:allowedChildObjectTypeIds" );
474 if ( it
!= aProperties
.end( ) )
476 libcmis::PropertyPtr pProperty
= it
->second
;
479 std::vector
< std::string
> typesIds
= pProperty
->getStrings( );
480 for ( const auto& rType
: typesIds
)
482 bTypeRestricted
= true;
483 libcmis::ObjectTypePtr type
= getSession( xEnv
)->getType( rType
);
485 // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis
486 if ( type
->getBaseType( )->getId( ) == typeId
)
488 m_pObjectType
= type
;
496 if ( !bTypeRestricted
)
497 m_pObjectType
= getSession( xEnv
)->getType( typeId
);
499 return m_pObjectType
;
503 libcmis::ObjectPtr
const & Content::getObject( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
505 // can't get the session for some reason
506 // the recent file opening at start up is an example.
509 if ( !getSession( xEnv
) )
512 catch ( uno::RuntimeException
& )
516 if ( !m_pObject
.get() )
518 if ( !m_sObjectId
.isEmpty( ) )
522 m_pObject
= getSession( xEnv
)->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
524 catch ( const libcmis::Exception
& )
526 SAL_INFO( "ucb.ucp.cmis", "object: " << OUSTR_TO_STDSTR(m_sObjectId
));
527 throw libcmis::Exception( "Object not found" );
530 else if (!(m_sObjectPath
.isEmpty() || m_sObjectPath
== "/"))
534 m_pObject
= getSession( xEnv
)->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath
) );
536 catch ( const libcmis::Exception
& )
538 // In some cases, getting the object from the path doesn't work,
539 // but getting the parent from its path and the get the child in the list is OK.
540 // It's weird, but needed to handle case where the path isn't the folders/files
541 // names separated by '/' (as in Lotus Live)
542 INetURLObject
aParentUrl( m_sURL
);
543 std::string sName
= OUSTR_TO_STDSTR( aParentUrl
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
) );
544 aParentUrl
.removeSegment( );
545 OUString sParentUrl
= aParentUrl
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
546 // Avoid infinite recursion if sParentUrl == m_sURL
547 if (sParentUrl
!= m_sURL
)
549 rtl::Reference
<Content
> xParent(new Content(m_xContext
, m_pProvider
, new ucbhelper::ContentIdentifier(sParentUrl
)));
550 libcmis::FolderPtr pParentFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>(xParent
->getObject(xEnv
));
553 std::vector
< libcmis::ObjectPtr
> children
= pParentFolder
->getChildren();
554 auto it
= std::find_if(children
.begin(), children
.end(),
555 [&sName
](const libcmis::ObjectPtr
& rChild
) { return rChild
->getName() == sName
; });
556 if (it
!= children
.end())
562 throw libcmis::Exception( "Object not found" );
567 m_pObject
= getSession( xEnv
)->getRootFolder( );
569 m_sObjectId
= OUString( );
576 bool Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
578 bool bIsFolder
= false;
581 libcmis::ObjectPtr obj
= getObject( xEnv
);
583 bIsFolder
= obj
->getBaseType( ) == "cmis:folder";
585 catch ( const libcmis::Exception
& e
)
587 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
589 ucbhelper::cancelCommandExecution(
590 ucb::IOErrorCode_GENERAL
,
591 uno::Sequence
< uno::Any
>( 0 ),
593 OUString::createFromAscii( e
.what( ) ) );
599 uno::Any
Content::getBadArgExcept()
601 return uno::Any( lang::IllegalArgumentException(
602 "Wrong argument type!",
606 libcmis::ObjectPtr
Content::updateProperties(
607 const uno::Any
& iCmisProps
,
608 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
610 // Convert iCmisProps to Cmis Properties;
611 uno::Sequence
< document::CmisProperty
> aPropsSeq
;
612 iCmisProps
>>= aPropsSeq
;
613 std::map
< std::string
, libcmis::PropertyPtr
> aProperties
;
615 for ( const auto& rProp
: std::as_const(aPropsSeq
) )
617 std::string id
= OUSTR_TO_STDSTR( rProp
.Id
);
618 libcmis::PropertyPtr prop
= lcl_unoToCmisProperty( rProp
);
619 aProperties
.insert( std::pair
<std::string
, libcmis::PropertyPtr
>( id
, prop
) );
621 libcmis::ObjectPtr updateObj
;
624 updateObj
= getObject( xEnv
)->updateProperties( aProperties
);
626 catch ( const libcmis::Exception
& e
)
628 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: "<< e
.what( ) );
634 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
635 const uno::Sequence
< beans::Property
>& rProperties
,
636 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
638 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
= new ::ucbhelper::PropertyValueSet( m_xContext
);
640 for( const beans::Property
& rProp
: rProperties
)
644 if ( rProp
.Name
== "IsDocument" )
648 libcmis::ObjectPtr obj
= getObject( xEnv
);
650 xRow
->appendBoolean( rProp
, obj
->getBaseType( ) == "cmis:document" );
652 catch ( const libcmis::Exception
& )
654 if ( m_pObjectType
.get( ) )
655 xRow
->appendBoolean( rProp
, getObjectType( xEnv
)->getBaseType()->getId( ) == "cmis:document" );
657 xRow
->appendVoid( rProp
);
660 else if ( rProp
.Name
== "IsFolder" )
664 libcmis::ObjectPtr obj
= getObject( xEnv
);
666 xRow
->appendBoolean( rProp
, obj
->getBaseType( ) == "cmis:folder" );
668 xRow
->appendBoolean( rProp
, false );
670 catch ( const libcmis::Exception
& )
672 if ( m_pObjectType
.get( ) )
673 xRow
->appendBoolean( rProp
, getObjectType( xEnv
)->getBaseType()->getId( ) == "cmis:folder" );
675 xRow
->appendVoid( rProp
);
678 else if ( rProp
.Name
== "Title" )
683 sTitle
= STD_TO_OUSTR( getObject( xEnv
)->getName() );
685 catch ( const libcmis::Exception
& )
687 if ( !m_pObjectProps
.empty() )
689 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
690 if ( it
!= m_pObjectProps
.end( ) )
692 std::vector
< std::string
> values
= it
->second
->getStrings( );
693 if ( !values
.empty() )
694 sTitle
= STD_TO_OUSTR( values
.front( ) );
699 // Nothing worked... get it from the path
700 if ( sTitle
.isEmpty( ) )
702 OUString sPath
= m_sObjectPath
;
704 // Get rid of the trailing slash problem
705 if ( sPath
.endsWith("/") )
706 sPath
= sPath
.copy( 0, sPath
.getLength() - 1 );
708 // Get the last segment
709 sal_Int32 nPos
= sPath
.lastIndexOf( '/' );
711 sTitle
= sPath
.copy( nPos
+ 1 );
714 if ( !sTitle
.isEmpty( ) )
715 xRow
->appendString( rProp
, sTitle
);
717 xRow
->appendVoid( rProp
);
719 else if ( rProp
.Name
== "ObjectId" )
724 sId
= STD_TO_OUSTR( getObject( xEnv
)->getId() );
726 catch ( const libcmis::Exception
& )
728 if ( !m_pObjectProps
.empty() )
730 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:objectId" );
731 if ( it
!= m_pObjectProps
.end( ) )
733 std::vector
< std::string
> values
= it
->second
->getStrings( );
734 if ( !values
.empty() )
735 sId
= STD_TO_OUSTR( values
.front( ) );
740 if ( !sId
.isEmpty( ) )
741 xRow
->appendString( rProp
, sId
);
743 xRow
->appendVoid( rProp
);
745 else if ( rProp
.Name
== "TitleOnServer" )
747 xRow
->appendString( rProp
, m_sObjectPath
);
749 else if ( rProp
.Name
== "IsReadOnly" )
751 boost::shared_ptr
< libcmis::AllowableActions
> allowableActions
= getObject( xEnv
)->getAllowableActions( );
752 bool bReadOnly
= false;
753 if ( !allowableActions
->isAllowed( libcmis::ObjectAction::SetContentStream
) &&
754 !allowableActions
->isAllowed( libcmis::ObjectAction::CheckIn
) )
757 xRow
->appendBoolean( rProp
, bReadOnly
);
759 else if ( rProp
.Name
== "DateCreated" )
761 util::DateTime aTime
= lcl_boostToUnoTime( getObject( xEnv
)->getCreationDate( ) );
762 xRow
->appendTimestamp( rProp
, aTime
);
764 else if ( rProp
.Name
== "DateModified" )
766 util::DateTime aTime
= lcl_boostToUnoTime( getObject( xEnv
)->getLastModificationDate( ) );
767 xRow
->appendTimestamp( rProp
, aTime
);
769 else if ( rProp
.Name
== "Size" )
773 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get( ) );
774 if ( nullptr != document
)
775 xRow
->appendLong( rProp
, document
->getContentLength() );
777 xRow
->appendVoid( rProp
);
779 catch ( const libcmis::Exception
& )
781 xRow
->appendVoid( rProp
);
784 else if ( rProp
.Name
== "CreatableContentsInfo" )
786 xRow
->appendObject( rProp
, uno::Any( queryCreatableContentsInfo( xEnv
) ) );
788 else if ( rProp
.Name
== "MediaType" )
792 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get( ) );
793 if ( nullptr != document
)
794 xRow
->appendString( rProp
, STD_TO_OUSTR( document
->getContentType() ) );
796 xRow
->appendVoid( rProp
);
798 catch ( const libcmis::Exception
& )
800 xRow
->appendVoid( rProp
);
803 else if ( rProp
.Name
== "IsVolume" )
805 xRow
->appendBoolean( rProp
, false );
807 else if ( rProp
.Name
== "IsRemote" )
809 xRow
->appendBoolean( rProp
, false );
811 else if ( rProp
.Name
== "IsRemoveable" )
813 xRow
->appendBoolean( rProp
, false );
815 else if ( rProp
.Name
== "IsFloppy" )
817 xRow
->appendBoolean( rProp
, false );
819 else if ( rProp
.Name
== "IsCompactDisc" )
821 xRow
->appendBoolean( rProp
, false );
823 else if ( rProp
.Name
== "IsHidden" )
825 xRow
->appendBoolean( rProp
, false );
827 else if ( rProp
.Name
== "TargetURL" )
829 xRow
->appendString( rProp
, "" );
831 else if ( rProp
.Name
== "BaseURI" )
833 xRow
->appendString( rProp
, m_aURL
.getBindingUrl( ) );
835 else if ( rProp
.Name
== "CmisProperties" )
839 libcmis::ObjectPtr object
= getObject( xEnv
);
840 std::map
< std::string
, libcmis::PropertyPtr
>& aProperties
= object
->getProperties( );
841 uno::Sequence
< document::CmisProperty
> aCmisProperties( aProperties
.size( ) );
842 document::CmisProperty
* pCmisProps
= aCmisProperties
.getArray( );
844 for ( const auto& [sId
, rProperty
] : aProperties
)
846 auto sDisplayName
= rProperty
->getPropertyType()->getDisplayName( );
847 bool bUpdatable
= rProperty
->getPropertyType()->isUpdatable( );
848 bool bRequired
= rProperty
->getPropertyType()->isRequired( );
849 bool bMultiValued
= rProperty
->getPropertyType()->isMultiValued();
850 bool bOpenChoice
= rProperty
->getPropertyType()->isOpenChoice();
852 pCmisProps
[i
].Id
= STD_TO_OUSTR( sId
);
853 pCmisProps
[i
].Name
= STD_TO_OUSTR( sDisplayName
);
854 pCmisProps
[i
].Updatable
= bUpdatable
;
855 pCmisProps
[i
].Required
= bRequired
;
856 pCmisProps
[i
].MultiValued
= bMultiValued
;
857 pCmisProps
[i
].OpenChoice
= bOpenChoice
;
858 pCmisProps
[i
].Value
= lcl_cmisPropertyToUno( rProperty
);
859 switch ( rProperty
->getPropertyType( )->getType( ) )
862 case libcmis::PropertyType::String
:
863 pCmisProps
[i
].Type
= CMIS_TYPE_STRING
;
865 case libcmis::PropertyType::Integer
:
866 pCmisProps
[i
].Type
= CMIS_TYPE_INTEGER
;
868 case libcmis::PropertyType::Decimal
:
869 pCmisProps
[i
].Type
= CMIS_TYPE_DECIMAL
;
871 case libcmis::PropertyType::Bool
:
872 pCmisProps
[i
].Type
= CMIS_TYPE_BOOL
;
874 case libcmis::PropertyType::DateTime
:
875 pCmisProps
[i
].Type
= CMIS_TYPE_DATETIME
;
880 xRow
->appendObject( rProp
.Name
, uno::Any( aCmisProperties
) );
882 catch ( const libcmis::Exception
& )
884 xRow
->appendVoid( rProp
);
887 else if ( rProp
.Name
== "IsVersionable" )
891 libcmis::ObjectPtr object
= getObject( xEnv
);
892 bool bIsVersionable
= object
->getTypeDescription( )->isVersionable( );
893 xRow
->appendBoolean( rProp
, bIsVersionable
);
895 catch ( const libcmis::Exception
& )
897 xRow
->appendVoid( rProp
);
900 else if ( rProp
.Name
== "CanCheckOut" )
904 libcmis::ObjectPtr pObject
= getObject( xEnv
);
905 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
906 bool bAllowed
= false;
909 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckOut
);
911 xRow
->appendBoolean( rProp
, bAllowed
);
913 catch ( const libcmis::Exception
& )
915 xRow
->appendVoid( rProp
);
918 else if ( rProp
.Name
== "CanCancelCheckOut" )
922 libcmis::ObjectPtr pObject
= getObject( xEnv
);
923 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
924 bool bAllowed
= false;
927 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CancelCheckOut
);
929 xRow
->appendBoolean( rProp
, bAllowed
);
931 catch ( const libcmis::Exception
& )
933 xRow
->appendVoid( rProp
);
936 else if ( rProp
.Name
== "CanCheckIn" )
940 libcmis::ObjectPtr pObject
= getObject( xEnv
);
941 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
942 bool bAllowed
= false;
945 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckIn
);
947 xRow
->appendBoolean( rProp
, bAllowed
);
949 catch ( const libcmis::Exception
& )
951 xRow
->appendVoid( rProp
);
955 SAL_INFO( "ucb.ucp.cmis", "Looking for unsupported property " << rProp
.Name
);
957 catch (const libcmis::Exception
&)
959 xRow
->appendVoid( rProp
);
966 uno::Any
Content::open(const ucb::OpenCommandArgument2
& rOpenCommand
,
967 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
969 bool bIsFolder
= isFolder( xEnv
);
971 // Handle the case of the non-existing file
972 if ( !getObject( xEnv
) )
974 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(m_xIdentifier
->getContentIdentifier()) };
976 ucb::InteractiveAugmentedIOException(OUString(), getXWeak(),
977 task::InteractionClassification_ERROR
,
978 bIsFolder
? ucb::IOErrorCode_NOT_EXISTING_PATH
: ucb::IOErrorCode_NOT_EXISTING
, aArgs
)
981 ucbhelper::cancelCommandExecution(aErr
, xEnv
);
987 ( rOpenCommand
.Mode
== ucb::OpenMode::ALL
) ||
988 ( rOpenCommand
.Mode
== ucb::OpenMode::FOLDERS
) ||
989 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENTS
)
992 if ( bOpenFolder
&& bIsFolder
)
994 uno::Reference
< ucb::XDynamicResultSet
> xSet
995 = new DynamicResultSet(m_xContext
, this, rOpenCommand
, xEnv
);
998 else if ( rOpenCommand
.Sink
.is() )
1001 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
1002 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
)
1005 ucbhelper::cancelCommandExecution(
1006 uno::Any ( ucb::UnsupportedOpenModeException
1007 ( OUString(), getXWeak(),
1008 sal_Int16( rOpenCommand
.Mode
) ) ),
1012 if ( !feedSink( rOpenCommand
.Sink
, xEnv
) )
1014 // Note: rOpenCommand.Sink may contain an XStream
1015 // implementation. Support for this type of
1016 // sink is optional...
1017 SAL_INFO( "ucb.ucp.cmis", "Failed to copy data to sink" );
1019 ucbhelper::cancelCommandExecution(
1020 uno::Any (ucb::UnsupportedDataSinkException
1021 ( OUString(), getXWeak(),
1022 rOpenCommand
.Sink
) ),
1027 SAL_INFO( "ucb.ucp.cmis", "Open falling through ..." );
1032 OUString
Content::checkIn( const ucb::CheckinArgument
& rArg
,
1033 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1035 ucbhelper::Content
aSourceContent( rArg
.SourceURL
, xEnv
, comphelper::getProcessComponentContext( ) );
1036 uno::Reference
< io::XInputStream
> xIn
= aSourceContent
.openStream( );
1038 libcmis::ObjectPtr object
;
1041 object
= getObject( xEnv
);
1043 catch ( const libcmis::Exception
& e
)
1045 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1046 ucbhelper::cancelCommandExecution(
1047 ucb::IOErrorCode_GENERAL
,
1048 uno::Sequence
< uno::Any
>( 0 ),
1050 OUString::createFromAscii( e
.what() ) );
1053 libcmis::Document
* pPwc
= dynamic_cast< libcmis::Document
* >( object
.get( ) );
1056 ucbhelper::cancelCommandExecution(
1057 ucb::IOErrorCode_GENERAL
,
1058 uno::Sequence
< uno::Any
>( 0 ),
1060 "Checkin only supported by documents" );
1063 boost::shared_ptr
< std::ostream
> pOut( new std::ostringstream ( std::ios_base::binary
| std::ios_base::in
| std::ios_base::out
) );
1064 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1065 copyData( xIn
, xOutput
);
1067 std::map
< std::string
, libcmis::PropertyPtr
> newProperties
;
1068 libcmis::DocumentPtr pDoc
;
1072 pDoc
= pPwc
->checkIn( rArg
.MajorVersion
, OUSTR_TO_STDSTR( rArg
.VersionComment
), newProperties
,
1073 pOut
, OUSTR_TO_STDSTR( rArg
.MimeType
), OUSTR_TO_STDSTR( rArg
.NewTitle
) );
1075 catch ( const libcmis::Exception
& e
)
1077 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1078 ucbhelper::cancelCommandExecution(
1079 ucb::IOErrorCode_GENERAL
,
1080 uno::Sequence
< uno::Any
>( 0 ),
1082 OUString::createFromAscii( e
.what() ) );
1085 // Get the URL and send it back as a result
1086 URL
aCmisUrl( m_sURL
);
1087 std::vector
< std::string
> aPaths
= pDoc
->getPaths( );
1088 if ( !aPaths
.empty() )
1090 aCmisUrl
.setObjectPath(STD_TO_OUSTR(aPaths
.front()));
1094 // We may have unfiled document depending on the server, those
1095 // won't have any path, use their ID instead
1096 aCmisUrl
.setObjectId(STD_TO_OUSTR(pDoc
->getId()));
1098 return aCmisUrl
.asString( );
1101 OUString
Content::checkOut( const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1106 // Checkout the document if possible
1107 libcmis::DocumentPtr pDoc
= boost::dynamic_pointer_cast
< libcmis::Document
>( getObject( xEnv
) );
1108 if ( pDoc
.get( ) == nullptr )
1110 ucbhelper::cancelCommandExecution(
1111 ucb::IOErrorCode_GENERAL
,
1112 uno::Sequence
< uno::Any
>( 0 ),
1114 "Checkout only supported by documents" );
1116 libcmis::DocumentPtr pPwc
= pDoc
->checkOut( );
1118 // Compute the URL of the Private Working Copy (PWC)
1119 URL
aCmisUrl( m_sURL
);
1120 std::vector
< std::string
> aPaths
= pPwc
->getPaths( );
1121 if ( !aPaths
.empty() )
1123 auto sPath
= aPaths
.front( );
1124 aCmisUrl
.setObjectPath( STD_TO_OUSTR( sPath
) );
1128 // We may have unfiled PWC depending on the server, those
1129 // won't have any path, use their ID instead
1130 auto sId
= pPwc
->getId( );
1131 aCmisUrl
.setObjectId( STD_TO_OUSTR( sId
) );
1133 aRet
= aCmisUrl
.asString( );
1135 catch ( const libcmis::Exception
& e
)
1137 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1138 ucbhelper::cancelCommandExecution(
1139 ucb::IOErrorCode_GENERAL
,
1140 uno::Sequence
< uno::Any
>( 0 ),
1142 o3tl::runtimeToOUString(e
.what()));
1147 OUString
Content::cancelCheckOut( const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1152 libcmis::DocumentPtr pPwc
= boost::dynamic_pointer_cast
< libcmis::Document
>( getObject( xEnv
) );
1153 if ( pPwc
.get( ) == nullptr )
1155 ucbhelper::cancelCommandExecution(
1156 ucb::IOErrorCode_GENERAL
,
1157 uno::Sequence
< uno::Any
>( 0 ),
1159 "CancelCheckout only supported by documents" );
1161 pPwc
->cancelCheckout( );
1163 // Get the Original document (latest version)
1164 std::vector
< libcmis::DocumentPtr
> aVersions
= pPwc
->getAllVersions( );
1165 for ( const auto& rVersion
: aVersions
)
1167 libcmis::DocumentPtr pVersion
= rVersion
;
1168 std::map
< std::string
, libcmis::PropertyPtr
> aProps
= pVersion
->getProperties( );
1169 bool bIsLatestVersion
= false;
1170 std::map
< std::string
, libcmis::PropertyPtr
>::iterator propIt
= aProps
.find( std::string( "cmis:isLatestVersion" ) );
1171 if ( propIt
!= aProps
.end( ) && !propIt
->second
->getBools( ).empty( ) )
1173 bIsLatestVersion
= propIt
->second
->getBools( ).front( );
1176 if ( bIsLatestVersion
)
1178 // Compute the URL of the Document
1179 URL
aCmisUrl( m_sURL
);
1180 std::vector
< std::string
> aPaths
= pVersion
->getPaths( );
1181 if ( !aPaths
.empty() )
1183 auto sPath
= aPaths
.front( );
1184 aCmisUrl
.setObjectPath( STD_TO_OUSTR( sPath
) );
1188 // We may have unfiled doc depending on the server, those
1189 // won't have any path, use their ID instead
1190 auto sId
= pVersion
->getId( );
1191 aCmisUrl
.setObjectId( STD_TO_OUSTR( sId
) );
1193 aRet
= aCmisUrl
.asString( );
1198 catch ( const libcmis::Exception
& e
)
1200 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1201 ucbhelper::cancelCommandExecution(
1202 ucb::IOErrorCode_GENERAL
,
1203 uno::Sequence
< uno::Any
>( 0 ),
1205 o3tl::runtimeToOUString(e
.what()));
1210 uno::Sequence
< document::CmisVersion
> Content::getAllVersions( const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1215 libcmis::DocumentPtr pDoc
= boost::dynamic_pointer_cast
< libcmis::Document
>( getObject( xEnv
) );
1216 if ( pDoc
.get( ) == nullptr )
1218 ucbhelper::cancelCommandExecution(
1219 ucb::IOErrorCode_GENERAL
,
1220 uno::Sequence
< uno::Any
>( 0 ),
1222 "Can not get the document" );
1224 std::vector
< libcmis::DocumentPtr
> aCmisVersions
= pDoc
->getAllVersions( );
1225 uno::Sequence
< document::CmisVersion
> aVersions( aCmisVersions
.size( ) );
1226 auto aVersionsRange
= asNonConstRange(aVersions
);
1228 for ( const auto& rVersion
: aCmisVersions
)
1230 libcmis::DocumentPtr pVersion
= rVersion
;
1231 aVersionsRange
[i
].Id
= STD_TO_OUSTR( pVersion
->getId( ) );
1232 aVersionsRange
[i
].Author
= STD_TO_OUSTR( pVersion
->getCreatedBy( ) );
1233 aVersionsRange
[i
].TimeStamp
= lcl_boostToUnoTime( pVersion
->getLastModificationDate( ) );
1234 aVersionsRange
[i
].Comment
= STD_TO_OUSTR( pVersion
->getStringProperty("cmis:checkinComment") );
1239 catch ( const libcmis::Exception
& e
)
1241 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1242 ucbhelper::cancelCommandExecution(
1243 ucb::IOErrorCode_GENERAL
,
1244 uno::Sequence
< uno::Any
>( 0 ),
1246 o3tl::runtimeToOUString(e
.what()));
1248 return uno::Sequence
< document::CmisVersion
> ( );
1251 void Content::transfer( const ucb::TransferInfo
& rTransferInfo
,
1252 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1254 // If the source isn't on the same CMIS repository, then simply copy
1255 INetURLObject
aSourceUrl( rTransferInfo
.SourceURL
);
1256 if ( aSourceUrl
.GetProtocol() != INetProtocol::Cmis
)
1258 OUString sSrcBindingUrl
= URL( rTransferInfo
.SourceURL
).getBindingUrl( );
1259 if ( sSrcBindingUrl
!= m_aURL
.getBindingUrl( ) )
1261 ucbhelper::cancelCommandExecution(
1263 ucb::InteractiveBadTransferURLException(
1264 "Unsupported URL scheme!",
1270 SAL_INFO( "ucb.ucp.cmis", "TODO - Content::transfer()" );
1273 void Content::insert( const uno::Reference
< io::XInputStream
> & xInputStream
,
1274 bool bReplaceExisting
, std::u16string_view rMimeType
,
1275 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1277 if ( !xInputStream
.is() )
1279 ucbhelper::cancelCommandExecution( uno::Any
1280 ( ucb::MissingInputStreamException
1281 ( OUString(), getXWeak() ) ),
1285 // For transient content, the URL is the one of the parent
1286 if ( !m_bTransient
)
1291 // Try to get the object from the server if there is any
1292 libcmis::FolderPtr pFolder
;
1295 pFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>( getObject( xEnv
) );
1297 catch ( const libcmis::Exception
& )
1301 if ( pFolder
== nullptr )
1304 libcmis::ObjectPtr object
;
1305 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
1306 if ( it
== m_pObjectProps
.end( ) )
1308 ucbhelper::cancelCommandExecution( uno::Any
1309 ( uno::RuntimeException( "Missing name property",
1313 auto newName
= it
->second
->getStrings( ).front( );
1314 auto newPath
= OUSTR_TO_STDSTR( m_sObjectPath
);
1315 if ( !newPath
.empty( ) && newPath
[ newPath
.size( ) - 1 ] != '/' )
1320 if ( !m_sObjectId
.isEmpty( ) )
1321 object
= getSession( xEnv
)->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
1323 object
= getSession( xEnv
)->getObjectByPath( newPath
);
1324 sNewPath
= STD_TO_OUSTR( newPath
);
1326 catch ( const libcmis::Exception
& )
1328 // Nothing matched the path
1331 if ( nullptr != object
.get( ) )
1333 // Are the base type matching?
1334 if ( object
->getBaseType( ) != m_pObjectType
->getBaseType( )->getId() )
1336 ucbhelper::cancelCommandExecution( uno::Any
1337 ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
1342 // Update the existing object if it's a document
1343 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( object
.get( ) );
1344 if ( nullptr != document
)
1346 boost::shared_ptr
< std::ostream
> pOut( new std::ostringstream ( std::ios_base::binary
| std::ios_base::in
| std::ios_base::out
) );
1347 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1348 copyData( xInputStream
, xOutput
);
1351 document
->setContentStream( pOut
, OUSTR_TO_STDSTR( rMimeType
), std::string( ), bReplaceExisting
);
1353 catch ( const libcmis::Exception
& )
1355 ucbhelper::cancelCommandExecution( uno::Any
1356 ( uno::RuntimeException( "Error when setting document content",
1364 // We need to create a brand new object... either folder or document
1365 bool bIsFolder
= getObjectType( xEnv
)->getBaseType( )->getId( ) == "cmis:folder";
1366 setCmisProperty( "cmis:objectTypeId", getObjectType( xEnv
)->getId( ), xEnv
);
1372 pFolder
->createFolder( m_pObjectProps
);
1373 sNewPath
= STD_TO_OUSTR( newPath
);
1375 catch ( const libcmis::Exception
& )
1377 ucbhelper::cancelCommandExecution( uno::Any
1378 ( uno::RuntimeException( "Error when creating folder",
1385 boost::shared_ptr
< std::ostream
> pOut( new std::ostringstream ( std::ios_base::binary
| std::ios_base::in
| std::ios_base::out
) );
1386 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1387 copyData( xInputStream
, xOutput
);
1390 pFolder
->createDocument( m_pObjectProps
, pOut
, OUSTR_TO_STDSTR( rMimeType
), std::string() );
1391 sNewPath
= STD_TO_OUSTR( newPath
);
1393 catch ( const libcmis::Exception
& )
1395 ucbhelper::cancelCommandExecution( uno::Any
1396 ( uno::RuntimeException( "Error when creating document",
1403 if ( sNewPath
.isEmpty( ) && m_sObjectId
.isEmpty( ) )
1406 // Update the current content: it's no longer transient
1407 m_sObjectPath
= sNewPath
;
1409 aUrl
.setObjectPath( m_sObjectPath
);
1410 aUrl
.setObjectId( m_sObjectId
);
1411 m_sURL
= aUrl
.asString( );
1413 m_pObjectType
.reset( );
1414 m_pObjectProps
.clear( );
1415 m_bTransient
= false;
1419 const int TRANSFER_BUFFER_SIZE
= 65536;
1421 void Content::copyData(
1422 const uno::Reference
< io::XInputStream
>& xIn
,
1423 const uno::Reference
< io::XOutputStream
>& xOut
)
1425 uno::Sequence
< sal_Int8
> theData( TRANSFER_BUFFER_SIZE
);
1427 while ( xIn
->readBytes( theData
, TRANSFER_BUFFER_SIZE
) > 0 )
1428 xOut
->writeBytes( theData
);
1430 xOut
->closeOutput();
1433 uno::Sequence
< uno::Any
> Content::setPropertyValues(
1434 const uno::Sequence
< beans::PropertyValue
>& rValues
,
1435 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1439 // Get the already set properties if possible
1440 if ( !m_bTransient
&& getObject( xEnv
).get( ) )
1442 m_pObjectProps
.clear( );
1443 m_pObjectType
= getObject( xEnv
)->getTypeDescription();
1446 catch ( const libcmis::Exception
& e
)
1448 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1449 ucbhelper::cancelCommandExecution(
1450 ucb::IOErrorCode_GENERAL
,
1451 uno::Sequence
< uno::Any
>( 0 ),
1453 o3tl::runtimeToOUString(e
.what()));
1456 sal_Int32 nCount
= rValues
.getLength();
1457 uno::Sequence
< uno::Any
> aRet( nCount
);
1458 auto aRetRange
= asNonConstRange(aRet
);
1459 bool bChanged
= false;
1460 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
1461 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1463 const beans::PropertyValue
& rValue
= pValues
[ n
];
1464 if ( rValue
.Name
== "ContentType" ||
1465 rValue
.Name
== "MediaType" ||
1466 rValue
.Name
== "IsDocument" ||
1467 rValue
.Name
== "IsFolder" ||
1468 rValue
.Name
== "Size" ||
1469 rValue
.Name
== "CreatableContentsInfo" )
1471 lang::IllegalAccessException
e ( "Property is read-only!",
1473 aRetRange
[ n
] <<= e
;
1475 else if ( rValue
.Name
== "Title" )
1478 if (!( rValue
.Value
>>= aNewTitle
))
1480 aRetRange
[ n
] <<= beans::IllegalTypeException
1481 ( "Property value has wrong type!",
1486 if ( aNewTitle
.isEmpty() )
1488 aRetRange
[ n
] <<= lang::IllegalArgumentException
1489 ( "Empty title not allowed!",
1495 setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle
), xEnv
);
1500 SAL_INFO( "ucb.ucp.cmis", "Couldn't set property: " << rValue
.Name
);
1501 lang::IllegalAccessException
e ( "Property is read-only!",
1503 aRetRange
[ n
] <<= e
;
1509 if ( !m_bTransient
&& bChanged
)
1511 getObject( xEnv
)->updateProperties( m_pObjectProps
);
1514 catch ( const libcmis::Exception
& e
)
1516 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1517 ucbhelper::cancelCommandExecution(
1518 ucb::IOErrorCode_GENERAL
,
1519 uno::Sequence
< uno::Any
>( 0 ),
1521 o3tl::runtimeToOUString(e
.what()));
1527 bool Content::feedSink( const uno::Reference
< uno::XInterface
>& xSink
,
1528 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1533 uno::Reference
< io::XOutputStream
> xOut(xSink
, uno::UNO_QUERY
);
1534 uno::Reference
< io::XActiveDataSink
> xDataSink(xSink
, uno::UNO_QUERY
);
1535 uno::Reference
< io::XActiveDataStreamer
> xDataStreamer( xSink
, uno::UNO_QUERY
);
1537 if ( !xOut
.is() && !xDataSink
.is() && ( !xDataStreamer
.is() || !xDataStreamer
->getStream().is() ) )
1540 if ( xDataStreamer
.is() && !xOut
.is() )
1541 xOut
= xDataStreamer
->getStream()->getOutputStream();
1545 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get() );
1550 boost::shared_ptr
< std::istream
> aIn
= document
->getContentStream( );
1552 uno::Reference
< io::XInputStream
> xIn
= new StdInputStream( aIn
);
1556 if ( xDataSink
.is() )
1557 xDataSink
->setInputStream( xIn
);
1558 else if ( xOut
.is() )
1559 copyData( xIn
, xOut
);
1561 catch ( const libcmis::Exception
& e
)
1563 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1564 ucbhelper::cancelCommandExecution(
1565 ucb::IOErrorCode_GENERAL
,
1566 uno::Sequence
< uno::Any
>( 0 ),
1568 o3tl::runtimeToOUString(e
.what()));
1574 uno::Sequence
< beans::Property
> Content::getProperties(
1575 const uno::Reference
< ucb::XCommandEnvironment
> & )
1577 static const beans::Property aGenericProperties
[] =
1579 beans::Property( "IsDocument",
1580 -1, cppu::UnoType
<bool>::get(),
1581 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1582 beans::Property( "IsFolder",
1583 -1, cppu::UnoType
<bool>::get(),
1584 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1585 beans::Property( "Title",
1586 -1, cppu::UnoType
<OUString
>::get(),
1587 beans::PropertyAttribute::BOUND
),
1588 beans::Property( "ObjectId",
1589 -1, cppu::UnoType
<OUString
>::get(),
1590 beans::PropertyAttribute::BOUND
),
1591 beans::Property( "TitleOnServer",
1592 -1, cppu::UnoType
<OUString
>::get(),
1593 beans::PropertyAttribute::BOUND
),
1594 beans::Property( "IsReadOnly",
1595 -1, cppu::UnoType
<bool>::get(),
1596 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1597 beans::Property( "DateCreated",
1598 -1, cppu::UnoType
<util::DateTime
>::get(),
1599 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1600 beans::Property( "DateModified",
1601 -1, cppu::UnoType
<util::DateTime
>::get(),
1602 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1603 beans::Property( "Size",
1604 -1, cppu::UnoType
<sal_Int64
>::get(),
1605 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1606 beans::Property( "CreatableContentsInfo",
1607 -1, cppu::UnoType
<uno::Sequence
< ucb::ContentInfo
>>::get(),
1608 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1609 beans::Property( "MediaType",
1610 -1, cppu::UnoType
<OUString
>::get(),
1611 beans::PropertyAttribute::BOUND
),
1612 beans::Property( "CmisProperties",
1613 -1, cppu::UnoType
<uno::Sequence
< document::CmisProperty
>>::get(),
1614 beans::PropertyAttribute::BOUND
),
1615 beans::Property( "IsVersionable",
1616 -1, cppu::UnoType
<bool>::get(),
1617 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1618 beans::Property( "CanCheckOut",
1619 -1, cppu::UnoType
<bool>::get(),
1620 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1621 beans::Property( "CanCancelCheckOut",
1622 -1, cppu::UnoType
<bool>::get(),
1623 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1624 beans::Property( "CanCheckIn",
1625 -1, cppu::UnoType
<bool>::get(),
1626 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1629 const int nProps
= SAL_N_ELEMENTS(aGenericProperties
);
1630 return uno::Sequence
< beans::Property
> ( aGenericProperties
, nProps
);
1633 uno::Sequence
< ucb::CommandInfo
> Content::getCommands(
1634 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1636 static const ucb::CommandInfo aCommandInfoTable
[] =
1638 // Required commands
1641 -1, cppu::UnoType
<void>::get() ),
1643 ( "getPropertySetInfo",
1644 -1, cppu::UnoType
<void>::get() ),
1646 ( "getPropertyValues",
1647 -1, cppu::UnoType
<uno::Sequence
< beans::Property
>>::get() ),
1649 ( "setPropertyValues",
1650 -1, cppu::UnoType
<uno::Sequence
< beans::PropertyValue
>>::get() ),
1652 // Optional standard commands
1655 -1, cppu::UnoType
<bool>::get() ),
1658 -1, cppu::UnoType
<ucb::InsertCommandArgument2
>::get() ),
1661 -1, cppu::UnoType
<ucb::OpenCommandArgument2
>::get() ),
1663 // Mandatory CMIS-only commands
1664 ucb::CommandInfo ( "checkout", -1, cppu::UnoType
<void>::get() ),
1665 ucb::CommandInfo ( "cancelCheckout", -1, cppu::UnoType
<void>::get() ),
1666 ucb::CommandInfo ( "checkIn", -1,
1667 cppu::UnoType
<ucb::TransferInfo
>::get() ),
1668 ucb::CommandInfo ( "updateProperties", -1, cppu::UnoType
<void>::get() ),
1671 -1, cppu::UnoType
<uno::Sequence
< document::CmisVersion
>>::get() ),
1674 // Folder Only, omitted if not a folder
1677 -1, cppu::UnoType
<ucb::TransferInfo
>::get() ),
1679 ( "createNewContent",
1680 -1, cppu::UnoType
<ucb::ContentInfo
>::get() )
1683 const int nProps
= SAL_N_ELEMENTS( aCommandInfoTable
);
1684 return uno::Sequence
< ucb::CommandInfo
>(aCommandInfoTable
, isFolder( xEnv
) ? nProps
: nProps
- 2);
1687 OUString
Content::getParentURL( )
1689 SAL_INFO( "ucb.ucp.cmis", "Content::getParentURL()" );
1690 OUString parentUrl
= "/";
1691 if ( m_sObjectPath
== "/" )
1695 INetURLObject
aUrl( m_sURL
);
1696 if ( aUrl
.getSegmentCount( ) > 0 )
1698 URL
aCmisUrl( m_sURL
);
1699 aUrl
.removeSegment( );
1700 aCmisUrl
.setObjectPath( aUrl
.GetURLPath( INetURLObject::DecodeMechanism::WithCharset
) );
1701 parentUrl
= aCmisUrl
.asString( );
1707 XTYPEPROVIDER_COMMON_IMPL( Content
);
1709 void SAL_CALL
Content::acquire() noexcept
1711 ContentImplHelper::acquire();
1714 void SAL_CALL
Content::release() noexcept
1716 ContentImplHelper::release();
1719 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
1721 uno::Any aRet
= cppu::queryInterface( rType
, static_cast< ucb::XContentCreator
* >( this ) );
1722 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface(rType
);
1725 OUString SAL_CALL
Content::getImplementationName()
1727 return "com.sun.star.comp.CmisContent";
1730 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
1732 uno::Sequence
<OUString
> aSNS
{ "com.sun.star.ucb.CmisContent" };
1736 OUString SAL_CALL
Content::getContentType()
1741 if (isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ))
1742 sRet
= CMIS_FOLDER_TYPE
;
1744 sRet
= CMIS_FILE_TYPE
;
1746 catch (const uno::RuntimeException
&)
1750 catch (const uno::Exception
& e
)
1752 uno::Any
a(cppu::getCaughtException());
1753 throw lang::WrappedTargetRuntimeException(
1754 "wrapped Exception " + e
.Message
,
1755 uno::Reference
<uno::XInterface
>(), a
);
1760 uno::Any SAL_CALL
Content::execute(
1761 const ucb::Command
& aCommand
,
1762 sal_Int32
/*CommandId*/,
1763 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1765 SAL_INFO( "ucb.ucp.cmis", "Content::execute( ) - " << aCommand
.Name
);
1768 if ( aCommand
.Name
== "getPropertyValues" )
1770 uno::Sequence
< beans::Property
> Properties
;
1771 if ( !( aCommand
.Argument
>>= Properties
) )
1772 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1773 aRet
<<= getPropertyValues( Properties
, xEnv
);
1775 else if ( aCommand
.Name
== "getPropertySetInfo" )
1776 aRet
<<= getPropertySetInfo( xEnv
, false );
1777 else if ( aCommand
.Name
== "getCommandInfo" )
1778 aRet
<<= getCommandInfo( xEnv
, false );
1779 else if ( aCommand
.Name
== "open" )
1781 ucb::OpenCommandArgument2 aOpenCommand
;
1782 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
1783 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1784 aRet
= open( aOpenCommand
, xEnv
);
1786 else if ( aCommand
.Name
== "transfer" )
1788 ucb::TransferInfo transferArgs
;
1789 if ( !( aCommand
.Argument
>>= transferArgs
) )
1790 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1791 transfer( transferArgs
, xEnv
);
1793 else if ( aCommand
.Name
== "setPropertyValues" )
1795 uno::Sequence
< beans::PropertyValue
> aProperties
;
1796 if ( !( aCommand
.Argument
>>= aProperties
) || !aProperties
.hasElements() )
1797 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1798 aRet
<<= setPropertyValues( aProperties
, xEnv
);
1800 else if (aCommand
.Name
== "createNewContent"
1801 && isFolder( xEnv
) )
1803 ucb::ContentInfo arg
;
1804 if ( !( aCommand
.Argument
>>= arg
) )
1805 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1806 aRet
<<= createNewContent( arg
);
1808 else if ( aCommand
.Name
== "insert" )
1810 ucb::InsertCommandArgument2 arg
;
1811 if ( !( aCommand
.Argument
>>= arg
) )
1813 ucb::InsertCommandArgument insertArg
;
1814 if ( !( aCommand
.Argument
>>= insertArg
) )
1815 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1817 arg
.Data
= insertArg
.Data
;
1818 arg
.ReplaceExisting
= insertArg
.ReplaceExisting
;
1820 // store the document id
1821 m_sObjectId
= arg
.DocumentId
;
1822 insert( arg
.Data
, arg
.ReplaceExisting
, arg
.MimeType
, xEnv
);
1824 else if ( aCommand
.Name
== "delete" )
1828 if ( !isFolder( xEnv
) )
1830 getObject( xEnv
)->remove( );
1834 libcmis::Folder
* folder
= dynamic_cast< libcmis::Folder
* >( getObject( xEnv
).get() );
1836 folder
->removeTree( );
1839 catch ( const libcmis::Exception
& e
)
1841 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1842 ucbhelper::cancelCommandExecution(
1843 ucb::IOErrorCode_GENERAL
,
1844 uno::Sequence
< uno::Any
>( 0 ),
1846 o3tl::runtimeToOUString(e
.what()));
1849 else if ( aCommand
.Name
== "checkout" )
1851 aRet
<<= checkOut( xEnv
);
1853 else if ( aCommand
.Name
== "cancelCheckout" )
1855 aRet
<<= cancelCheckOut( xEnv
);
1857 else if ( aCommand
.Name
== "checkin" )
1859 ucb::CheckinArgument aArg
;
1860 if ( !( aCommand
.Argument
>>= aArg
) )
1862 ucbhelper::cancelCommandExecution ( getBadArgExcept(), xEnv
);
1864 aRet
<<= checkIn( aArg
, xEnv
);
1866 else if ( aCommand
.Name
== "getAllVersions" )
1868 aRet
<<= getAllVersions( xEnv
);
1870 else if ( aCommand
.Name
== "updateProperties" )
1872 updateProperties( aCommand
.Argument
, xEnv
);
1876 SAL_INFO( "ucb.ucp.cmis", "Unknown command to execute" );
1878 ucbhelper::cancelCommandExecution
1879 ( uno::Any( ucb::UnsupportedCommandException
1888 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
1890 SAL_INFO( "ucb.ucp.cmis", "TODO - Content::abort()" );
1891 // TODO Implement me
1894 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
Content::queryCreatableContentsInfo()
1896 return queryCreatableContentsInfo( uno::Reference
< ucb::XCommandEnvironment
>() );
1899 uno::Reference
< ucb::XContent
> SAL_CALL
Content::createNewContent(
1900 const ucb::ContentInfo
& Info
)
1902 bool create_document
;
1904 if ( Info
.Type
== CMIS_FILE_TYPE
)
1905 create_document
= true;
1906 else if ( Info
.Type
== CMIS_FOLDER_TYPE
)
1907 create_document
= false;
1910 SAL_INFO( "ucb.ucp.cmis", "Unknown type of content to create" );
1911 return uno::Reference
< ucb::XContent
>();
1914 OUString sParentURL
= m_xIdentifier
->getContentIdentifier();
1916 // Set the parent URL for the transient objects
1917 uno::Reference
< ucb::XContentIdentifier
> xId(new ::ucbhelper::ContentIdentifier(sParentURL
));
1921 return new ::cmis::Content( m_xContext
, m_pProvider
, xId
, !create_document
);
1923 catch ( ucb::ContentCreationException
& )
1925 return uno::Reference
< ucb::XContent
>();
1929 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
1933 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
1935 static cppu::OTypeCollection s_aFolderCollection
1936 (CPPU_TYPE_REF( lang::XTypeProvider
),
1937 CPPU_TYPE_REF( lang::XServiceInfo
),
1938 CPPU_TYPE_REF( lang::XComponent
),
1939 CPPU_TYPE_REF( ucb::XContent
),
1940 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1941 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1942 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1943 CPPU_TYPE_REF( beans::XPropertyContainer
),
1944 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1945 CPPU_TYPE_REF( container::XChild
),
1946 CPPU_TYPE_REF( ucb::XContentCreator
) );
1947 return s_aFolderCollection
.getTypes();
1950 catch (const uno::RuntimeException
&)
1954 catch (const uno::Exception
& e
)
1956 uno::Any
a(cppu::getCaughtException());
1957 throw lang::WrappedTargetRuntimeException(
1958 "wrapped Exception " + e
.Message
,
1959 uno::Reference
<uno::XInterface
>(), a
);
1962 static cppu::OTypeCollection s_aFileCollection
1963 (CPPU_TYPE_REF( lang::XTypeProvider
),
1964 CPPU_TYPE_REF( lang::XServiceInfo
),
1965 CPPU_TYPE_REF( lang::XComponent
),
1966 CPPU_TYPE_REF( ucb::XContent
),
1967 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1968 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1969 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1970 CPPU_TYPE_REF( beans::XPropertyContainer
),
1971 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1972 CPPU_TYPE_REF( container::XChild
) );
1974 return s_aFileCollection
.getTypes();
1977 uno::Sequence
< ucb::ContentInfo
> Content::queryCreatableContentsInfo(
1978 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1982 if ( isFolder( xEnv
) )
1985 // Minimum set of props we really need
1986 uno::Sequence
< beans::Property
> props
1991 cppu::UnoType
<OUString
>::get(),
1992 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
2000 ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
|
2001 ucb::ContentInfoAttribute::KIND_DOCUMENT
),
2006 ucb::ContentInfoAttribute::KIND_FOLDER
,
2012 catch (const uno::RuntimeException
&)
2016 catch (const uno::Exception
& e
)
2018 uno::Any
a(cppu::getCaughtException());
2019 throw lang::WrappedTargetRuntimeException(
2020 "wrapped Exception " + e
.Message
,
2021 uno::Reference
<uno::XInterface
>(), a
);
2026 std::vector
< uno::Reference
< ucb::XContent
> > Content::getChildren( )
2028 std::vector
< uno::Reference
< ucb::XContent
> > results
;
2029 SAL_INFO( "ucb.ucp.cmis", "Content::getChildren() " << m_sURL
);
2031 libcmis::FolderPtr pFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>( getObject( uno::Reference
< ucb::XCommandEnvironment
>() ) );
2032 if ( nullptr != pFolder
)
2034 // Get the children from pObject
2037 std::vector
< libcmis::ObjectPtr
> children
= pFolder
->getChildren( );
2039 // Loop over the results
2040 for ( const auto& rChild
: children
)
2042 // TODO Cache the objects
2044 INetURLObject
aURL( m_sURL
);
2045 OUString sUser
= aURL
.GetUser( INetURLObject::DecodeMechanism::WithCharset
);
2048 OUString
sPath( m_sObjectPath
);
2049 if ( !sPath
.endsWith("/") )
2051 sPath
+= STD_TO_OUSTR( rChild
->getName( ) );
2052 OUString sId
= STD_TO_OUSTR( rChild
->getId( ) );
2054 aUrl
.setObjectId( sId
);
2055 aUrl
.setObjectPath( sPath
);
2056 aUrl
.setUsername( sUser
);
2058 uno::Reference
< ucb::XContentIdentifier
> xId
= new ucbhelper::ContentIdentifier( aUrl
.asString( ) );
2059 uno::Reference
< ucb::XContent
> xContent
= new Content( m_xContext
, m_pProvider
, xId
, rChild
);
2061 results
.push_back( xContent
);
2064 catch ( const libcmis::Exception
& e
)
2066 SAL_INFO( "ucb.ucp.cmis", "Exception thrown: " << e
.what() );
2073 void Content::setCmisProperty(const std::string
& rName
, const std::string
& rValue
, const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
2075 if ( !getObjectType( xEnv
).get( ) )
2078 std::map
< std::string
, libcmis::PropertyPtr
>::iterator propIt
= m_pObjectProps
.find(rName
);
2080 if ( propIt
== m_pObjectProps
.end( ) && getObjectType( xEnv
).get( ) )
2082 std::map
< std::string
, libcmis::PropertyTypePtr
> propsTypes
= getObjectType( xEnv
)->getPropertiesTypes( );
2083 std::map
< std::string
, libcmis::PropertyTypePtr
>::iterator typeIt
= propsTypes
.find(rName
);
2085 if ( typeIt
!= propsTypes
.end( ) )
2087 libcmis::PropertyTypePtr propType
= typeIt
->second
;
2088 libcmis::PropertyPtr
property( new libcmis::Property( propType
, { rValue
}) );
2089 m_pObjectProps
.insert(std::pair
< std::string
, libcmis::PropertyPtr
>(rName
, property
));
2092 else if ( propIt
!= m_pObjectProps
.end( ) )
2094 propIt
->second
->setValues( { rValue
} );
2099 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */