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/.
11 #include <string_view>
13 #include <boost/make_shared.hpp>
15 #include <com/sun/star/beans/IllegalTypeException.hpp>
16 #include <com/sun/star/beans/PropertyAttribute.hpp>
17 #include <com/sun/star/beans/PropertyValue.hpp>
18 #include <com/sun/star/beans/XPropertySetInfo.hpp>
19 #include <com/sun/star/document/CmisProperty.hpp>
20 #include <com/sun/star/io/XActiveDataSink.hpp>
21 #include <com/sun/star/io/XActiveDataStreamer.hpp>
22 #include <com/sun/star/lang/IllegalAccessException.hpp>
23 #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
25 #include <com/sun/star/task/InteractionClassification.hpp>
26 #include <com/sun/star/ucb/ContentInfo.hpp>
27 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
28 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
29 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
30 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
31 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
32 #include <com/sun/star/ucb/OpenMode.hpp>
33 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
34 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
35 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
36 #include <com/sun/star/ucb/XCommandInfo.hpp>
37 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
39 #include <com/sun/star/xml/crypto/XDigestContext.hpp>
40 #include <com/sun/star/xml/crypto/DigestID.hpp>
41 #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
44 #include <comphelper/processfactory.hxx>
45 #include <comphelper/sequence.hxx>
46 #include <cppuhelper/exc_hlp.hxx>
47 #include <cppuhelper/queryinterface.hxx>
48 #include <config_oauth2.h>
49 #include <o3tl/runtimetooustring.hxx>
50 #include <sal/log.hxx>
51 #include <tools/urlobj.hxx>
52 #include <tools/long.hxx>
53 #include <ucbhelper/cancelcommandexecution.hxx>
54 #include <ucbhelper/content.hxx>
55 #include <ucbhelper/contentidentifier.hxx>
56 #include <ucbhelper/propertyvalueset.hxx>
57 #include <ucbhelper/proxydecider.hxx>
58 #include <ucbhelper/macros.hxx>
59 #include <sax/tools/converter.hxx>
61 #include "auth_provider.hxx"
62 #include "certvalidation_handler.hxx"
63 #include "cmis_content.hxx"
64 #include "cmis_provider.hxx"
65 #include "cmis_resultset.hxx"
66 #include "cmis_strings.hxx"
67 #include "std_inputstream.hxx"
68 #include "std_outputstream.hxx"
70 #define OUSTR_TO_STDSTR(s) std::string( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() )
71 #define STD_TO_OUSTR( str ) OUString( str.c_str(), str.length( ), RTL_TEXTENCODING_UTF8 )
73 using namespace com::sun::star
;
77 util::DateTime
lcl_boostToUnoTime(const boost::posix_time::ptime
& boostTime
)
79 util::DateTime unoTime
;
80 unoTime
.Year
= boostTime
.date().year();
81 unoTime
.Month
= boostTime
.date().month();
82 unoTime
.Day
= boostTime
.date().day();
83 unoTime
.Hours
= boostTime
.time_of_day().hours();
84 unoTime
.Minutes
= boostTime
.time_of_day().minutes();
85 unoTime
.Seconds
= boostTime
.time_of_day().seconds();
87 // TODO FIXME maybe we should compile with BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
88 // to actually get nanosecond precision in boostTime?
89 // use this way rather than total_nanos to avoid overflows with 32-bit long
90 const tools::Long ticks
= boostTime
.time_of_day().fractional_seconds();
91 tools::Long nanoSeconds
= ticks
* ( 1000000000 / boost::posix_time::time_duration::ticks_per_second());
93 unoTime
.NanoSeconds
= nanoSeconds
;
98 uno::Any
lcl_cmisPropertyToUno( const libcmis::PropertyPtr
& pProperty
)
101 switch ( pProperty
->getPropertyType( )->getType( ) )
104 case libcmis::PropertyType::String
:
106 auto aCmisStrings
= pProperty
->getStrings( );
107 uno::Sequence
< OUString
> aStrings( aCmisStrings
.size( ) );
108 OUString
* aStringsArr
= aStrings
.getArray( );
110 for ( const auto& rCmisStr
: aCmisStrings
)
112 aStringsArr
[i
++] = STD_TO_OUSTR( rCmisStr
);
117 case libcmis::PropertyType::Integer
:
119 auto aCmisLongs
= pProperty
->getLongs( );
120 uno::Sequence
< sal_Int64
> aLongs( aCmisLongs
.size( ) );
121 sal_Int64
* aLongsArr
= aLongs
.getArray( );
123 for ( const auto& rCmisLong
: aCmisLongs
)
125 aLongsArr
[i
++] = rCmisLong
;
130 case libcmis::PropertyType::Decimal
:
132 auto aCmisDoubles
= pProperty
->getDoubles( );
133 uno::Sequence
< double > aDoubles
= comphelper::containerToSequence(aCmisDoubles
);
137 case libcmis::PropertyType::Bool
:
139 auto aCmisBools
= pProperty
->getBools( );
140 uno::Sequence
< sal_Bool
> aBools( aCmisBools
.size( ) );
141 sal_Bool
* aBoolsArr
= aBools
.getArray( );
143 for ( bool bCmisBool
: aCmisBools
)
145 aBoolsArr
[i
++] = bCmisBool
;
150 case libcmis::PropertyType::DateTime
:
152 auto aCmisTimes
= pProperty
->getDateTimes( );
153 uno::Sequence
< util::DateTime
> aTimes( aCmisTimes
.size( ) );
154 util::DateTime
* aTimesArr
= aTimes
.getArray( );
156 for ( const auto& rCmisTime
: aCmisTimes
)
158 aTimesArr
[i
++] = lcl_boostToUnoTime( rCmisTime
);
167 libcmis::PropertyPtr
lcl_unoToCmisProperty(const document::CmisProperty
& prop
)
169 libcmis::PropertyTypePtr
propertyType( new libcmis::PropertyType( ) );
171 OUString id
= prop
.Id
;
172 OUString name
= prop
.Name
;
173 bool bUpdatable
= prop
.Updatable
;
174 bool bRequired
= prop
.Required
;
175 bool bMultiValued
= prop
.MultiValued
;
176 bool bOpenChoice
= prop
.OpenChoice
;
177 uno::Any value
= prop
.Value
;
178 std::vector
< std::string
> values
;
180 libcmis::PropertyType::Type type
= libcmis::PropertyType::String
;
181 if ( prop
.Type
== CMIS_TYPE_STRING
)
183 uno::Sequence
< OUString
> seqValue
;
185 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
186 [](const OUString
& rValue
) -> std::string
{ return OUSTR_TO_STDSTR( rValue
); });
187 type
= libcmis::PropertyType::String
;
189 else if ( prop
.Type
== CMIS_TYPE_BOOL
)
191 uno::Sequence
< sal_Bool
> seqValue
;
193 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
194 [](const bool nValue
) -> std::string
{ return OUSTR_TO_STDSTR( OUString::boolean( nValue
) ); });
195 type
= libcmis::PropertyType::Bool
;
197 else if ( prop
.Type
== CMIS_TYPE_INTEGER
)
199 uno::Sequence
< sal_Int64
> seqValue
;
201 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
202 [](const sal_Int64 nValue
) -> std::string
{ return OUSTR_TO_STDSTR( OUString::number( nValue
) ); });
203 type
= libcmis::PropertyType::Integer
;
205 else if ( prop
.Type
== CMIS_TYPE_DECIMAL
)
207 uno::Sequence
< double > seqValue
;
209 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
210 [](const double fValue
) -> std::string
{ return OUSTR_TO_STDSTR( OUString::number( fValue
) ); });
211 type
= libcmis::PropertyType::Decimal
;
213 else if ( prop
.Type
== CMIS_TYPE_DATETIME
)
215 uno::Sequence
< util::DateTime
> seqValue
;
217 std::transform(std::cbegin(seqValue
), std::cend(seqValue
), std::back_inserter(values
),
218 [](const util::DateTime
& rValue
) -> std::string
{
219 OUStringBuffer aBuffer
;
220 ::sax::Converter::convertDateTime( aBuffer
, rValue
, nullptr );
221 return OUSTR_TO_STDSTR( aBuffer
.makeStringAndClear( ) );
223 type
= libcmis::PropertyType::DateTime
;
226 propertyType
->setId( OUSTR_TO_STDSTR( id
));
227 propertyType
->setDisplayName( OUSTR_TO_STDSTR( name
) );
228 propertyType
->setUpdatable( bUpdatable
);
229 propertyType
->setRequired( bRequired
);
230 propertyType
->setMultiValued( bMultiValued
);
231 propertyType
->setOpenChoice( bOpenChoice
);
232 propertyType
->setType( type
);
234 libcmis::PropertyPtr
property( new libcmis::Property( propertyType
, values
) );
239 uno::Sequence
< uno::Any
> generateErrorArguments( const cmis::URL
& rURL
)
241 uno::Sequence
< uno::Any
> aArguments
{ uno::Any(beans::PropertyValue(
244 uno::makeAny( rURL
.getBindingUrl() ),
245 beans::PropertyState_DIRECT_VALUE
)),
246 uno::Any(beans::PropertyValue(
249 uno::makeAny( rURL
.getUsername() ),
250 beans::PropertyState_DIRECT_VALUE
)),
251 uno::Any(beans::PropertyValue(
254 uno::makeAny( rURL
.getRepositoryId() ),
255 beans::PropertyState_DIRECT_VALUE
)) };
263 Content::Content( const uno::Reference
< uno::XComponentContext
>& rxContext
,
264 ContentProvider
*pProvider
, const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
265 libcmis::ObjectPtr
const & pObject
)
266 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
267 m_pProvider( pProvider
),
268 m_pSession( nullptr ),
269 m_pObject( pObject
),
270 m_sURL( Identifier
->getContentIdentifier( ) ),
271 m_aURL( Identifier
->getContentIdentifier( ) ),
272 m_bTransient( false ),
275 SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL
);
277 m_sObjectPath
= m_aURL
.getObjectPath( );
278 m_sObjectId
= m_aURL
.getObjectId( );
281 Content::Content( const uno::Reference
< uno::XComponentContext
>& rxContext
, ContentProvider
*pProvider
,
282 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
284 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
285 m_pProvider( pProvider
),
286 m_pSession( nullptr ),
287 m_sURL( Identifier
->getContentIdentifier( ) ),
288 m_aURL( Identifier
->getContentIdentifier( ) ),
289 m_bTransient( true ),
290 m_bIsFolder( bIsFolder
)
292 SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL
);
294 m_sObjectPath
= m_aURL
.getObjectPath( );
295 m_sObjectId
= m_aURL
.getObjectId( );
302 libcmis::Session
* Content::getSession( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
304 // Set the proxy if needed. We are doing that all times as the proxy data shouldn't be cached.
305 ucbhelper::InternetProxyDecider
aProxyDecider( m_xContext
);
306 INetURLObject
aBindingUrl( m_aURL
.getBindingUrl( ) );
307 const ucbhelper::InternetProxyServer
& rProxy
= aProxyDecider
.getProxy(
308 INetURLObject::GetScheme( aBindingUrl
.GetProtocol( ) ), aBindingUrl
.GetHost(), aBindingUrl
.GetPort() );
309 OUString sProxy
= rProxy
.aName
;
310 if ( rProxy
.nPort
> 0 )
311 sProxy
+= ":" + OUString::number( rProxy
.nPort
);
312 libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy
), std::string(), std::string(), std::string() );
314 // Look for a cached session, key is binding url + repo id
315 OUString sSessionId
= m_aURL
.getBindingUrl( ) + m_aURL
.getRepositoryId( );
316 if ( nullptr == m_pSession
)
317 m_pSession
= m_pProvider
->getSession( sSessionId
, m_aURL
.getUsername( ) );
319 if ( nullptr == m_pSession
)
322 // Initialize NSS library to make sure libcmis (and curl) can access CACERTs using NSS
323 // when using internal libcurl.
324 uno::Reference
< css::xml::crypto::XNSSInitializer
>
325 xNSSInitializer
= css::xml::crypto::NSSInitializer::create( m_xContext
);
327 uno::Reference
< css::xml::crypto::XDigestContext
> xDigestContext(
328 xNSSInitializer
->getDigestContext( css::xml::crypto::DigestID::SHA256
,
329 uno::Sequence
< beans::NamedValue
>() ),
330 uno::UNO_SET_THROW
);
333 // Set the SSL Validation handler
334 libcmis::CertValidationHandlerPtr
certHandler(
335 new CertValidationHandler( xEnv
, m_xContext
, aBindingUrl
.GetHost( ) ) );
336 libcmis::SessionFactory::setCertificateValidationHandler( certHandler
);
338 // Get the auth credentials
339 AuthProvider
aAuthProvider(xEnv
, m_xIdentifier
->getContentIdentifier(), m_aURL
.getBindingUrl());
340 AuthProvider::setXEnv( xEnv
);
342 auto rUsername
= OUSTR_TO_STDSTR( m_aURL
.getUsername( ) );
343 auto rPassword
= OUSTR_TO_STDSTR( m_aURL
.getPassword( ) );
345 bool bSkipInitialPWAuth
= false;
346 if (m_aURL
.getBindingUrl() == ONEDRIVE_BASE_URL
347 || m_aURL
.getBindingUrl() == GDRIVE_BASE_URL
)
349 // skip the initial username and pw-auth prompt, the only supported method is the
350 // auth-code-fallback one (login with your browser, copy code into the dialog)
351 // TODO: if LO were to listen on localhost for the request, it would be much nicer
353 bSkipInitialPWAuth
= true;
354 rPassword
= aAuthProvider
.getRefreshToken(rUsername
);
357 bool bIsDone
= false;
361 if (bSkipInitialPWAuth
|| aAuthProvider
.authenticationQuery(rUsername
, rPassword
))
363 // Initiate a CMIS session and register it as we found nothing
364 libcmis::OAuth2DataPtr oauth2Data
;
365 if ( m_aURL
.getBindingUrl( ) == GDRIVE_BASE_URL
)
367 // reset the skip, so user gets a chance to cancel
368 bSkipInitialPWAuth
= false;
369 libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback
);
370 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
371 GDRIVE_AUTH_URL
, GDRIVE_TOKEN_URL
,
372 GDRIVE_SCOPE
, GDRIVE_REDIRECT_URI
,
373 GDRIVE_CLIENT_ID
, GDRIVE_CLIENT_SECRET
);
375 if ( m_aURL
.getBindingUrl().startsWith( ALFRESCO_CLOUD_BASE_URL
) )
376 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
377 ALFRESCO_CLOUD_AUTH_URL
, ALFRESCO_CLOUD_TOKEN_URL
,
378 ALFRESCO_CLOUD_SCOPE
, ALFRESCO_CLOUD_REDIRECT_URI
,
379 ALFRESCO_CLOUD_CLIENT_ID
, ALFRESCO_CLOUD_CLIENT_SECRET
);
380 if ( m_aURL
.getBindingUrl( ) == ONEDRIVE_BASE_URL
)
382 // reset the skip, so user gets a chance to cancel
383 bSkipInitialPWAuth
= false;
384 libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback
);
385 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
386 ONEDRIVE_AUTH_URL
, ONEDRIVE_TOKEN_URL
,
387 ONEDRIVE_SCOPE
, ONEDRIVE_REDIRECT_URI
,
388 ONEDRIVE_CLIENT_ID
, ONEDRIVE_CLIENT_SECRET
);
392 m_pSession
= libcmis::SessionFactory::createSession(
393 OUSTR_TO_STDSTR( m_aURL
.getBindingUrl( ) ),
394 rUsername
, rPassword
, OUSTR_TO_STDSTR( m_aURL
.getRepositoryId( ) ), false, oauth2Data
);
396 if ( m_pSession
== nullptr )
398 // Fail: session was not created
399 ucbhelper::cancelCommandExecution(
400 ucb::IOErrorCode_INVALID_DEVICE
,
401 generateErrorArguments(m_aURL
),
404 else if ( m_pSession
->getRepository() == nullptr )
406 // Fail: no repository or repository is invalid
407 ucbhelper::cancelCommandExecution(
408 ucb::IOErrorCode_INVALID_DEVICE
,
409 generateErrorArguments(m_aURL
),
411 "error accessing a repository");
415 m_pProvider
->registerSession(sSessionId
, m_aURL
.getUsername( ), m_pSession
);
416 if (m_aURL
.getBindingUrl() == ONEDRIVE_BASE_URL
417 || m_aURL
.getBindingUrl() == GDRIVE_BASE_URL
)
419 aAuthProvider
.storeRefreshToken(rUsername
, rPassword
,
420 m_pSession
->getRefreshToken());
426 catch( const libcmis::Exception
& e
)
428 if ( e
.getType() != "permissionDenied" )
430 SAL_INFO("ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what());
437 // Silently fail as the user cancelled the authentication
438 ucbhelper::cancelCommandExecution(
439 ucb::IOErrorCode_ABORT
,
440 uno::Sequence
< uno::Any
>( 0 ),
442 throw uno::RuntimeException( );
449 libcmis::ObjectTypePtr
const & Content::getObjectType( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
451 if ( nullptr == m_pObjectType
.get( ) && m_bTransient
)
453 std::string typeId
= m_bIsFolder
? "cmis:folder" : "cmis:document";
454 // The type to create needs to be fetched from the possible children types
455 // defined in the parent folder. Then, we'll pick up the first one we find matching
456 // cmis:folder or cmis:document (depending what we need to create).
457 // The easy case will work in most cases, but not on some servers (like Lotus Live)
458 libcmis::Folder
* pParent
= nullptr;
459 bool bTypeRestricted
= false;
462 pParent
= dynamic_cast< libcmis::Folder
* >( getObject( xEnv
).get( ) );
464 catch ( const libcmis::Exception
& )
470 std::map
< std::string
, libcmis::PropertyPtr
>& aProperties
= pParent
->getProperties( );
471 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= aProperties
.find( "cmis:allowedChildObjectTypeIds" );
472 if ( it
!= aProperties
.end( ) )
474 libcmis::PropertyPtr pProperty
= it
->second
;
477 std::vector
< std::string
> typesIds
= pProperty
->getStrings( );
478 for ( const auto& rType
: typesIds
)
480 bTypeRestricted
= true;
481 libcmis::ObjectTypePtr type
= getSession( xEnv
)->getType( rType
);
483 // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis
484 if ( type
->getBaseType( )->getId( ) == typeId
)
486 m_pObjectType
= type
;
494 if ( !bTypeRestricted
)
495 m_pObjectType
= getSession( xEnv
)->getType( typeId
);
497 return m_pObjectType
;
501 libcmis::ObjectPtr
const & Content::getObject( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
503 // can't get the session for some reason
504 // the recent file opening at start up is an example.
507 if ( !getSession( xEnv
) )
510 catch ( uno::RuntimeException
& )
514 if ( !m_pObject
.get() )
516 if ( !m_sObjectId
.isEmpty( ) )
520 m_pObject
= getSession( xEnv
)->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
522 catch ( const libcmis::Exception
& )
524 SAL_INFO( "ucb.ucp.cmis", "object: " << OUSTR_TO_STDSTR(m_sObjectId
));
525 throw libcmis::Exception( "Object not found" );
528 else if (!(m_sObjectPath
.isEmpty() || m_sObjectPath
== "/"))
532 m_pObject
= getSession( xEnv
)->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath
) );
534 catch ( const libcmis::Exception
& )
536 // In some cases, getting the object from the path doesn't work,
537 // but getting the parent from its path and the get the child in the list is OK.
538 // It's weird, but needed to handle case where the path isn't the folders/files
539 // names separated by '/' (as in Lotus Live)
540 INetURLObject
aParentUrl( m_sURL
);
541 std::string sName
= OUSTR_TO_STDSTR( aParentUrl
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
) );
542 aParentUrl
.removeSegment( );
543 OUString sParentUrl
= aParentUrl
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
544 // Avoid infinite recursion if sParentUrl == m_sURL
545 if (sParentUrl
!= m_sURL
)
547 rtl::Reference
<Content
> xParent(new Content(m_xContext
, m_pProvider
, new ucbhelper::ContentIdentifier(sParentUrl
)));
548 libcmis::FolderPtr pParentFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>(xParent
->getObject(xEnv
));
551 std::vector
< libcmis::ObjectPtr
> children
= pParentFolder
->getChildren();
552 auto it
= std::find_if(children
.begin(), children
.end(),
553 [&sName
](const libcmis::ObjectPtr
& rChild
) { return rChild
->getName() == sName
; });
554 if (it
!= children
.end())
560 throw libcmis::Exception( "Object not found" );
565 m_pObject
= getSession( xEnv
)->getRootFolder( );
567 m_sObjectId
= OUString( );
574 bool Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
576 bool bIsFolder
= false;
579 libcmis::ObjectPtr obj
= getObject( xEnv
);
581 bIsFolder
= obj
->getBaseType( ) == "cmis:folder";
583 catch ( const libcmis::Exception
& e
)
585 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
587 ucbhelper::cancelCommandExecution(
588 ucb::IOErrorCode_GENERAL
,
589 uno::Sequence
< uno::Any
>( 0 ),
591 OUString::createFromAscii( e
.what( ) ) );
597 uno::Any
Content::getBadArgExcept()
599 return uno::makeAny( lang::IllegalArgumentException(
600 "Wrong argument type!",
601 static_cast< cppu::OWeakObject
* >( this ), -1) );
604 libcmis::ObjectPtr
Content::updateProperties(
605 const uno::Any
& iCmisProps
,
606 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
608 // Convert iCmisProps to Cmis Properties;
609 uno::Sequence
< document::CmisProperty
> aPropsSeq
;
610 iCmisProps
>>= aPropsSeq
;
611 std::map
< std::string
, libcmis::PropertyPtr
> aProperties
;
613 for ( const auto& rProp
: std::as_const(aPropsSeq
) )
615 std::string id
= OUSTR_TO_STDSTR( rProp
.Id
);
616 libcmis::PropertyPtr prop
= lcl_unoToCmisProperty( rProp
);
617 aProperties
.insert( std::pair
<std::string
, libcmis::PropertyPtr
>( id
, prop
) );
619 libcmis::ObjectPtr updateObj
;
622 updateObj
= getObject( xEnv
)->updateProperties( aProperties
);
624 catch ( const libcmis::Exception
& e
)
626 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: "<< e
.what( ) );
632 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
633 const uno::Sequence
< beans::Property
>& rProperties
,
634 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
636 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
= new ::ucbhelper::PropertyValueSet( m_xContext
);
638 for( const beans::Property
& rProp
: rProperties
)
642 if ( rProp
.Name
== "IsDocument" )
646 libcmis::ObjectPtr obj
= getObject( xEnv
);
648 xRow
->appendBoolean( rProp
, obj
->getBaseType( ) == "cmis:document" );
650 catch ( const libcmis::Exception
& )
652 if ( m_pObjectType
.get( ) )
653 xRow
->appendBoolean( rProp
, getObjectType( xEnv
)->getBaseType()->getId( ) == "cmis:document" );
655 xRow
->appendVoid( rProp
);
658 else if ( rProp
.Name
== "IsFolder" )
662 libcmis::ObjectPtr obj
= getObject( xEnv
);
664 xRow
->appendBoolean( rProp
, obj
->getBaseType( ) == "cmis:folder" );
666 xRow
->appendBoolean( rProp
, false );
668 catch ( const libcmis::Exception
& )
670 if ( m_pObjectType
.get( ) )
671 xRow
->appendBoolean( rProp
, getObjectType( xEnv
)->getBaseType()->getId( ) == "cmis:folder" );
673 xRow
->appendVoid( rProp
);
676 else if ( rProp
.Name
== "Title" )
681 sTitle
= STD_TO_OUSTR( getObject( xEnv
)->getName() );
683 catch ( const libcmis::Exception
& )
685 if ( !m_pObjectProps
.empty() )
687 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
688 if ( it
!= m_pObjectProps
.end( ) )
690 std::vector
< std::string
> values
= it
->second
->getStrings( );
691 if ( !values
.empty() )
692 sTitle
= STD_TO_OUSTR( values
.front( ) );
697 // Nothing worked... get it from the path
698 if ( sTitle
.isEmpty( ) )
700 OUString sPath
= m_sObjectPath
;
702 // Get rid of the trailing slash problem
703 if ( sPath
.endsWith("/") )
704 sPath
= sPath
.copy( 0, sPath
.getLength() - 1 );
706 // Get the last segment
707 sal_Int32 nPos
= sPath
.lastIndexOf( '/' );
709 sTitle
= sPath
.copy( nPos
+ 1 );
712 if ( !sTitle
.isEmpty( ) )
713 xRow
->appendString( rProp
, sTitle
);
715 xRow
->appendVoid( rProp
);
717 else if ( rProp
.Name
== "ObjectId" )
722 sId
= STD_TO_OUSTR( getObject( xEnv
)->getId() );
724 catch ( const libcmis::Exception
& )
726 if ( !m_pObjectProps
.empty() )
728 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:objectId" );
729 if ( it
!= m_pObjectProps
.end( ) )
731 std::vector
< std::string
> values
= it
->second
->getStrings( );
732 if ( !values
.empty() )
733 sId
= STD_TO_OUSTR( values
.front( ) );
738 if ( !sId
.isEmpty( ) )
739 xRow
->appendString( rProp
, sId
);
741 xRow
->appendVoid( rProp
);
743 else if ( rProp
.Name
== "TitleOnServer" )
745 xRow
->appendString( rProp
, m_sObjectPath
);
747 else if ( rProp
.Name
== "IsReadOnly" )
749 boost::shared_ptr
< libcmis::AllowableActions
> allowableActions
= getObject( xEnv
)->getAllowableActions( );
750 bool bReadOnly
= false;
751 if ( !allowableActions
->isAllowed( libcmis::ObjectAction::SetContentStream
) &&
752 !allowableActions
->isAllowed( libcmis::ObjectAction::CheckIn
) )
755 xRow
->appendBoolean( rProp
, bReadOnly
);
757 else if ( rProp
.Name
== "DateCreated" )
759 util::DateTime aTime
= lcl_boostToUnoTime( getObject( xEnv
)->getCreationDate( ) );
760 xRow
->appendTimestamp( rProp
, aTime
);
762 else if ( rProp
.Name
== "DateModified" )
764 util::DateTime aTime
= lcl_boostToUnoTime( getObject( xEnv
)->getLastModificationDate( ) );
765 xRow
->appendTimestamp( rProp
, aTime
);
767 else if ( rProp
.Name
== "Size" )
771 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get( ) );
772 if ( nullptr != document
)
773 xRow
->appendLong( rProp
, document
->getContentLength() );
775 xRow
->appendVoid( rProp
);
777 catch ( const libcmis::Exception
& )
779 xRow
->appendVoid( rProp
);
782 else if ( rProp
.Name
== "CreatableContentsInfo" )
784 xRow
->appendObject( rProp
, uno::makeAny( queryCreatableContentsInfo( xEnv
) ) );
786 else if ( rProp
.Name
== "MediaType" )
790 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get( ) );
791 if ( nullptr != document
)
792 xRow
->appendString( rProp
, STD_TO_OUSTR( document
->getContentType() ) );
794 xRow
->appendVoid( rProp
);
796 catch ( const libcmis::Exception
& )
798 xRow
->appendVoid( rProp
);
801 else if ( rProp
.Name
== "IsVolume" )
803 xRow
->appendBoolean( rProp
, false );
805 else if ( rProp
.Name
== "IsRemote" )
807 xRow
->appendBoolean( rProp
, false );
809 else if ( rProp
.Name
== "IsRemoveable" )
811 xRow
->appendBoolean( rProp
, false );
813 else if ( rProp
.Name
== "IsFloppy" )
815 xRow
->appendBoolean( rProp
, false );
817 else if ( rProp
.Name
== "IsCompactDisc" )
819 xRow
->appendBoolean( rProp
, false );
821 else if ( rProp
.Name
== "IsHidden" )
823 xRow
->appendBoolean( rProp
, false );
825 else if ( rProp
.Name
== "TargetURL" )
827 xRow
->appendString( rProp
, "" );
829 else if ( rProp
.Name
== "BaseURI" )
831 xRow
->appendString( rProp
, m_aURL
.getBindingUrl( ) );
833 else if ( rProp
.Name
== "CmisProperties" )
837 libcmis::ObjectPtr object
= getObject( xEnv
);
838 std::map
< std::string
, libcmis::PropertyPtr
>& aProperties
= object
->getProperties( );
839 uno::Sequence
< document::CmisProperty
> aCmisProperties( aProperties
.size( ) );
840 document::CmisProperty
* pCmisProps
= aCmisProperties
.getArray( );
842 for ( const auto& [sId
, rProperty
] : aProperties
)
844 auto sDisplayName
= rProperty
->getPropertyType()->getDisplayName( );
845 bool bUpdatable
= rProperty
->getPropertyType()->isUpdatable( );
846 bool bRequired
= rProperty
->getPropertyType()->isRequired( );
847 bool bMultiValued
= rProperty
->getPropertyType()->isMultiValued();
848 bool bOpenChoice
= rProperty
->getPropertyType()->isOpenChoice();
850 pCmisProps
[i
].Id
= STD_TO_OUSTR( sId
);
851 pCmisProps
[i
].Name
= STD_TO_OUSTR( sDisplayName
);
852 pCmisProps
[i
].Updatable
= bUpdatable
;
853 pCmisProps
[i
].Required
= bRequired
;
854 pCmisProps
[i
].MultiValued
= bMultiValued
;
855 pCmisProps
[i
].OpenChoice
= bOpenChoice
;
856 pCmisProps
[i
].Value
= lcl_cmisPropertyToUno( rProperty
);
857 switch ( rProperty
->getPropertyType( )->getType( ) )
860 case libcmis::PropertyType::String
:
861 pCmisProps
[i
].Type
= CMIS_TYPE_STRING
;
863 case libcmis::PropertyType::Integer
:
864 pCmisProps
[i
].Type
= CMIS_TYPE_INTEGER
;
866 case libcmis::PropertyType::Decimal
:
867 pCmisProps
[i
].Type
= CMIS_TYPE_DECIMAL
;
869 case libcmis::PropertyType::Bool
:
870 pCmisProps
[i
].Type
= CMIS_TYPE_BOOL
;
872 case libcmis::PropertyType::DateTime
:
873 pCmisProps
[i
].Type
= CMIS_TYPE_DATETIME
;
878 xRow
->appendObject( rProp
.Name
, uno::makeAny( aCmisProperties
) );
880 catch ( const libcmis::Exception
& )
882 xRow
->appendVoid( rProp
);
885 else if ( rProp
.Name
== "IsVersionable" )
889 libcmis::ObjectPtr object
= getObject( xEnv
);
890 bool bIsVersionable
= object
->getTypeDescription( )->isVersionable( );
891 xRow
->appendBoolean( rProp
, bIsVersionable
);
893 catch ( const libcmis::Exception
& )
895 xRow
->appendVoid( rProp
);
898 else if ( rProp
.Name
== "CanCheckOut" )
902 libcmis::ObjectPtr pObject
= getObject( xEnv
);
903 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
904 bool bAllowed
= false;
907 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckOut
);
909 xRow
->appendBoolean( rProp
, bAllowed
);
911 catch ( const libcmis::Exception
& )
913 xRow
->appendVoid( rProp
);
916 else if ( rProp
.Name
== "CanCancelCheckOut" )
920 libcmis::ObjectPtr pObject
= getObject( xEnv
);
921 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
922 bool bAllowed
= false;
925 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CancelCheckOut
);
927 xRow
->appendBoolean( rProp
, bAllowed
);
929 catch ( const libcmis::Exception
& )
931 xRow
->appendVoid( rProp
);
934 else if ( rProp
.Name
== "CanCheckIn" )
938 libcmis::ObjectPtr pObject
= getObject( xEnv
);
939 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
940 bool bAllowed
= false;
943 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckIn
);
945 xRow
->appendBoolean( rProp
, bAllowed
);
947 catch ( const libcmis::Exception
& )
949 xRow
->appendVoid( rProp
);
953 SAL_INFO( "ucb.ucp.cmis", "Looking for unsupported property " << rProp
.Name
);
955 catch (const libcmis::Exception
&)
957 xRow
->appendVoid( rProp
);
964 uno::Any
Content::open(const ucb::OpenCommandArgument2
& rOpenCommand
,
965 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
967 bool bIsFolder
= isFolder( xEnv
);
969 // Handle the case of the non-existing file
970 if ( !getObject( xEnv
) )
972 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(m_xIdentifier
->getContentIdentifier()) };
973 uno::Any aErr
= uno::makeAny(
974 ucb::InteractiveAugmentedIOException(OUString(), static_cast< cppu::OWeakObject
* >( this ),
975 task::InteractionClassification_ERROR
,
976 bIsFolder
? ucb::IOErrorCode_NOT_EXISTING_PATH
: ucb::IOErrorCode_NOT_EXISTING
, aArgs
)
979 ucbhelper::cancelCommandExecution(aErr
, xEnv
);
985 ( rOpenCommand
.Mode
== ucb::OpenMode::ALL
) ||
986 ( rOpenCommand
.Mode
== ucb::OpenMode::FOLDERS
) ||
987 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENTS
)
990 if ( bOpenFolder
&& bIsFolder
)
992 uno::Reference
< ucb::XDynamicResultSet
> xSet
993 = new DynamicResultSet(m_xContext
, this, rOpenCommand
, xEnv
);
996 else if ( rOpenCommand
.Sink
.is() )
999 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
1000 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
)
1003 ucbhelper::cancelCommandExecution(
1004 uno::makeAny ( ucb::UnsupportedOpenModeException
1005 ( OUString(), static_cast< cppu::OWeakObject
* >( this ),
1006 sal_Int16( rOpenCommand
.Mode
) ) ),
1010 if ( !feedSink( rOpenCommand
.Sink
, xEnv
) )
1012 // Note: rOpenCommand.Sink may contain an XStream
1013 // implementation. Support for this type of
1014 // sink is optional...
1015 SAL_INFO( "ucb.ucp.cmis", "Failed to copy data to sink" );
1017 ucbhelper::cancelCommandExecution(
1018 uno::makeAny (ucb::UnsupportedDataSinkException
1019 ( OUString(), static_cast< cppu::OWeakObject
* >( this ),
1020 rOpenCommand
.Sink
) ),
1025 SAL_INFO( "ucb.ucp.cmis", "Open falling through ..." );
1030 OUString
Content::checkIn( const ucb::CheckinArgument
& rArg
,
1031 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1033 ucbhelper::Content
aSourceContent( rArg
.SourceURL
, xEnv
, comphelper::getProcessComponentContext( ) );
1034 uno::Reference
< io::XInputStream
> xIn
= aSourceContent
.openStream( );
1036 libcmis::ObjectPtr object
;
1039 object
= getObject( xEnv
);
1041 catch ( const libcmis::Exception
& e
)
1043 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1044 ucbhelper::cancelCommandExecution(
1045 ucb::IOErrorCode_GENERAL
,
1046 uno::Sequence
< uno::Any
>( 0 ),
1048 OUString::createFromAscii( e
.what() ) );
1051 libcmis::Document
* pPwc
= dynamic_cast< libcmis::Document
* >( object
.get( ) );
1054 ucbhelper::cancelCommandExecution(
1055 ucb::IOErrorCode_GENERAL
,
1056 uno::Sequence
< uno::Any
>( 0 ),
1058 "Checkin only supported by documents" );
1061 boost::shared_ptr
< std::ostream
> pOut( new std::ostringstream ( std::ios_base::binary
| std::ios_base::in
| std::ios_base::out
) );
1062 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1063 copyData( xIn
, xOutput
);
1065 std::map
< std::string
, libcmis::PropertyPtr
> newProperties
;
1066 libcmis::DocumentPtr pDoc
;
1070 pDoc
= pPwc
->checkIn( rArg
.MajorVersion
, OUSTR_TO_STDSTR( rArg
.VersionComment
), newProperties
,
1071 pOut
, OUSTR_TO_STDSTR( rArg
.MimeType
), OUSTR_TO_STDSTR( rArg
.NewTitle
) );
1073 catch ( const libcmis::Exception
& e
)
1075 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1076 ucbhelper::cancelCommandExecution(
1077 ucb::IOErrorCode_GENERAL
,
1078 uno::Sequence
< uno::Any
>( 0 ),
1080 OUString::createFromAscii( e
.what() ) );
1083 // Get the URL and send it back as a result
1084 URL
aCmisUrl( m_sURL
);
1085 std::vector
< std::string
> aPaths
= pDoc
->getPaths( );
1086 if ( !aPaths
.empty() )
1088 auto sPath
= aPaths
.front( );
1089 aCmisUrl
.setObjectPath( STD_TO_OUSTR( sPath
) );
1093 // We may have unfiled document depending on the server, those
1094 // won't have any path, use their ID instead
1095 auto sId
= pDoc
->getId( );
1096 aCmisUrl
.setObjectId( STD_TO_OUSTR( sId
) );
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!",
1265 static_cast< cppu::OWeakObject
* >( this ) ) ),
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::makeAny
1280 ( ucb::MissingInputStreamException
1281 ( OUString(), static_cast< cppu::OWeakObject
* >( this ) ) ),
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::makeAny
1309 ( uno::RuntimeException( "Missing name property",
1310 static_cast< cppu::OWeakObject
* >( this ) ) ),
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::makeAny
1337 ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
1338 static_cast< cppu::OWeakObject
* >( this ) ) ),
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::makeAny
1356 ( uno::RuntimeException( "Error when setting document content",
1357 static_cast< cppu::OWeakObject
* >( this ) ) ),
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::makeAny
1378 ( uno::RuntimeException( "Error when creating folder",
1379 static_cast< cppu::OWeakObject
* >( this ) ) ),
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::makeAny
1396 ( uno::RuntimeException( "Error when creating document",
1397 static_cast< cppu::OWeakObject
* >( this ) ) ),
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!",
1472 static_cast< cppu::OWeakObject
* >( this ) );
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!",
1482 static_cast< cppu::OWeakObject
* >( this ) );
1486 if ( aNewTitle
.isEmpty() )
1488 aRetRange
[ n
] <<= lang::IllegalArgumentException
1489 ( "Empty title not allowed!",
1490 static_cast< cppu::OWeakObject
* >( this ), -1 );
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!",
1502 static_cast< cppu::OWeakObject
* >( this ) );
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 sRet
= isFolder( uno::Reference
< ucb::XCommandEnvironment
>() )
1742 ? std::u16string_view(u
"" CMIS_FOLDER_TYPE
)
1743 : std::u16string_view(u
"" CMIS_FILE_TYPE
);
1745 catch (const uno::RuntimeException
&)
1749 catch (const uno::Exception
& e
)
1751 uno::Any
a(cppu::getCaughtException());
1752 throw lang::WrappedTargetRuntimeException(
1753 "wrapped Exception " + e
.Message
,
1754 uno::Reference
<uno::XInterface
>(), a
);
1759 uno::Any SAL_CALL
Content::execute(
1760 const ucb::Command
& aCommand
,
1761 sal_Int32
/*CommandId*/,
1762 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1764 SAL_INFO( "ucb.ucp.cmis", "Content::execute( ) - " << aCommand
.Name
);
1767 if ( aCommand
.Name
== "getPropertyValues" )
1769 uno::Sequence
< beans::Property
> Properties
;
1770 if ( !( aCommand
.Argument
>>= Properties
) )
1771 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1772 aRet
<<= getPropertyValues( Properties
, xEnv
);
1774 else if ( aCommand
.Name
== "getPropertySetInfo" )
1775 aRet
<<= getPropertySetInfo( xEnv
, false );
1776 else if ( aCommand
.Name
== "getCommandInfo" )
1777 aRet
<<= getCommandInfo( xEnv
, false );
1778 else if ( aCommand
.Name
== "open" )
1780 ucb::OpenCommandArgument2 aOpenCommand
;
1781 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
1782 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1783 aRet
= open( aOpenCommand
, xEnv
);
1785 else if ( aCommand
.Name
== "transfer" )
1787 ucb::TransferInfo transferArgs
;
1788 if ( !( aCommand
.Argument
>>= transferArgs
) )
1789 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1790 transfer( transferArgs
, xEnv
);
1792 else if ( aCommand
.Name
== "setPropertyValues" )
1794 uno::Sequence
< beans::PropertyValue
> aProperties
;
1795 if ( !( aCommand
.Argument
>>= aProperties
) || !aProperties
.hasElements() )
1796 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1797 aRet
<<= setPropertyValues( aProperties
, xEnv
);
1799 else if (aCommand
.Name
== "createNewContent"
1800 && isFolder( xEnv
) )
1802 ucb::ContentInfo arg
;
1803 if ( !( aCommand
.Argument
>>= arg
) )
1804 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1805 aRet
<<= createNewContent( arg
);
1807 else if ( aCommand
.Name
== "insert" )
1809 ucb::InsertCommandArgument2 arg
;
1810 if ( !( aCommand
.Argument
>>= arg
) )
1812 ucb::InsertCommandArgument insertArg
;
1813 if ( !( aCommand
.Argument
>>= insertArg
) )
1814 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1816 arg
.Data
= insertArg
.Data
;
1817 arg
.ReplaceExisting
= insertArg
.ReplaceExisting
;
1819 // store the document id
1820 m_sObjectId
= arg
.DocumentId
;
1821 insert( arg
.Data
, arg
.ReplaceExisting
, arg
.MimeType
, xEnv
);
1823 else if ( aCommand
.Name
== "delete" )
1827 if ( !isFolder( xEnv
) )
1829 getObject( xEnv
)->remove( );
1833 libcmis::Folder
* folder
= dynamic_cast< libcmis::Folder
* >( getObject( xEnv
).get() );
1835 folder
->removeTree( );
1838 catch ( const libcmis::Exception
& e
)
1840 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1841 ucbhelper::cancelCommandExecution(
1842 ucb::IOErrorCode_GENERAL
,
1843 uno::Sequence
< uno::Any
>( 0 ),
1845 o3tl::runtimeToOUString(e
.what()));
1848 else if ( aCommand
.Name
== "checkout" )
1850 aRet
<<= checkOut( xEnv
);
1852 else if ( aCommand
.Name
== "cancelCheckout" )
1854 aRet
<<= cancelCheckOut( xEnv
);
1856 else if ( aCommand
.Name
== "checkin" )
1858 ucb::CheckinArgument aArg
;
1859 if ( !( aCommand
.Argument
>>= aArg
) )
1861 ucbhelper::cancelCommandExecution ( getBadArgExcept(), xEnv
);
1863 aRet
<<= checkIn( aArg
, xEnv
);
1865 else if ( aCommand
.Name
== "getAllVersions" )
1867 aRet
<<= getAllVersions( xEnv
);
1869 else if ( aCommand
.Name
== "updateProperties" )
1871 updateProperties( aCommand
.Argument
, xEnv
);
1875 SAL_INFO( "ucb.ucp.cmis", "Unknown command to execute" );
1877 ucbhelper::cancelCommandExecution
1878 ( uno::makeAny( ucb::UnsupportedCommandException
1880 static_cast< cppu::OWeakObject
* >( this ) ) ),
1887 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
1889 SAL_INFO( "ucb.ucp.cmis", "TODO - Content::abort()" );
1890 // TODO Implement me
1893 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
Content::queryCreatableContentsInfo()
1895 return queryCreatableContentsInfo( uno::Reference
< ucb::XCommandEnvironment
>() );
1898 uno::Reference
< ucb::XContent
> SAL_CALL
Content::createNewContent(
1899 const ucb::ContentInfo
& Info
)
1901 bool create_document
;
1903 if ( Info
.Type
== CMIS_FILE_TYPE
)
1904 create_document
= true;
1905 else if ( Info
.Type
== CMIS_FOLDER_TYPE
)
1906 create_document
= false;
1909 SAL_INFO( "ucb.ucp.cmis", "Unknown type of content to create" );
1910 return uno::Reference
< ucb::XContent
>();
1913 OUString sParentURL
= m_xIdentifier
->getContentIdentifier();
1915 // Set the parent URL for the transient objects
1916 uno::Reference
< ucb::XContentIdentifier
> xId(new ::ucbhelper::ContentIdentifier(sParentURL
));
1920 return new ::cmis::Content( m_xContext
, m_pProvider
, xId
, !create_document
);
1922 catch ( ucb::ContentCreationException
& )
1924 return uno::Reference
< ucb::XContent
>();
1928 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
1932 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
1934 static cppu::OTypeCollection s_aFolderCollection
1935 (CPPU_TYPE_REF( lang::XTypeProvider
),
1936 CPPU_TYPE_REF( lang::XServiceInfo
),
1937 CPPU_TYPE_REF( lang::XComponent
),
1938 CPPU_TYPE_REF( ucb::XContent
),
1939 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1940 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1941 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1942 CPPU_TYPE_REF( beans::XPropertyContainer
),
1943 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1944 CPPU_TYPE_REF( container::XChild
),
1945 CPPU_TYPE_REF( ucb::XContentCreator
) );
1946 return s_aFolderCollection
.getTypes();
1949 catch (const uno::RuntimeException
&)
1953 catch (const uno::Exception
& e
)
1955 uno::Any
a(cppu::getCaughtException());
1956 throw lang::WrappedTargetRuntimeException(
1957 "wrapped Exception " + e
.Message
,
1958 uno::Reference
<uno::XInterface
>(), a
);
1961 static cppu::OTypeCollection s_aFileCollection
1962 (CPPU_TYPE_REF( lang::XTypeProvider
),
1963 CPPU_TYPE_REF( lang::XServiceInfo
),
1964 CPPU_TYPE_REF( lang::XComponent
),
1965 CPPU_TYPE_REF( ucb::XContent
),
1966 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1967 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1968 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1969 CPPU_TYPE_REF( beans::XPropertyContainer
),
1970 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1971 CPPU_TYPE_REF( container::XChild
) );
1973 return s_aFileCollection
.getTypes();
1976 uno::Sequence
< ucb::ContentInfo
> Content::queryCreatableContentsInfo(
1977 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1981 if ( isFolder( xEnv
) )
1984 // Minimum set of props we really need
1985 uno::Sequence
< beans::Property
> props
1990 cppu::UnoType
<OUString
>::get(),
1991 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
1999 ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
|
2000 ucb::ContentInfoAttribute::KIND_DOCUMENT
),
2005 ucb::ContentInfoAttribute::KIND_FOLDER
,
2011 catch (const uno::RuntimeException
&)
2015 catch (const uno::Exception
& e
)
2017 uno::Any
a(cppu::getCaughtException());
2018 throw lang::WrappedTargetRuntimeException(
2019 "wrapped Exception " + e
.Message
,
2020 uno::Reference
<uno::XInterface
>(), a
);
2025 std::vector
< uno::Reference
< ucb::XContent
> > Content::getChildren( )
2027 std::vector
< uno::Reference
< ucb::XContent
> > results
;
2028 SAL_INFO( "ucb.ucp.cmis", "Content::getChildren() " << m_sURL
);
2030 libcmis::FolderPtr pFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>( getObject( uno::Reference
< ucb::XCommandEnvironment
>() ) );
2031 if ( nullptr != pFolder
)
2033 // Get the children from pObject
2036 std::vector
< libcmis::ObjectPtr
> children
= pFolder
->getChildren( );
2038 // Loop over the results
2039 for ( const auto& rChild
: children
)
2041 // TODO Cache the objects
2043 INetURLObject
aURL( m_sURL
);
2044 OUString sUser
= aURL
.GetUser( INetURLObject::DecodeMechanism::WithCharset
);
2047 OUString
sPath( m_sObjectPath
);
2048 if ( !sPath
.endsWith("/") )
2050 sPath
+= STD_TO_OUSTR( rChild
->getName( ) );
2051 OUString sId
= STD_TO_OUSTR( rChild
->getId( ) );
2053 aUrl
.setObjectId( sId
);
2054 aUrl
.setObjectPath( sPath
);
2055 aUrl
.setUsername( sUser
);
2057 uno::Reference
< ucb::XContentIdentifier
> xId
= new ucbhelper::ContentIdentifier( aUrl
.asString( ) );
2058 uno::Reference
< ucb::XContent
> xContent
= new Content( m_xContext
, m_pProvider
, xId
, rChild
);
2060 results
.push_back( xContent
);
2063 catch ( const libcmis::Exception
& e
)
2065 SAL_INFO( "ucb.ucp.cmis", "Exception thrown: " << e
.what() );
2072 void Content::setCmisProperty(const std::string
& rName
, const std::string
& rValue
, const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
2074 if ( !getObjectType( xEnv
).get( ) )
2077 std::map
< std::string
, libcmis::PropertyPtr
>::iterator propIt
= m_pObjectProps
.find(rName
);
2079 if ( propIt
== m_pObjectProps
.end( ) && getObjectType( xEnv
).get( ) )
2081 std::map
< std::string
, libcmis::PropertyTypePtr
> propsTypes
= getObjectType( xEnv
)->getPropertiesTypes( );
2082 std::map
< std::string
, libcmis::PropertyTypePtr
>::iterator typeIt
= propsTypes
.find(rName
);
2084 if ( typeIt
!= propsTypes
.end( ) )
2086 libcmis::PropertyTypePtr propType
= typeIt
->second
;
2087 libcmis::PropertyPtr
property( new libcmis::Property( propType
, { rValue
}) );
2088 m_pObjectProps
.insert(std::pair
< std::string
, libcmis::PropertyPtr
>(rName
, property
));
2091 else if ( propIt
!= m_pObjectProps
.end( ) )
2093 propIt
->second
->setValues( { rValue
} );
2098 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */