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 <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 ucbhelper::InternetProxyServer
& rProxy
= aProxyDecider
.getProxy(
310 INetURLObject::GetScheme( aBindingUrl
.GetProtocol( ) ), aBindingUrl
.GetHost(), aBindingUrl
.GetPort() );
311 OUString sProxy
= rProxy
.aName
;
312 if ( rProxy
.nPort
> 0 )
313 sProxy
+= ":" + OUString::number( rProxy
.nPort
);
314 libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy
), std::string(), std::string(), std::string() );
316 // Look for a cached session, key is binding url + repo id
317 OUString sSessionId
= m_aURL
.getBindingUrl( ) + m_aURL
.getRepositoryId( );
318 if ( nullptr == m_pSession
)
319 m_pSession
= m_pProvider
->getSession( sSessionId
, m_aURL
.getUsername( ) );
321 if ( nullptr == m_pSession
)
324 // Initialize NSS library to make sure libcmis (and curl) can access CACERTs using NSS
325 // when using internal libcurl.
326 uno::Reference
< css::xml::crypto::XNSSInitializer
>
327 xNSSInitializer
= css::xml::crypto::NSSInitializer::create( m_xContext
);
329 uno::Reference
< css::xml::crypto::XDigestContext
> xDigestContext(
330 xNSSInitializer
->getDigestContext( css::xml::crypto::DigestID::SHA256
,
331 uno::Sequence
< beans::NamedValue
>() ),
332 uno::UNO_SET_THROW
);
335 // Set the SSL Validation handler
336 libcmis::CertValidationHandlerPtr
certHandler(
337 new CertValidationHandler( xEnv
, m_xContext
, aBindingUrl
.GetHost( ) ) );
338 libcmis::SessionFactory::setCertificateValidationHandler( certHandler
);
340 // init libcurl callback
341 libcmis::SessionFactory::setCurlInitProtocolsFunction(&::InitCurl_easy
);
343 // Get the auth credentials
344 AuthProvider
aAuthProvider(xEnv
, m_xIdentifier
->getContentIdentifier(), m_aURL
.getBindingUrl());
345 AuthProvider::setXEnv( xEnv
);
347 auto rUsername
= OUSTR_TO_STDSTR( m_aURL
.getUsername( ) );
348 auto rPassword
= OUSTR_TO_STDSTR( m_aURL
.getPassword( ) );
350 bool bSkipInitialPWAuth
= false;
351 if (m_aURL
.getBindingUrl() == ONEDRIVE_BASE_URL
352 || m_aURL
.getBindingUrl() == GDRIVE_BASE_URL
)
354 // skip the initial username and pw-auth prompt, the only supported method is the
355 // auth-code-fallback one (login with your browser, copy code into the dialog)
356 // TODO: if LO were to listen on localhost for the request, it would be much nicer
358 bSkipInitialPWAuth
= true;
359 rPassword
= aAuthProvider
.getRefreshToken(rUsername
);
362 bool bIsDone
= false;
366 if (bSkipInitialPWAuth
|| aAuthProvider
.authenticationQuery(rUsername
, rPassword
))
368 // Initiate a CMIS session and register it as we found nothing
369 libcmis::OAuth2DataPtr oauth2Data
;
370 if ( m_aURL
.getBindingUrl( ) == GDRIVE_BASE_URL
)
372 // reset the skip, so user gets a chance to cancel
373 bSkipInitialPWAuth
= false;
374 libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback
);
375 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
376 GDRIVE_AUTH_URL
, GDRIVE_TOKEN_URL
,
377 GDRIVE_SCOPE
, GDRIVE_REDIRECT_URI
,
378 GDRIVE_CLIENT_ID
, GDRIVE_CLIENT_SECRET
);
380 if ( m_aURL
.getBindingUrl().startsWith( ALFRESCO_CLOUD_BASE_URL
) )
381 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
382 ALFRESCO_CLOUD_AUTH_URL
, ALFRESCO_CLOUD_TOKEN_URL
,
383 ALFRESCO_CLOUD_SCOPE
, ALFRESCO_CLOUD_REDIRECT_URI
,
384 ALFRESCO_CLOUD_CLIENT_ID
, ALFRESCO_CLOUD_CLIENT_SECRET
);
385 if ( m_aURL
.getBindingUrl( ) == ONEDRIVE_BASE_URL
)
387 // reset the skip, so user gets a chance to cancel
388 bSkipInitialPWAuth
= false;
389 libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback
);
390 oauth2Data
= boost::make_shared
<libcmis::OAuth2Data
>(
391 ONEDRIVE_AUTH_URL
, ONEDRIVE_TOKEN_URL
,
392 ONEDRIVE_SCOPE
, ONEDRIVE_REDIRECT_URI
,
393 ONEDRIVE_CLIENT_ID
, ONEDRIVE_CLIENT_SECRET
);
397 m_pSession
= libcmis::SessionFactory::createSession(
398 OUSTR_TO_STDSTR( m_aURL
.getBindingUrl( ) ),
399 rUsername
, rPassword
, OUSTR_TO_STDSTR( m_aURL
.getRepositoryId( ) ), false, oauth2Data
);
401 if ( m_pSession
== nullptr )
403 // Fail: session was not created
404 ucbhelper::cancelCommandExecution(
405 ucb::IOErrorCode_INVALID_DEVICE
,
406 generateErrorArguments(m_aURL
),
409 else if ( m_pSession
->getRepository() == nullptr )
411 // Fail: no repository or repository is invalid
412 ucbhelper::cancelCommandExecution(
413 ucb::IOErrorCode_INVALID_DEVICE
,
414 generateErrorArguments(m_aURL
),
416 "error accessing a repository");
420 m_pProvider
->registerSession(sSessionId
, m_aURL
.getUsername( ), m_pSession
);
421 if (m_aURL
.getBindingUrl() == ONEDRIVE_BASE_URL
422 || m_aURL
.getBindingUrl() == GDRIVE_BASE_URL
)
424 aAuthProvider
.storeRefreshToken(rUsername
, rPassword
,
425 m_pSession
->getRefreshToken());
431 catch( const libcmis::Exception
& e
)
433 if ( e
.getType() != "permissionDenied" )
435 SAL_INFO("ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what());
442 // Silently fail as the user cancelled the authentication
443 ucbhelper::cancelCommandExecution(
444 ucb::IOErrorCode_ABORT
,
445 uno::Sequence
< uno::Any
>( 0 ),
447 throw uno::RuntimeException( );
454 libcmis::ObjectTypePtr
const & Content::getObjectType( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
456 if ( nullptr == m_pObjectType
.get( ) && m_bTransient
)
458 std::string typeId
= m_bIsFolder
? "cmis:folder" : "cmis:document";
459 // The type to create needs to be fetched from the possible children types
460 // defined in the parent folder. Then, we'll pick up the first one we find matching
461 // cmis:folder or cmis:document (depending what we need to create).
462 // The easy case will work in most cases, but not on some servers (like Lotus Live)
463 libcmis::Folder
* pParent
= nullptr;
464 bool bTypeRestricted
= false;
467 pParent
= dynamic_cast< libcmis::Folder
* >( getObject( xEnv
).get( ) );
469 catch ( const libcmis::Exception
& )
475 std::map
< std::string
, libcmis::PropertyPtr
>& aProperties
= pParent
->getProperties( );
476 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= aProperties
.find( "cmis:allowedChildObjectTypeIds" );
477 if ( it
!= aProperties
.end( ) )
479 libcmis::PropertyPtr pProperty
= it
->second
;
482 std::vector
< std::string
> typesIds
= pProperty
->getStrings( );
483 for ( const auto& rType
: typesIds
)
485 bTypeRestricted
= true;
486 libcmis::ObjectTypePtr type
= getSession( xEnv
)->getType( rType
);
488 // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis
489 if ( type
->getBaseType( )->getId( ) == typeId
)
491 m_pObjectType
= type
;
499 if ( !bTypeRestricted
)
500 m_pObjectType
= getSession( xEnv
)->getType( typeId
);
502 return m_pObjectType
;
506 libcmis::ObjectPtr
const & Content::getObject( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
508 // can't get the session for some reason
509 // the recent file opening at start up is an example.
512 if ( !getSession( xEnv
) )
515 catch ( uno::RuntimeException
& )
519 if ( !m_pObject
.get() )
521 if ( !m_sObjectId
.isEmpty( ) )
525 m_pObject
= getSession( xEnv
)->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
527 catch ( const libcmis::Exception
& )
529 SAL_INFO( "ucb.ucp.cmis", "object: " << OUSTR_TO_STDSTR(m_sObjectId
));
530 throw libcmis::Exception( "Object not found" );
533 else if (!(m_sObjectPath
.isEmpty() || m_sObjectPath
== "/"))
537 m_pObject
= getSession( xEnv
)->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath
) );
539 catch ( const libcmis::Exception
& )
541 // In some cases, getting the object from the path doesn't work,
542 // but getting the parent from its path and the get the child in the list is OK.
543 // It's weird, but needed to handle case where the path isn't the folders/files
544 // names separated by '/' (as in Lotus Live)
545 INetURLObject
aParentUrl( m_sURL
);
546 std::string sName
= OUSTR_TO_STDSTR( aParentUrl
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
) );
547 aParentUrl
.removeSegment( );
548 OUString sParentUrl
= aParentUrl
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
549 // Avoid infinite recursion if sParentUrl == m_sURL
550 if (sParentUrl
!= m_sURL
)
552 rtl::Reference
<Content
> xParent(new Content(m_xContext
, m_pProvider
, new ucbhelper::ContentIdentifier(sParentUrl
)));
553 libcmis::FolderPtr pParentFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>(xParent
->getObject(xEnv
));
556 std::vector
< libcmis::ObjectPtr
> children
= pParentFolder
->getChildren();
557 auto it
= std::find_if(children
.begin(), children
.end(),
558 [&sName
](const libcmis::ObjectPtr
& rChild
) { return rChild
->getName() == sName
; });
559 if (it
!= children
.end())
565 throw libcmis::Exception( "Object not found" );
570 m_pObject
= getSession( xEnv
)->getRootFolder( );
572 m_sObjectId
= OUString( );
579 bool Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
581 bool bIsFolder
= false;
584 libcmis::ObjectPtr obj
= getObject( xEnv
);
586 bIsFolder
= obj
->getBaseType( ) == "cmis:folder";
588 catch ( const libcmis::Exception
& e
)
590 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
592 ucbhelper::cancelCommandExecution(
593 ucb::IOErrorCode_GENERAL
,
594 uno::Sequence
< uno::Any
>( 0 ),
596 OUString::createFromAscii( e
.what( ) ) );
602 uno::Any
Content::getBadArgExcept()
604 return uno::Any( lang::IllegalArgumentException(
605 "Wrong argument type!",
606 static_cast< cppu::OWeakObject
* >( this ), -1) );
609 libcmis::ObjectPtr
Content::updateProperties(
610 const uno::Any
& iCmisProps
,
611 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
613 // Convert iCmisProps to Cmis Properties;
614 uno::Sequence
< document::CmisProperty
> aPropsSeq
;
615 iCmisProps
>>= aPropsSeq
;
616 std::map
< std::string
, libcmis::PropertyPtr
> aProperties
;
618 for ( const auto& rProp
: std::as_const(aPropsSeq
) )
620 std::string id
= OUSTR_TO_STDSTR( rProp
.Id
);
621 libcmis::PropertyPtr prop
= lcl_unoToCmisProperty( rProp
);
622 aProperties
.insert( std::pair
<std::string
, libcmis::PropertyPtr
>( id
, prop
) );
624 libcmis::ObjectPtr updateObj
;
627 updateObj
= getObject( xEnv
)->updateProperties( aProperties
);
629 catch ( const libcmis::Exception
& e
)
631 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: "<< e
.what( ) );
637 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
638 const uno::Sequence
< beans::Property
>& rProperties
,
639 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
641 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
= new ::ucbhelper::PropertyValueSet( m_xContext
);
643 for( const beans::Property
& rProp
: rProperties
)
647 if ( rProp
.Name
== "IsDocument" )
651 libcmis::ObjectPtr obj
= getObject( xEnv
);
653 xRow
->appendBoolean( rProp
, obj
->getBaseType( ) == "cmis:document" );
655 catch ( const libcmis::Exception
& )
657 if ( m_pObjectType
.get( ) )
658 xRow
->appendBoolean( rProp
, getObjectType( xEnv
)->getBaseType()->getId( ) == "cmis:document" );
660 xRow
->appendVoid( rProp
);
663 else if ( rProp
.Name
== "IsFolder" )
667 libcmis::ObjectPtr obj
= getObject( xEnv
);
669 xRow
->appendBoolean( rProp
, obj
->getBaseType( ) == "cmis:folder" );
671 xRow
->appendBoolean( rProp
, false );
673 catch ( const libcmis::Exception
& )
675 if ( m_pObjectType
.get( ) )
676 xRow
->appendBoolean( rProp
, getObjectType( xEnv
)->getBaseType()->getId( ) == "cmis:folder" );
678 xRow
->appendVoid( rProp
);
681 else if ( rProp
.Name
== "Title" )
686 sTitle
= STD_TO_OUSTR( getObject( xEnv
)->getName() );
688 catch ( const libcmis::Exception
& )
690 if ( !m_pObjectProps
.empty() )
692 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
693 if ( it
!= m_pObjectProps
.end( ) )
695 std::vector
< std::string
> values
= it
->second
->getStrings( );
696 if ( !values
.empty() )
697 sTitle
= STD_TO_OUSTR( values
.front( ) );
702 // Nothing worked... get it from the path
703 if ( sTitle
.isEmpty( ) )
705 OUString sPath
= m_sObjectPath
;
707 // Get rid of the trailing slash problem
708 if ( sPath
.endsWith("/") )
709 sPath
= sPath
.copy( 0, sPath
.getLength() - 1 );
711 // Get the last segment
712 sal_Int32 nPos
= sPath
.lastIndexOf( '/' );
714 sTitle
= sPath
.copy( nPos
+ 1 );
717 if ( !sTitle
.isEmpty( ) )
718 xRow
->appendString( rProp
, sTitle
);
720 xRow
->appendVoid( rProp
);
722 else if ( rProp
.Name
== "ObjectId" )
727 sId
= STD_TO_OUSTR( getObject( xEnv
)->getId() );
729 catch ( const libcmis::Exception
& )
731 if ( !m_pObjectProps
.empty() )
733 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:objectId" );
734 if ( it
!= m_pObjectProps
.end( ) )
736 std::vector
< std::string
> values
= it
->second
->getStrings( );
737 if ( !values
.empty() )
738 sId
= STD_TO_OUSTR( values
.front( ) );
743 if ( !sId
.isEmpty( ) )
744 xRow
->appendString( rProp
, sId
);
746 xRow
->appendVoid( rProp
);
748 else if ( rProp
.Name
== "TitleOnServer" )
750 xRow
->appendString( rProp
, m_sObjectPath
);
752 else if ( rProp
.Name
== "IsReadOnly" )
754 boost::shared_ptr
< libcmis::AllowableActions
> allowableActions
= getObject( xEnv
)->getAllowableActions( );
755 bool bReadOnly
= false;
756 if ( !allowableActions
->isAllowed( libcmis::ObjectAction::SetContentStream
) &&
757 !allowableActions
->isAllowed( libcmis::ObjectAction::CheckIn
) )
760 xRow
->appendBoolean( rProp
, bReadOnly
);
762 else if ( rProp
.Name
== "DateCreated" )
764 util::DateTime aTime
= lcl_boostToUnoTime( getObject( xEnv
)->getCreationDate( ) );
765 xRow
->appendTimestamp( rProp
, aTime
);
767 else if ( rProp
.Name
== "DateModified" )
769 util::DateTime aTime
= lcl_boostToUnoTime( getObject( xEnv
)->getLastModificationDate( ) );
770 xRow
->appendTimestamp( rProp
, aTime
);
772 else if ( rProp
.Name
== "Size" )
776 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get( ) );
777 if ( nullptr != document
)
778 xRow
->appendLong( rProp
, document
->getContentLength() );
780 xRow
->appendVoid( rProp
);
782 catch ( const libcmis::Exception
& )
784 xRow
->appendVoid( rProp
);
787 else if ( rProp
.Name
== "CreatableContentsInfo" )
789 xRow
->appendObject( rProp
, uno::Any( queryCreatableContentsInfo( xEnv
) ) );
791 else if ( rProp
.Name
== "MediaType" )
795 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get( ) );
796 if ( nullptr != document
)
797 xRow
->appendString( rProp
, STD_TO_OUSTR( document
->getContentType() ) );
799 xRow
->appendVoid( rProp
);
801 catch ( const libcmis::Exception
& )
803 xRow
->appendVoid( rProp
);
806 else if ( rProp
.Name
== "IsVolume" )
808 xRow
->appendBoolean( rProp
, false );
810 else if ( rProp
.Name
== "IsRemote" )
812 xRow
->appendBoolean( rProp
, false );
814 else if ( rProp
.Name
== "IsRemoveable" )
816 xRow
->appendBoolean( rProp
, false );
818 else if ( rProp
.Name
== "IsFloppy" )
820 xRow
->appendBoolean( rProp
, false );
822 else if ( rProp
.Name
== "IsCompactDisc" )
824 xRow
->appendBoolean( rProp
, false );
826 else if ( rProp
.Name
== "IsHidden" )
828 xRow
->appendBoolean( rProp
, false );
830 else if ( rProp
.Name
== "TargetURL" )
832 xRow
->appendString( rProp
, "" );
834 else if ( rProp
.Name
== "BaseURI" )
836 xRow
->appendString( rProp
, m_aURL
.getBindingUrl( ) );
838 else if ( rProp
.Name
== "CmisProperties" )
842 libcmis::ObjectPtr object
= getObject( xEnv
);
843 std::map
< std::string
, libcmis::PropertyPtr
>& aProperties
= object
->getProperties( );
844 uno::Sequence
< document::CmisProperty
> aCmisProperties( aProperties
.size( ) );
845 document::CmisProperty
* pCmisProps
= aCmisProperties
.getArray( );
847 for ( const auto& [sId
, rProperty
] : aProperties
)
849 auto sDisplayName
= rProperty
->getPropertyType()->getDisplayName( );
850 bool bUpdatable
= rProperty
->getPropertyType()->isUpdatable( );
851 bool bRequired
= rProperty
->getPropertyType()->isRequired( );
852 bool bMultiValued
= rProperty
->getPropertyType()->isMultiValued();
853 bool bOpenChoice
= rProperty
->getPropertyType()->isOpenChoice();
855 pCmisProps
[i
].Id
= STD_TO_OUSTR( sId
);
856 pCmisProps
[i
].Name
= STD_TO_OUSTR( sDisplayName
);
857 pCmisProps
[i
].Updatable
= bUpdatable
;
858 pCmisProps
[i
].Required
= bRequired
;
859 pCmisProps
[i
].MultiValued
= bMultiValued
;
860 pCmisProps
[i
].OpenChoice
= bOpenChoice
;
861 pCmisProps
[i
].Value
= lcl_cmisPropertyToUno( rProperty
);
862 switch ( rProperty
->getPropertyType( )->getType( ) )
865 case libcmis::PropertyType::String
:
866 pCmisProps
[i
].Type
= CMIS_TYPE_STRING
;
868 case libcmis::PropertyType::Integer
:
869 pCmisProps
[i
].Type
= CMIS_TYPE_INTEGER
;
871 case libcmis::PropertyType::Decimal
:
872 pCmisProps
[i
].Type
= CMIS_TYPE_DECIMAL
;
874 case libcmis::PropertyType::Bool
:
875 pCmisProps
[i
].Type
= CMIS_TYPE_BOOL
;
877 case libcmis::PropertyType::DateTime
:
878 pCmisProps
[i
].Type
= CMIS_TYPE_DATETIME
;
883 xRow
->appendObject( rProp
.Name
, uno::Any( aCmisProperties
) );
885 catch ( const libcmis::Exception
& )
887 xRow
->appendVoid( rProp
);
890 else if ( rProp
.Name
== "IsVersionable" )
894 libcmis::ObjectPtr object
= getObject( xEnv
);
895 bool bIsVersionable
= object
->getTypeDescription( )->isVersionable( );
896 xRow
->appendBoolean( rProp
, bIsVersionable
);
898 catch ( const libcmis::Exception
& )
900 xRow
->appendVoid( rProp
);
903 else if ( rProp
.Name
== "CanCheckOut" )
907 libcmis::ObjectPtr pObject
= getObject( xEnv
);
908 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
909 bool bAllowed
= false;
912 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckOut
);
914 xRow
->appendBoolean( rProp
, bAllowed
);
916 catch ( const libcmis::Exception
& )
918 xRow
->appendVoid( rProp
);
921 else if ( rProp
.Name
== "CanCancelCheckOut" )
925 libcmis::ObjectPtr pObject
= getObject( xEnv
);
926 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
927 bool bAllowed
= false;
930 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CancelCheckOut
);
932 xRow
->appendBoolean( rProp
, bAllowed
);
934 catch ( const libcmis::Exception
& )
936 xRow
->appendVoid( rProp
);
939 else if ( rProp
.Name
== "CanCheckIn" )
943 libcmis::ObjectPtr pObject
= getObject( xEnv
);
944 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
945 bool bAllowed
= false;
948 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckIn
);
950 xRow
->appendBoolean( rProp
, bAllowed
);
952 catch ( const libcmis::Exception
& )
954 xRow
->appendVoid( rProp
);
958 SAL_INFO( "ucb.ucp.cmis", "Looking for unsupported property " << rProp
.Name
);
960 catch (const libcmis::Exception
&)
962 xRow
->appendVoid( rProp
);
969 uno::Any
Content::open(const ucb::OpenCommandArgument2
& rOpenCommand
,
970 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
972 bool bIsFolder
= isFolder( xEnv
);
974 // Handle the case of the non-existing file
975 if ( !getObject( xEnv
) )
977 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(m_xIdentifier
->getContentIdentifier()) };
979 ucb::InteractiveAugmentedIOException(OUString(), static_cast< cppu::OWeakObject
* >( this ),
980 task::InteractionClassification_ERROR
,
981 bIsFolder
? ucb::IOErrorCode_NOT_EXISTING_PATH
: ucb::IOErrorCode_NOT_EXISTING
, aArgs
)
984 ucbhelper::cancelCommandExecution(aErr
, xEnv
);
990 ( rOpenCommand
.Mode
== ucb::OpenMode::ALL
) ||
991 ( rOpenCommand
.Mode
== ucb::OpenMode::FOLDERS
) ||
992 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENTS
)
995 if ( bOpenFolder
&& bIsFolder
)
997 uno::Reference
< ucb::XDynamicResultSet
> xSet
998 = new DynamicResultSet(m_xContext
, this, rOpenCommand
, xEnv
);
1001 else if ( rOpenCommand
.Sink
.is() )
1004 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
1005 ( rOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
)
1008 ucbhelper::cancelCommandExecution(
1009 uno::Any ( ucb::UnsupportedOpenModeException
1010 ( OUString(), static_cast< cppu::OWeakObject
* >( this ),
1011 sal_Int16( rOpenCommand
.Mode
) ) ),
1015 if ( !feedSink( rOpenCommand
.Sink
, xEnv
) )
1017 // Note: rOpenCommand.Sink may contain an XStream
1018 // implementation. Support for this type of
1019 // sink is optional...
1020 SAL_INFO( "ucb.ucp.cmis", "Failed to copy data to sink" );
1022 ucbhelper::cancelCommandExecution(
1023 uno::Any (ucb::UnsupportedDataSinkException
1024 ( OUString(), static_cast< cppu::OWeakObject
* >( this ),
1025 rOpenCommand
.Sink
) ),
1030 SAL_INFO( "ucb.ucp.cmis", "Open falling through ..." );
1035 OUString
Content::checkIn( const ucb::CheckinArgument
& rArg
,
1036 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1038 ucbhelper::Content
aSourceContent( rArg
.SourceURL
, xEnv
, comphelper::getProcessComponentContext( ) );
1039 uno::Reference
< io::XInputStream
> xIn
= aSourceContent
.openStream( );
1041 libcmis::ObjectPtr object
;
1044 object
= getObject( xEnv
);
1046 catch ( const libcmis::Exception
& e
)
1048 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1049 ucbhelper::cancelCommandExecution(
1050 ucb::IOErrorCode_GENERAL
,
1051 uno::Sequence
< uno::Any
>( 0 ),
1053 OUString::createFromAscii( e
.what() ) );
1056 libcmis::Document
* pPwc
= dynamic_cast< libcmis::Document
* >( object
.get( ) );
1059 ucbhelper::cancelCommandExecution(
1060 ucb::IOErrorCode_GENERAL
,
1061 uno::Sequence
< uno::Any
>( 0 ),
1063 "Checkin only supported by documents" );
1066 boost::shared_ptr
< std::ostream
> pOut( new std::ostringstream ( std::ios_base::binary
| std::ios_base::in
| std::ios_base::out
) );
1067 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1068 copyData( xIn
, xOutput
);
1070 std::map
< std::string
, libcmis::PropertyPtr
> newProperties
;
1071 libcmis::DocumentPtr pDoc
;
1075 pDoc
= pPwc
->checkIn( rArg
.MajorVersion
, OUSTR_TO_STDSTR( rArg
.VersionComment
), newProperties
,
1076 pOut
, OUSTR_TO_STDSTR( rArg
.MimeType
), OUSTR_TO_STDSTR( rArg
.NewTitle
) );
1078 catch ( const libcmis::Exception
& e
)
1080 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1081 ucbhelper::cancelCommandExecution(
1082 ucb::IOErrorCode_GENERAL
,
1083 uno::Sequence
< uno::Any
>( 0 ),
1085 OUString::createFromAscii( e
.what() ) );
1088 // Get the URL and send it back as a result
1089 URL
aCmisUrl( m_sURL
);
1090 std::vector
< std::string
> aPaths
= pDoc
->getPaths( );
1091 if ( !aPaths
.empty() )
1093 auto sPath
= aPaths
.front( );
1094 aCmisUrl
.setObjectPath( STD_TO_OUSTR( sPath
) );
1098 // We may have unfiled document depending on the server, those
1099 // won't have any path, use their ID instead
1100 auto sId
= pDoc
->getId( );
1101 aCmisUrl
.setObjectId( STD_TO_OUSTR( sId
) );
1103 return aCmisUrl
.asString( );
1106 OUString
Content::checkOut( const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1111 // Checkout the document if possible
1112 libcmis::DocumentPtr pDoc
= boost::dynamic_pointer_cast
< libcmis::Document
>( getObject( xEnv
) );
1113 if ( pDoc
.get( ) == nullptr )
1115 ucbhelper::cancelCommandExecution(
1116 ucb::IOErrorCode_GENERAL
,
1117 uno::Sequence
< uno::Any
>( 0 ),
1119 "Checkout only supported by documents" );
1121 libcmis::DocumentPtr pPwc
= pDoc
->checkOut( );
1123 // Compute the URL of the Private Working Copy (PWC)
1124 URL
aCmisUrl( m_sURL
);
1125 std::vector
< std::string
> aPaths
= pPwc
->getPaths( );
1126 if ( !aPaths
.empty() )
1128 auto sPath
= aPaths
.front( );
1129 aCmisUrl
.setObjectPath( STD_TO_OUSTR( sPath
) );
1133 // We may have unfiled PWC depending on the server, those
1134 // won't have any path, use their ID instead
1135 auto sId
= pPwc
->getId( );
1136 aCmisUrl
.setObjectId( STD_TO_OUSTR( sId
) );
1138 aRet
= aCmisUrl
.asString( );
1140 catch ( const libcmis::Exception
& e
)
1142 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1143 ucbhelper::cancelCommandExecution(
1144 ucb::IOErrorCode_GENERAL
,
1145 uno::Sequence
< uno::Any
>( 0 ),
1147 o3tl::runtimeToOUString(e
.what()));
1152 OUString
Content::cancelCheckOut( const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1157 libcmis::DocumentPtr pPwc
= boost::dynamic_pointer_cast
< libcmis::Document
>( getObject( xEnv
) );
1158 if ( pPwc
.get( ) == nullptr )
1160 ucbhelper::cancelCommandExecution(
1161 ucb::IOErrorCode_GENERAL
,
1162 uno::Sequence
< uno::Any
>( 0 ),
1164 "CancelCheckout only supported by documents" );
1166 pPwc
->cancelCheckout( );
1168 // Get the Original document (latest version)
1169 std::vector
< libcmis::DocumentPtr
> aVersions
= pPwc
->getAllVersions( );
1170 for ( const auto& rVersion
: aVersions
)
1172 libcmis::DocumentPtr pVersion
= rVersion
;
1173 std::map
< std::string
, libcmis::PropertyPtr
> aProps
= pVersion
->getProperties( );
1174 bool bIsLatestVersion
= false;
1175 std::map
< std::string
, libcmis::PropertyPtr
>::iterator propIt
= aProps
.find( std::string( "cmis:isLatestVersion" ) );
1176 if ( propIt
!= aProps
.end( ) && !propIt
->second
->getBools( ).empty( ) )
1178 bIsLatestVersion
= propIt
->second
->getBools( ).front( );
1181 if ( bIsLatestVersion
)
1183 // Compute the URL of the Document
1184 URL
aCmisUrl( m_sURL
);
1185 std::vector
< std::string
> aPaths
= pVersion
->getPaths( );
1186 if ( !aPaths
.empty() )
1188 auto sPath
= aPaths
.front( );
1189 aCmisUrl
.setObjectPath( STD_TO_OUSTR( sPath
) );
1193 // We may have unfiled doc depending on the server, those
1194 // won't have any path, use their ID instead
1195 auto sId
= pVersion
->getId( );
1196 aCmisUrl
.setObjectId( STD_TO_OUSTR( sId
) );
1198 aRet
= aCmisUrl
.asString( );
1203 catch ( const libcmis::Exception
& e
)
1205 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1206 ucbhelper::cancelCommandExecution(
1207 ucb::IOErrorCode_GENERAL
,
1208 uno::Sequence
< uno::Any
>( 0 ),
1210 o3tl::runtimeToOUString(e
.what()));
1215 uno::Sequence
< document::CmisVersion
> Content::getAllVersions( const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1220 libcmis::DocumentPtr pDoc
= boost::dynamic_pointer_cast
< libcmis::Document
>( getObject( xEnv
) );
1221 if ( pDoc
.get( ) == nullptr )
1223 ucbhelper::cancelCommandExecution(
1224 ucb::IOErrorCode_GENERAL
,
1225 uno::Sequence
< uno::Any
>( 0 ),
1227 "Can not get the document" );
1229 std::vector
< libcmis::DocumentPtr
> aCmisVersions
= pDoc
->getAllVersions( );
1230 uno::Sequence
< document::CmisVersion
> aVersions( aCmisVersions
.size( ) );
1231 auto aVersionsRange
= asNonConstRange(aVersions
);
1233 for ( const auto& rVersion
: aCmisVersions
)
1235 libcmis::DocumentPtr pVersion
= rVersion
;
1236 aVersionsRange
[i
].Id
= STD_TO_OUSTR( pVersion
->getId( ) );
1237 aVersionsRange
[i
].Author
= STD_TO_OUSTR( pVersion
->getCreatedBy( ) );
1238 aVersionsRange
[i
].TimeStamp
= lcl_boostToUnoTime( pVersion
->getLastModificationDate( ) );
1239 aVersionsRange
[i
].Comment
= STD_TO_OUSTR( pVersion
->getStringProperty("cmis:checkinComment") );
1244 catch ( const libcmis::Exception
& e
)
1246 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1247 ucbhelper::cancelCommandExecution(
1248 ucb::IOErrorCode_GENERAL
,
1249 uno::Sequence
< uno::Any
>( 0 ),
1251 o3tl::runtimeToOUString(e
.what()));
1253 return uno::Sequence
< document::CmisVersion
> ( );
1256 void Content::transfer( const ucb::TransferInfo
& rTransferInfo
,
1257 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1259 // If the source isn't on the same CMIS repository, then simply copy
1260 INetURLObject
aSourceUrl( rTransferInfo
.SourceURL
);
1261 if ( aSourceUrl
.GetProtocol() != INetProtocol::Cmis
)
1263 OUString sSrcBindingUrl
= URL( rTransferInfo
.SourceURL
).getBindingUrl( );
1264 if ( sSrcBindingUrl
!= m_aURL
.getBindingUrl( ) )
1266 ucbhelper::cancelCommandExecution(
1268 ucb::InteractiveBadTransferURLException(
1269 "Unsupported URL scheme!",
1270 static_cast< cppu::OWeakObject
* >( this ) ) ),
1275 SAL_INFO( "ucb.ucp.cmis", "TODO - Content::transfer()" );
1278 void Content::insert( const uno::Reference
< io::XInputStream
> & xInputStream
,
1279 bool bReplaceExisting
, std::u16string_view rMimeType
,
1280 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1282 if ( !xInputStream
.is() )
1284 ucbhelper::cancelCommandExecution( uno::Any
1285 ( ucb::MissingInputStreamException
1286 ( OUString(), static_cast< cppu::OWeakObject
* >( this ) ) ),
1290 // For transient content, the URL is the one of the parent
1291 if ( !m_bTransient
)
1296 // Try to get the object from the server if there is any
1297 libcmis::FolderPtr pFolder
;
1300 pFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>( getObject( xEnv
) );
1302 catch ( const libcmis::Exception
& )
1306 if ( pFolder
== nullptr )
1309 libcmis::ObjectPtr object
;
1310 std::map
< std::string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
1311 if ( it
== m_pObjectProps
.end( ) )
1313 ucbhelper::cancelCommandExecution( uno::Any
1314 ( uno::RuntimeException( "Missing name property",
1315 static_cast< cppu::OWeakObject
* >( this ) ) ),
1318 auto newName
= it
->second
->getStrings( ).front( );
1319 auto newPath
= OUSTR_TO_STDSTR( m_sObjectPath
);
1320 if ( !newPath
.empty( ) && newPath
[ newPath
.size( ) - 1 ] != '/' )
1325 if ( !m_sObjectId
.isEmpty( ) )
1326 object
= getSession( xEnv
)->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
1328 object
= getSession( xEnv
)->getObjectByPath( newPath
);
1329 sNewPath
= STD_TO_OUSTR( newPath
);
1331 catch ( const libcmis::Exception
& )
1333 // Nothing matched the path
1336 if ( nullptr != object
.get( ) )
1338 // Are the base type matching?
1339 if ( object
->getBaseType( ) != m_pObjectType
->getBaseType( )->getId() )
1341 ucbhelper::cancelCommandExecution( uno::Any
1342 ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
1343 static_cast< cppu::OWeakObject
* >( this ) ) ),
1347 // Update the existing object if it's a document
1348 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( object
.get( ) );
1349 if ( nullptr != document
)
1351 boost::shared_ptr
< std::ostream
> pOut( new std::ostringstream ( std::ios_base::binary
| std::ios_base::in
| std::ios_base::out
) );
1352 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1353 copyData( xInputStream
, xOutput
);
1356 document
->setContentStream( pOut
, OUSTR_TO_STDSTR( rMimeType
), std::string( ), bReplaceExisting
);
1358 catch ( const libcmis::Exception
& )
1360 ucbhelper::cancelCommandExecution( uno::Any
1361 ( uno::RuntimeException( "Error when setting document content",
1362 static_cast< cppu::OWeakObject
* >( this ) ) ),
1369 // We need to create a brand new object... either folder or document
1370 bool bIsFolder
= getObjectType( xEnv
)->getBaseType( )->getId( ) == "cmis:folder";
1371 setCmisProperty( "cmis:objectTypeId", getObjectType( xEnv
)->getId( ), xEnv
);
1377 pFolder
->createFolder( m_pObjectProps
);
1378 sNewPath
= STD_TO_OUSTR( newPath
);
1380 catch ( const libcmis::Exception
& )
1382 ucbhelper::cancelCommandExecution( uno::Any
1383 ( uno::RuntimeException( "Error when creating folder",
1384 static_cast< cppu::OWeakObject
* >( this ) ) ),
1390 boost::shared_ptr
< std::ostream
> pOut( new std::ostringstream ( std::ios_base::binary
| std::ios_base::in
| std::ios_base::out
) );
1391 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1392 copyData( xInputStream
, xOutput
);
1395 pFolder
->createDocument( m_pObjectProps
, pOut
, OUSTR_TO_STDSTR( rMimeType
), std::string() );
1396 sNewPath
= STD_TO_OUSTR( newPath
);
1398 catch ( const libcmis::Exception
& )
1400 ucbhelper::cancelCommandExecution( uno::Any
1401 ( uno::RuntimeException( "Error when creating document",
1402 static_cast< cppu::OWeakObject
* >( this ) ) ),
1408 if ( sNewPath
.isEmpty( ) && m_sObjectId
.isEmpty( ) )
1411 // Update the current content: it's no longer transient
1412 m_sObjectPath
= sNewPath
;
1414 aUrl
.setObjectPath( m_sObjectPath
);
1415 aUrl
.setObjectId( m_sObjectId
);
1416 m_sURL
= aUrl
.asString( );
1418 m_pObjectType
.reset( );
1419 m_pObjectProps
.clear( );
1420 m_bTransient
= false;
1424 const int TRANSFER_BUFFER_SIZE
= 65536;
1426 void Content::copyData(
1427 const uno::Reference
< io::XInputStream
>& xIn
,
1428 const uno::Reference
< io::XOutputStream
>& xOut
)
1430 uno::Sequence
< sal_Int8
> theData( TRANSFER_BUFFER_SIZE
);
1432 while ( xIn
->readBytes( theData
, TRANSFER_BUFFER_SIZE
) > 0 )
1433 xOut
->writeBytes( theData
);
1435 xOut
->closeOutput();
1438 uno::Sequence
< uno::Any
> Content::setPropertyValues(
1439 const uno::Sequence
< beans::PropertyValue
>& rValues
,
1440 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1444 // Get the already set properties if possible
1445 if ( !m_bTransient
&& getObject( xEnv
).get( ) )
1447 m_pObjectProps
.clear( );
1448 m_pObjectType
= getObject( xEnv
)->getTypeDescription();
1451 catch ( const libcmis::Exception
& e
)
1453 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1454 ucbhelper::cancelCommandExecution(
1455 ucb::IOErrorCode_GENERAL
,
1456 uno::Sequence
< uno::Any
>( 0 ),
1458 o3tl::runtimeToOUString(e
.what()));
1461 sal_Int32 nCount
= rValues
.getLength();
1462 uno::Sequence
< uno::Any
> aRet( nCount
);
1463 auto aRetRange
= asNonConstRange(aRet
);
1464 bool bChanged
= false;
1465 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
1466 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1468 const beans::PropertyValue
& rValue
= pValues
[ n
];
1469 if ( rValue
.Name
== "ContentType" ||
1470 rValue
.Name
== "MediaType" ||
1471 rValue
.Name
== "IsDocument" ||
1472 rValue
.Name
== "IsFolder" ||
1473 rValue
.Name
== "Size" ||
1474 rValue
.Name
== "CreatableContentsInfo" )
1476 lang::IllegalAccessException
e ( "Property is read-only!",
1477 static_cast< cppu::OWeakObject
* >( this ) );
1478 aRetRange
[ n
] <<= e
;
1480 else if ( rValue
.Name
== "Title" )
1483 if (!( rValue
.Value
>>= aNewTitle
))
1485 aRetRange
[ n
] <<= beans::IllegalTypeException
1486 ( "Property value has wrong type!",
1487 static_cast< cppu::OWeakObject
* >( this ) );
1491 if ( aNewTitle
.isEmpty() )
1493 aRetRange
[ n
] <<= lang::IllegalArgumentException
1494 ( "Empty title not allowed!",
1495 static_cast< cppu::OWeakObject
* >( this ), -1 );
1500 setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle
), xEnv
);
1505 SAL_INFO( "ucb.ucp.cmis", "Couldn't set property: " << rValue
.Name
);
1506 lang::IllegalAccessException
e ( "Property is read-only!",
1507 static_cast< cppu::OWeakObject
* >( this ) );
1508 aRetRange
[ n
] <<= e
;
1514 if ( !m_bTransient
&& bChanged
)
1516 getObject( xEnv
)->updateProperties( m_pObjectProps
);
1519 catch ( const libcmis::Exception
& e
)
1521 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1522 ucbhelper::cancelCommandExecution(
1523 ucb::IOErrorCode_GENERAL
,
1524 uno::Sequence
< uno::Any
>( 0 ),
1526 o3tl::runtimeToOUString(e
.what()));
1532 bool Content::feedSink( const uno::Reference
< uno::XInterface
>& xSink
,
1533 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1538 uno::Reference
< io::XOutputStream
> xOut(xSink
, uno::UNO_QUERY
);
1539 uno::Reference
< io::XActiveDataSink
> xDataSink(xSink
, uno::UNO_QUERY
);
1540 uno::Reference
< io::XActiveDataStreamer
> xDataStreamer( xSink
, uno::UNO_QUERY
);
1542 if ( !xOut
.is() && !xDataSink
.is() && ( !xDataStreamer
.is() || !xDataStreamer
->getStream().is() ) )
1545 if ( xDataStreamer
.is() && !xOut
.is() )
1546 xOut
= xDataStreamer
->getStream()->getOutputStream();
1550 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get() );
1555 boost::shared_ptr
< std::istream
> aIn
= document
->getContentStream( );
1557 uno::Reference
< io::XInputStream
> xIn
= new StdInputStream( aIn
);
1561 if ( xDataSink
.is() )
1562 xDataSink
->setInputStream( xIn
);
1563 else if ( xOut
.is() )
1564 copyData( xIn
, xOut
);
1566 catch ( const libcmis::Exception
& e
)
1568 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1569 ucbhelper::cancelCommandExecution(
1570 ucb::IOErrorCode_GENERAL
,
1571 uno::Sequence
< uno::Any
>( 0 ),
1573 o3tl::runtimeToOUString(e
.what()));
1579 uno::Sequence
< beans::Property
> Content::getProperties(
1580 const uno::Reference
< ucb::XCommandEnvironment
> & )
1582 static const beans::Property aGenericProperties
[] =
1584 beans::Property( "IsDocument",
1585 -1, cppu::UnoType
<bool>::get(),
1586 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1587 beans::Property( "IsFolder",
1588 -1, cppu::UnoType
<bool>::get(),
1589 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1590 beans::Property( "Title",
1591 -1, cppu::UnoType
<OUString
>::get(),
1592 beans::PropertyAttribute::BOUND
),
1593 beans::Property( "ObjectId",
1594 -1, cppu::UnoType
<OUString
>::get(),
1595 beans::PropertyAttribute::BOUND
),
1596 beans::Property( "TitleOnServer",
1597 -1, cppu::UnoType
<OUString
>::get(),
1598 beans::PropertyAttribute::BOUND
),
1599 beans::Property( "IsReadOnly",
1600 -1, cppu::UnoType
<bool>::get(),
1601 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1602 beans::Property( "DateCreated",
1603 -1, cppu::UnoType
<util::DateTime
>::get(),
1604 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1605 beans::Property( "DateModified",
1606 -1, cppu::UnoType
<util::DateTime
>::get(),
1607 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1608 beans::Property( "Size",
1609 -1, cppu::UnoType
<sal_Int64
>::get(),
1610 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1611 beans::Property( "CreatableContentsInfo",
1612 -1, cppu::UnoType
<uno::Sequence
< ucb::ContentInfo
>>::get(),
1613 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1614 beans::Property( "MediaType",
1615 -1, cppu::UnoType
<OUString
>::get(),
1616 beans::PropertyAttribute::BOUND
),
1617 beans::Property( "CmisProperties",
1618 -1, cppu::UnoType
<uno::Sequence
< document::CmisProperty
>>::get(),
1619 beans::PropertyAttribute::BOUND
),
1620 beans::Property( "IsVersionable",
1621 -1, cppu::UnoType
<bool>::get(),
1622 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1623 beans::Property( "CanCheckOut",
1624 -1, cppu::UnoType
<bool>::get(),
1625 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1626 beans::Property( "CanCancelCheckOut",
1627 -1, cppu::UnoType
<bool>::get(),
1628 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1629 beans::Property( "CanCheckIn",
1630 -1, cppu::UnoType
<bool>::get(),
1631 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1634 const int nProps
= SAL_N_ELEMENTS(aGenericProperties
);
1635 return uno::Sequence
< beans::Property
> ( aGenericProperties
, nProps
);
1638 uno::Sequence
< ucb::CommandInfo
> Content::getCommands(
1639 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1641 static const ucb::CommandInfo aCommandInfoTable
[] =
1643 // Required commands
1646 -1, cppu::UnoType
<void>::get() ),
1648 ( "getPropertySetInfo",
1649 -1, cppu::UnoType
<void>::get() ),
1651 ( "getPropertyValues",
1652 -1, cppu::UnoType
<uno::Sequence
< beans::Property
>>::get() ),
1654 ( "setPropertyValues",
1655 -1, cppu::UnoType
<uno::Sequence
< beans::PropertyValue
>>::get() ),
1657 // Optional standard commands
1660 -1, cppu::UnoType
<bool>::get() ),
1663 -1, cppu::UnoType
<ucb::InsertCommandArgument2
>::get() ),
1666 -1, cppu::UnoType
<ucb::OpenCommandArgument2
>::get() ),
1668 // Mandatory CMIS-only commands
1669 ucb::CommandInfo ( "checkout", -1, cppu::UnoType
<void>::get() ),
1670 ucb::CommandInfo ( "cancelCheckout", -1, cppu::UnoType
<void>::get() ),
1671 ucb::CommandInfo ( "checkIn", -1,
1672 cppu::UnoType
<ucb::TransferInfo
>::get() ),
1673 ucb::CommandInfo ( "updateProperties", -1, cppu::UnoType
<void>::get() ),
1676 -1, cppu::UnoType
<uno::Sequence
< document::CmisVersion
>>::get() ),
1679 // Folder Only, omitted if not a folder
1682 -1, cppu::UnoType
<ucb::TransferInfo
>::get() ),
1684 ( "createNewContent",
1685 -1, cppu::UnoType
<ucb::ContentInfo
>::get() )
1688 const int nProps
= SAL_N_ELEMENTS( aCommandInfoTable
);
1689 return uno::Sequence
< ucb::CommandInfo
>(aCommandInfoTable
, isFolder( xEnv
) ? nProps
: nProps
- 2);
1692 OUString
Content::getParentURL( )
1694 SAL_INFO( "ucb.ucp.cmis", "Content::getParentURL()" );
1695 OUString parentUrl
= "/";
1696 if ( m_sObjectPath
== "/" )
1700 INetURLObject
aUrl( m_sURL
);
1701 if ( aUrl
.getSegmentCount( ) > 0 )
1703 URL
aCmisUrl( m_sURL
);
1704 aUrl
.removeSegment( );
1705 aCmisUrl
.setObjectPath( aUrl
.GetURLPath( INetURLObject::DecodeMechanism::WithCharset
) );
1706 parentUrl
= aCmisUrl
.asString( );
1712 XTYPEPROVIDER_COMMON_IMPL( Content
);
1714 void SAL_CALL
Content::acquire() noexcept
1716 ContentImplHelper::acquire();
1719 void SAL_CALL
Content::release() noexcept
1721 ContentImplHelper::release();
1724 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
1726 uno::Any aRet
= cppu::queryInterface( rType
, static_cast< ucb::XContentCreator
* >( this ) );
1727 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface(rType
);
1730 OUString SAL_CALL
Content::getImplementationName()
1732 return "com.sun.star.comp.CmisContent";
1735 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
1737 uno::Sequence
<OUString
> aSNS
{ "com.sun.star.ucb.CmisContent" };
1741 OUString SAL_CALL
Content::getContentType()
1746 if (isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ))
1747 sRet
= CMIS_FOLDER_TYPE
;
1749 sRet
= CMIS_FILE_TYPE
;
1751 catch (const uno::RuntimeException
&)
1755 catch (const uno::Exception
& e
)
1757 uno::Any
a(cppu::getCaughtException());
1758 throw lang::WrappedTargetRuntimeException(
1759 "wrapped Exception " + e
.Message
,
1760 uno::Reference
<uno::XInterface
>(), a
);
1765 uno::Any SAL_CALL
Content::execute(
1766 const ucb::Command
& aCommand
,
1767 sal_Int32
/*CommandId*/,
1768 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1770 SAL_INFO( "ucb.ucp.cmis", "Content::execute( ) - " << aCommand
.Name
);
1773 if ( aCommand
.Name
== "getPropertyValues" )
1775 uno::Sequence
< beans::Property
> Properties
;
1776 if ( !( aCommand
.Argument
>>= Properties
) )
1777 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1778 aRet
<<= getPropertyValues( Properties
, xEnv
);
1780 else if ( aCommand
.Name
== "getPropertySetInfo" )
1781 aRet
<<= getPropertySetInfo( xEnv
, false );
1782 else if ( aCommand
.Name
== "getCommandInfo" )
1783 aRet
<<= getCommandInfo( xEnv
, false );
1784 else if ( aCommand
.Name
== "open" )
1786 ucb::OpenCommandArgument2 aOpenCommand
;
1787 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
1788 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1789 aRet
= open( aOpenCommand
, xEnv
);
1791 else if ( aCommand
.Name
== "transfer" )
1793 ucb::TransferInfo transferArgs
;
1794 if ( !( aCommand
.Argument
>>= transferArgs
) )
1795 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1796 transfer( transferArgs
, xEnv
);
1798 else if ( aCommand
.Name
== "setPropertyValues" )
1800 uno::Sequence
< beans::PropertyValue
> aProperties
;
1801 if ( !( aCommand
.Argument
>>= aProperties
) || !aProperties
.hasElements() )
1802 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1803 aRet
<<= setPropertyValues( aProperties
, xEnv
);
1805 else if (aCommand
.Name
== "createNewContent"
1806 && isFolder( xEnv
) )
1808 ucb::ContentInfo arg
;
1809 if ( !( aCommand
.Argument
>>= arg
) )
1810 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1811 aRet
<<= createNewContent( arg
);
1813 else if ( aCommand
.Name
== "insert" )
1815 ucb::InsertCommandArgument2 arg
;
1816 if ( !( aCommand
.Argument
>>= arg
) )
1818 ucb::InsertCommandArgument insertArg
;
1819 if ( !( aCommand
.Argument
>>= insertArg
) )
1820 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1822 arg
.Data
= insertArg
.Data
;
1823 arg
.ReplaceExisting
= insertArg
.ReplaceExisting
;
1825 // store the document id
1826 m_sObjectId
= arg
.DocumentId
;
1827 insert( arg
.Data
, arg
.ReplaceExisting
, arg
.MimeType
, xEnv
);
1829 else if ( aCommand
.Name
== "delete" )
1833 if ( !isFolder( xEnv
) )
1835 getObject( xEnv
)->remove( );
1839 libcmis::Folder
* folder
= dynamic_cast< libcmis::Folder
* >( getObject( xEnv
).get() );
1841 folder
->removeTree( );
1844 catch ( const libcmis::Exception
& e
)
1846 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1847 ucbhelper::cancelCommandExecution(
1848 ucb::IOErrorCode_GENERAL
,
1849 uno::Sequence
< uno::Any
>( 0 ),
1851 o3tl::runtimeToOUString(e
.what()));
1854 else if ( aCommand
.Name
== "checkout" )
1856 aRet
<<= checkOut( xEnv
);
1858 else if ( aCommand
.Name
== "cancelCheckout" )
1860 aRet
<<= cancelCheckOut( xEnv
);
1862 else if ( aCommand
.Name
== "checkin" )
1864 ucb::CheckinArgument aArg
;
1865 if ( !( aCommand
.Argument
>>= aArg
) )
1867 ucbhelper::cancelCommandExecution ( getBadArgExcept(), xEnv
);
1869 aRet
<<= checkIn( aArg
, xEnv
);
1871 else if ( aCommand
.Name
== "getAllVersions" )
1873 aRet
<<= getAllVersions( xEnv
);
1875 else if ( aCommand
.Name
== "updateProperties" )
1877 updateProperties( aCommand
.Argument
, xEnv
);
1881 SAL_INFO( "ucb.ucp.cmis", "Unknown command to execute" );
1883 ucbhelper::cancelCommandExecution
1884 ( uno::Any( ucb::UnsupportedCommandException
1886 static_cast< cppu::OWeakObject
* >( this ) ) ),
1893 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
1895 SAL_INFO( "ucb.ucp.cmis", "TODO - Content::abort()" );
1896 // TODO Implement me
1899 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
Content::queryCreatableContentsInfo()
1901 return queryCreatableContentsInfo( uno::Reference
< ucb::XCommandEnvironment
>() );
1904 uno::Reference
< ucb::XContent
> SAL_CALL
Content::createNewContent(
1905 const ucb::ContentInfo
& Info
)
1907 bool create_document
;
1909 if ( Info
.Type
== CMIS_FILE_TYPE
)
1910 create_document
= true;
1911 else if ( Info
.Type
== CMIS_FOLDER_TYPE
)
1912 create_document
= false;
1915 SAL_INFO( "ucb.ucp.cmis", "Unknown type of content to create" );
1916 return uno::Reference
< ucb::XContent
>();
1919 OUString sParentURL
= m_xIdentifier
->getContentIdentifier();
1921 // Set the parent URL for the transient objects
1922 uno::Reference
< ucb::XContentIdentifier
> xId(new ::ucbhelper::ContentIdentifier(sParentURL
));
1926 return new ::cmis::Content( m_xContext
, m_pProvider
, xId
, !create_document
);
1928 catch ( ucb::ContentCreationException
& )
1930 return uno::Reference
< ucb::XContent
>();
1934 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
1938 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
1940 static cppu::OTypeCollection s_aFolderCollection
1941 (CPPU_TYPE_REF( lang::XTypeProvider
),
1942 CPPU_TYPE_REF( lang::XServiceInfo
),
1943 CPPU_TYPE_REF( lang::XComponent
),
1944 CPPU_TYPE_REF( ucb::XContent
),
1945 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1946 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1947 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1948 CPPU_TYPE_REF( beans::XPropertyContainer
),
1949 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1950 CPPU_TYPE_REF( container::XChild
),
1951 CPPU_TYPE_REF( ucb::XContentCreator
) );
1952 return s_aFolderCollection
.getTypes();
1955 catch (const uno::RuntimeException
&)
1959 catch (const uno::Exception
& e
)
1961 uno::Any
a(cppu::getCaughtException());
1962 throw lang::WrappedTargetRuntimeException(
1963 "wrapped Exception " + e
.Message
,
1964 uno::Reference
<uno::XInterface
>(), a
);
1967 static cppu::OTypeCollection s_aFileCollection
1968 (CPPU_TYPE_REF( lang::XTypeProvider
),
1969 CPPU_TYPE_REF( lang::XServiceInfo
),
1970 CPPU_TYPE_REF( lang::XComponent
),
1971 CPPU_TYPE_REF( ucb::XContent
),
1972 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1973 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1974 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1975 CPPU_TYPE_REF( beans::XPropertyContainer
),
1976 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1977 CPPU_TYPE_REF( container::XChild
) );
1979 return s_aFileCollection
.getTypes();
1982 uno::Sequence
< ucb::ContentInfo
> Content::queryCreatableContentsInfo(
1983 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1987 if ( isFolder( xEnv
) )
1990 // Minimum set of props we really need
1991 uno::Sequence
< beans::Property
> props
1996 cppu::UnoType
<OUString
>::get(),
1997 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
2005 ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
|
2006 ucb::ContentInfoAttribute::KIND_DOCUMENT
),
2011 ucb::ContentInfoAttribute::KIND_FOLDER
,
2017 catch (const uno::RuntimeException
&)
2021 catch (const uno::Exception
& e
)
2023 uno::Any
a(cppu::getCaughtException());
2024 throw lang::WrappedTargetRuntimeException(
2025 "wrapped Exception " + e
.Message
,
2026 uno::Reference
<uno::XInterface
>(), a
);
2031 std::vector
< uno::Reference
< ucb::XContent
> > Content::getChildren( )
2033 std::vector
< uno::Reference
< ucb::XContent
> > results
;
2034 SAL_INFO( "ucb.ucp.cmis", "Content::getChildren() " << m_sURL
);
2036 libcmis::FolderPtr pFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>( getObject( uno::Reference
< ucb::XCommandEnvironment
>() ) );
2037 if ( nullptr != pFolder
)
2039 // Get the children from pObject
2042 std::vector
< libcmis::ObjectPtr
> children
= pFolder
->getChildren( );
2044 // Loop over the results
2045 for ( const auto& rChild
: children
)
2047 // TODO Cache the objects
2049 INetURLObject
aURL( m_sURL
);
2050 OUString sUser
= aURL
.GetUser( INetURLObject::DecodeMechanism::WithCharset
);
2053 OUString
sPath( m_sObjectPath
);
2054 if ( !sPath
.endsWith("/") )
2056 sPath
+= STD_TO_OUSTR( rChild
->getName( ) );
2057 OUString sId
= STD_TO_OUSTR( rChild
->getId( ) );
2059 aUrl
.setObjectId( sId
);
2060 aUrl
.setObjectPath( sPath
);
2061 aUrl
.setUsername( sUser
);
2063 uno::Reference
< ucb::XContentIdentifier
> xId
= new ucbhelper::ContentIdentifier( aUrl
.asString( ) );
2064 uno::Reference
< ucb::XContent
> xContent
= new Content( m_xContext
, m_pProvider
, xId
, rChild
);
2066 results
.push_back( xContent
);
2069 catch ( const libcmis::Exception
& e
)
2071 SAL_INFO( "ucb.ucp.cmis", "Exception thrown: " << e
.what() );
2078 void Content::setCmisProperty(const std::string
& rName
, const std::string
& rValue
, const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
2080 if ( !getObjectType( xEnv
).get( ) )
2083 std::map
< std::string
, libcmis::PropertyPtr
>::iterator propIt
= m_pObjectProps
.find(rName
);
2085 if ( propIt
== m_pObjectProps
.end( ) && getObjectType( xEnv
).get( ) )
2087 std::map
< std::string
, libcmis::PropertyTypePtr
> propsTypes
= getObjectType( xEnv
)->getPropertiesTypes( );
2088 std::map
< std::string
, libcmis::PropertyTypePtr
>::iterator typeIt
= propsTypes
.find(rName
);
2090 if ( typeIt
!= propsTypes
.end( ) )
2092 libcmis::PropertyTypePtr propType
= typeIt
->second
;
2093 libcmis::PropertyPtr
property( new libcmis::Property( propType
, { rValue
}) );
2094 m_pObjectProps
.insert(std::pair
< std::string
, libcmis::PropertyPtr
>(rName
, property
));
2097 else if ( propIt
!= m_pObjectProps
.end( ) )
2099 propIt
->second
->setValues( { rValue
} );
2104 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */