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 <com/sun/star/beans/IllegalTypeException.hpp>
14 #include <com/sun/star/beans/PropertyAttribute.hpp>
15 #include <com/sun/star/beans/PropertyValue.hpp>
16 #include <com/sun/star/beans/XPropertySetInfo.hpp>
17 #include <com/sun/star/document/CmisProperty.hpp>
18 #include <com/sun/star/io/XActiveDataSink.hpp>
19 #include <com/sun/star/io/XActiveDataStreamer.hpp>
20 #include <com/sun/star/lang/IllegalAccessException.hpp>
21 #include <com/sun/star/lang/IllegalArgumentException.hpp>
22 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
23 #include <com/sun/star/task/InteractionClassification.hpp>
24 #include <com/sun/star/ucb/ContentInfo.hpp>
25 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
26 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
27 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
28 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
29 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
30 #include <com/sun/star/ucb/OpenMode.hpp>
31 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
32 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
33 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
34 #include <com/sun/star/ucb/XCommandInfo.hpp>
35 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
37 #include <com/sun/star/xml/crypto/XDigestContext.hpp>
38 #include <com/sun/star/xml/crypto/DigestID.hpp>
39 #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
42 #include <comphelper/processfactory.hxx>
43 #include <comphelper/sequence.hxx>
44 #include <cppuhelper/exc_hlp.hxx>
45 #include <cppuhelper/queryinterface.hxx>
46 #include <config_oauth2.h>
47 #include <o3tl/runtimetooustring.hxx>
48 #include <sal/log.hxx>
49 #include <tools/urlobj.hxx>
50 #include <tools/long.hxx>
51 #include <ucbhelper/cancelcommandexecution.hxx>
52 #include <ucbhelper/content.hxx>
53 #include <ucbhelper/contentidentifier.hxx>
54 #include <ucbhelper/propertyvalueset.hxx>
55 #include <ucbhelper/proxydecider.hxx>
56 #include <ucbhelper/macros.hxx>
57 #include <sax/tools/converter.hxx>
59 #include "auth_provider.hxx"
60 #include "certvalidation_handler.hxx"
61 #include "cmis_content.hxx"
62 #include "cmis_provider.hxx"
63 #include "cmis_resultset.hxx"
64 #include "cmis_strings.hxx"
65 #include "std_inputstream.hxx"
66 #include "std_outputstream.hxx"
68 #define OUSTR_TO_STDSTR(s) string( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() )
69 #define STD_TO_OUSTR( str ) OUString( str.c_str(), str.length( ), RTL_TEXTENCODING_UTF8 )
71 using namespace com::sun::star
;
76 util::DateTime
lcl_boostToUnoTime(const boost::posix_time::ptime
& boostTime
)
78 util::DateTime unoTime
;
79 unoTime
.Year
= boostTime
.date().year();
80 unoTime
.Month
= boostTime
.date().month();
81 unoTime
.Day
= boostTime
.date().day();
82 unoTime
.Hours
= boostTime
.time_of_day().hours();
83 unoTime
.Minutes
= boostTime
.time_of_day().minutes();
84 unoTime
.Seconds
= boostTime
.time_of_day().seconds();
86 // TODO FIXME maybe we should compile with BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
87 // to actually get nanosecond precision in boostTime?
88 // use this way rather than total_nanos to avoid overflows with 32-bit long
89 const tools::Long ticks
= boostTime
.time_of_day().fractional_seconds();
90 tools::Long nanoSeconds
= ticks
* ( 1000000000 / boost::posix_time::time_duration::ticks_per_second());
92 unoTime
.NanoSeconds
= nanoSeconds
;
97 uno::Any
lcl_cmisPropertyToUno( const libcmis::PropertyPtr
& pProperty
)
100 switch ( pProperty
->getPropertyType( )->getType( ) )
103 case libcmis::PropertyType::String
:
105 vector
< string
> aCmisStrings
= pProperty
->getStrings( );
106 uno::Sequence
< OUString
> aStrings( aCmisStrings
.size( ) );
107 OUString
* aStringsArr
= aStrings
.getArray( );
109 for ( const auto& rCmisStr
: aCmisStrings
)
111 aStringsArr
[i
++] = STD_TO_OUSTR( rCmisStr
);
116 case libcmis::PropertyType::Integer
:
118 vector
< long > aCmisLongs
= pProperty
->getLongs( );
119 uno::Sequence
< sal_Int64
> aLongs( aCmisLongs
.size( ) );
120 sal_Int64
* aLongsArr
= aLongs
.getArray( );
122 for ( const auto& rCmisLong
: aCmisLongs
)
124 aLongsArr
[i
++] = rCmisLong
;
129 case libcmis::PropertyType::Decimal
:
131 vector
< double > aCmisDoubles
= pProperty
->getDoubles( );
132 uno::Sequence
< double > aDoubles
= comphelper::containerToSequence(aCmisDoubles
);
136 case libcmis::PropertyType::Bool
:
138 vector
< bool > aCmisBools
= pProperty
->getBools( );
139 uno::Sequence
< sal_Bool
> aBools( aCmisBools
.size( ) );
140 sal_Bool
* aBoolsArr
= aBools
.getArray( );
142 for ( bool bCmisBool
: aCmisBools
)
144 aBoolsArr
[i
++] = bCmisBool
;
149 case libcmis::PropertyType::DateTime
:
151 vector
< boost::posix_time::ptime
> aCmisTimes
= pProperty
->getDateTimes( );
152 uno::Sequence
< util::DateTime
> aTimes( aCmisTimes
.size( ) );
153 util::DateTime
* aTimesArr
= aTimes
.getArray( );
155 for ( const auto& rCmisTime
: aCmisTimes
)
157 aTimesArr
[i
++] = lcl_boostToUnoTime( rCmisTime
);
166 libcmis::PropertyPtr
lcl_unoToCmisProperty(const document::CmisProperty
& prop
)
168 libcmis::PropertyTypePtr
propertyType( new libcmis::PropertyType( ) );
170 OUString id
= prop
.Id
;
171 OUString name
= prop
.Name
;
172 bool bUpdatable
= prop
.Updatable
;
173 bool bRequired
= prop
.Required
;
174 bool bMultiValued
= prop
.MultiValued
;
175 bool bOpenChoice
= prop
.OpenChoice
;
176 uno::Any value
= prop
.Value
;
177 std::vector
< std::string
> values
;
179 libcmis::PropertyType::Type type
= libcmis::PropertyType::String
;
180 if ( prop
.Type
== CMIS_TYPE_STRING
)
182 uno::Sequence
< OUString
> seqValue
;
184 std::transform(seqValue
.begin(), seqValue
.end(), std::back_inserter(values
),
185 [](const OUString
& rValue
) -> std::string
{ return OUSTR_TO_STDSTR( rValue
); });
186 type
= libcmis::PropertyType::String
;
188 else if ( prop
.Type
== CMIS_TYPE_BOOL
)
190 uno::Sequence
< sal_Bool
> seqValue
;
192 std::transform(seqValue
.begin(), seqValue
.end(), std::back_inserter(values
),
193 [](const bool nValue
) -> std::string
{ return OUSTR_TO_STDSTR( OUString::boolean( nValue
) ); });
194 type
= libcmis::PropertyType::Bool
;
196 else if ( prop
.Type
== CMIS_TYPE_INTEGER
)
198 uno::Sequence
< sal_Int64
> seqValue
;
200 std::transform(seqValue
.begin(), seqValue
.end(), std::back_inserter(values
),
201 [](const sal_Int64 nValue
) -> std::string
{ return OUSTR_TO_STDSTR( OUString::number( nValue
) ); });
202 type
= libcmis::PropertyType::Integer
;
204 else if ( prop
.Type
== CMIS_TYPE_DECIMAL
)
206 uno::Sequence
< double > seqValue
;
208 std::transform(seqValue
.begin(), seqValue
.end(), std::back_inserter(values
),
209 [](const double fValue
) -> std::string
{ return OUSTR_TO_STDSTR( OUString::number( fValue
) ); });
210 type
= libcmis::PropertyType::Decimal
;
212 else if ( prop
.Type
== CMIS_TYPE_DATETIME
)
214 uno::Sequence
< util::DateTime
> seqValue
;
216 std::transform(seqValue
.begin(), seqValue
.end(), std::back_inserter(values
),
217 [](const util::DateTime
& rValue
) -> std::string
{
218 OUStringBuffer aBuffer
;
219 ::sax::Converter::convertDateTime( aBuffer
, rValue
, nullptr );
220 return OUSTR_TO_STDSTR( aBuffer
.makeStringAndClear( ) );
222 type
= libcmis::PropertyType::DateTime
;
225 propertyType
->setId( OUSTR_TO_STDSTR( id
));
226 propertyType
->setDisplayName( OUSTR_TO_STDSTR( name
) );
227 propertyType
->setUpdatable( bUpdatable
);
228 propertyType
->setRequired( bRequired
);
229 propertyType
->setMultiValued( bMultiValued
);
230 propertyType
->setOpenChoice( bOpenChoice
);
231 propertyType
->setType( type
);
233 libcmis::PropertyPtr
property( new libcmis::Property( propertyType
, values
) );
238 uno::Sequence
< uno::Any
> generateErrorArguments( const cmis::URL
& rURL
)
240 uno::Sequence
< uno::Any
> aArguments(3);
243 aArguments
[i
++] <<= beans::PropertyValue(
246 uno::makeAny( rURL
.getBindingUrl() ),
247 beans::PropertyState_DIRECT_VALUE
);
249 aArguments
[i
++] <<= beans::PropertyValue(
252 uno::makeAny( rURL
.getUsername() ),
253 beans::PropertyState_DIRECT_VALUE
);
255 aArguments
[i
++] <<= beans::PropertyValue(
258 uno::makeAny( rURL
.getRepositoryId() ),
259 beans::PropertyState_DIRECT_VALUE
);
267 Content::Content( const uno::Reference
< uno::XComponentContext
>& rxContext
,
268 ContentProvider
*pProvider
, const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
269 libcmis::ObjectPtr
const & pObject
)
270 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
271 m_pProvider( pProvider
),
272 m_pSession( nullptr ),
273 m_pObject( pObject
),
274 m_sURL( Identifier
->getContentIdentifier( ) ),
275 m_aURL( Identifier
->getContentIdentifier( ) ),
276 m_bTransient( false ),
279 SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL
);
281 m_sObjectPath
= m_aURL
.getObjectPath( );
282 m_sObjectId
= m_aURL
.getObjectId( );
285 Content::Content( const uno::Reference
< uno::XComponentContext
>& rxContext
, ContentProvider
*pProvider
,
286 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
288 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
289 m_pProvider( pProvider
),
290 m_pSession( nullptr ),
291 m_sURL( Identifier
->getContentIdentifier( ) ),
292 m_aURL( Identifier
->getContentIdentifier( ) ),
293 m_bTransient( true ),
294 m_bIsFolder( bIsFolder
)
296 SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL
);
298 m_sObjectPath
= m_aURL
.getObjectPath( );
299 m_sObjectId
= m_aURL
.getObjectId( );
306 libcmis::Session
* Content::getSession( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
308 // Set the proxy if needed. We are doing that all times as the proxy data shouldn't be cached.
309 ucbhelper::InternetProxyDecider
aProxyDecider( m_xContext
);
310 INetURLObject
aBindingUrl( m_aURL
.getBindingUrl( ) );
311 const ucbhelper::InternetProxyServer
& rProxy
= aProxyDecider
.getProxy(
312 INetURLObject::GetScheme( aBindingUrl
.GetProtocol( ) ), aBindingUrl
.GetHost(), aBindingUrl
.GetPort() );
313 OUString sProxy
= rProxy
.aName
;
314 if ( rProxy
.nPort
> 0 )
315 sProxy
+= ":" + OUString::number( rProxy
.nPort
);
316 libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy
), string(), string(), string() );
318 // Look for a cached session, key is binding url + repo id
319 OUString sSessionId
= m_aURL
.getBindingUrl( ) + m_aURL
.getRepositoryId( );
320 if ( nullptr == m_pSession
)
321 m_pSession
= m_pProvider
->getSession( sSessionId
, m_aURL
.getUsername( ) );
323 if ( nullptr == m_pSession
)
326 // Initialize NSS library to make sure libcmis (and curl) can access CACERTs using NSS
327 // when using internal libcurl.
328 uno::Reference
< css::xml::crypto::XNSSInitializer
>
329 xNSSInitializer
= css::xml::crypto::NSSInitializer::create( m_xContext
);
331 uno::Reference
< css::xml::crypto::XDigestContext
> xDigestContext(
332 xNSSInitializer
->getDigestContext( css::xml::crypto::DigestID::SHA256
,
333 uno::Sequence
< beans::NamedValue
>() ),
334 uno::UNO_SET_THROW
);
337 // Set the SSL Validation handler
338 libcmis::CertValidationHandlerPtr
certHandler(
339 new CertValidationHandler( xEnv
, m_xContext
, aBindingUrl
.GetHost( ) ) );
340 libcmis::SessionFactory::setCertificateValidationHandler( certHandler
);
342 // Get the auth credentials
343 AuthProvider
aAuthProvider(xEnv
, m_xIdentifier
->getContentIdentifier(), m_aURL
.getBindingUrl());
344 AuthProvider::setXEnv( xEnv
);
346 string rUsername
= OUSTR_TO_STDSTR( m_aURL
.getUsername( ) );
347 string rPassword
= OUSTR_TO_STDSTR( m_aURL
.getPassword( ) );
349 bool bSkipInitialPWAuth
= false;
350 if (m_aURL
.getBindingUrl() == ONEDRIVE_BASE_URL
351 || m_aURL
.getBindingUrl() == GDRIVE_BASE_URL
)
353 // skip the initial username and pw-auth prompt, the only supported method is the
354 // auth-code-fallback one (login with your browser, copy code into the dialog)
355 // TODO: if LO were to listen on localhost for the request, it would be much nicer
357 bSkipInitialPWAuth
= true;
358 rPassword
= aAuthProvider
.getRefreshToken(rUsername
);
361 bool bIsDone
= false;
365 if (bSkipInitialPWAuth
|| aAuthProvider
.authenticationQuery(rUsername
, rPassword
))
367 // Initiate a CMIS session and register it as we found nothing
368 libcmis::OAuth2DataPtr oauth2Data
;
369 if ( m_aURL
.getBindingUrl( ) == GDRIVE_BASE_URL
)
371 // reset the skip, so user gets a chance to cancel
372 bSkipInitialPWAuth
= false;
373 libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback
);
374 oauth2Data
.reset( new libcmis::OAuth2Data(
375 GDRIVE_AUTH_URL
, GDRIVE_TOKEN_URL
,
376 GDRIVE_SCOPE
, GDRIVE_REDIRECT_URI
,
377 GDRIVE_CLIENT_ID
, GDRIVE_CLIENT_SECRET
) );
379 if ( m_aURL
.getBindingUrl().startsWith( ALFRESCO_CLOUD_BASE_URL
) )
380 oauth2Data
.reset( new libcmis::OAuth2Data(
381 ALFRESCO_CLOUD_AUTH_URL
, ALFRESCO_CLOUD_TOKEN_URL
,
382 ALFRESCO_CLOUD_SCOPE
, ALFRESCO_CLOUD_REDIRECT_URI
,
383 ALFRESCO_CLOUD_CLIENT_ID
, ALFRESCO_CLOUD_CLIENT_SECRET
) );
384 if ( m_aURL
.getBindingUrl( ) == ONEDRIVE_BASE_URL
)
386 // reset the skip, so user gets a chance to cancel
387 bSkipInitialPWAuth
= false;
388 libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback
);
389 oauth2Data
.reset( new libcmis::OAuth2Data(
390 ONEDRIVE_AUTH_URL
, ONEDRIVE_TOKEN_URL
,
391 ONEDRIVE_SCOPE
, ONEDRIVE_REDIRECT_URI
,
392 ONEDRIVE_CLIENT_ID
, ONEDRIVE_CLIENT_SECRET
) );
396 m_pSession
= libcmis::SessionFactory::createSession(
397 OUSTR_TO_STDSTR( m_aURL
.getBindingUrl( ) ),
398 rUsername
, rPassword
, OUSTR_TO_STDSTR( m_aURL
.getRepositoryId( ) ), false, oauth2Data
);
400 if ( m_pSession
== nullptr )
402 // Fail: session was not created
403 ucbhelper::cancelCommandExecution(
404 ucb::IOErrorCode_INVALID_DEVICE
,
405 generateErrorArguments(m_aURL
),
408 else if ( m_pSession
->getRepository() == nullptr )
410 // Fail: no repository or repository is invalid
411 ucbhelper::cancelCommandExecution(
412 ucb::IOErrorCode_INVALID_DEVICE
,
413 generateErrorArguments(m_aURL
),
415 "error accessing a repository");
419 m_pProvider
->registerSession(sSessionId
, m_aURL
.getUsername( ), m_pSession
);
420 if (m_aURL
.getBindingUrl() == ONEDRIVE_BASE_URL
421 || m_aURL
.getBindingUrl() == GDRIVE_BASE_URL
)
423 aAuthProvider
.storeRefreshToken(rUsername
, rPassword
,
424 m_pSession
->getRefreshToken());
430 catch( const libcmis::Exception
& e
)
432 if ( e
.getType() != "permissionDenied" )
434 SAL_INFO("ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what());
441 // Silently fail as the user cancelled the authentication
442 ucbhelper::cancelCommandExecution(
443 ucb::IOErrorCode_ABORT
,
444 uno::Sequence
< uno::Any
>( 0 ),
446 throw uno::RuntimeException( );
453 libcmis::ObjectTypePtr
const & Content::getObjectType( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
455 if ( nullptr == m_pObjectType
.get( ) && m_bTransient
)
457 string typeId
= m_bIsFolder
? "cmis:folder" : "cmis:document";
458 // The type to create needs to be fetched from the possible children types
459 // defined in the parent folder. Then, we'll pick up the first one we find matching
460 // cmis:folder or cmis:document (depending what we need to create).
461 // The easy case will work in most cases, but not on some servers (like Lotus Live)
462 libcmis::Folder
* pParent
= nullptr;
463 bool bTypeRestricted
= false;
466 pParent
= dynamic_cast< libcmis::Folder
* >( getObject( xEnv
).get( ) );
468 catch ( const libcmis::Exception
& )
474 map
< string
, libcmis::PropertyPtr
>& aProperties
= pParent
->getProperties( );
475 map
< string
, libcmis::PropertyPtr
>::iterator it
= aProperties
.find( "cmis:allowedChildObjectTypeIds" );
476 if ( it
!= aProperties
.end( ) )
478 libcmis::PropertyPtr pProperty
= it
->second
;
481 vector
< string
> typesIds
= pProperty
->getStrings( );
482 for ( const auto& rType
: typesIds
)
484 bTypeRestricted
= true;
485 libcmis::ObjectTypePtr type
= getSession( xEnv
)->getType( rType
);
487 // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis
488 if ( type
->getBaseType( )->getId( ) == typeId
)
490 m_pObjectType
= type
;
498 if ( !bTypeRestricted
)
499 m_pObjectType
= getSession( xEnv
)->getType( typeId
);
501 return m_pObjectType
;
505 libcmis::ObjectPtr
const & Content::getObject( const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
507 // can't get the session for some reason
508 // the recent file opening at start up is an example.
511 if ( !getSession( xEnv
) )
514 catch ( uno::RuntimeException
& )
518 if ( !m_pObject
.get() )
520 if ( !m_sObjectId
.isEmpty( ) )
524 m_pObject
= getSession( xEnv
)->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
526 catch ( const libcmis::Exception
& )
528 SAL_INFO( "ucb.ucp.cmis", "object: " << OUSTR_TO_STDSTR(m_sObjectId
));
529 throw libcmis::Exception( "Object not found" );
532 else if (!(m_sObjectPath
.isEmpty() || m_sObjectPath
== "/"))
536 m_pObject
= getSession( xEnv
)->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath
) );
538 catch ( const libcmis::Exception
& )
540 // In some cases, getting the object from the path doesn't work,
541 // but getting the parent from its path and the get the child in the list is OK.
542 // It's weird, but needed to handle case where the path isn't the folders/files
543 // names separated by '/' (as in Lotus Live)
544 INetURLObject
aParentUrl( m_sURL
);
545 string sName
= OUSTR_TO_STDSTR( aParentUrl
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
) );
546 aParentUrl
.removeSegment( );
547 OUString sParentUrl
= aParentUrl
.GetMainURL( INetURLObject::DecodeMechanism::NONE
);
548 // Avoid infinite recursion if sParentUrl == m_sURL
549 if (sParentUrl
!= m_sURL
)
551 rtl::Reference
<Content
> xParent(new Content(m_xContext
, m_pProvider
, new ucbhelper::ContentIdentifier(sParentUrl
)));
552 libcmis::FolderPtr pParentFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>(xParent
->getObject(xEnv
));
555 vector
< libcmis::ObjectPtr
> children
= pParentFolder
->getChildren();
556 auto it
= std::find_if(children
.begin(), children
.end(),
557 [&sName
](const libcmis::ObjectPtr
& rChild
) { return rChild
->getName() == sName
; });
558 if (it
!= children
.end())
564 throw libcmis::Exception( "Object not found" );
569 m_pObject
= getSession( xEnv
)->getRootFolder( );
571 m_sObjectId
= OUString( );
578 bool Content::isFolder(const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
580 bool bIsFolder
= false;
583 libcmis::ObjectPtr obj
= getObject( xEnv
);
585 bIsFolder
= obj
->getBaseType( ) == "cmis:folder";
587 catch ( const libcmis::Exception
& e
)
589 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
591 ucbhelper::cancelCommandExecution(
592 ucb::IOErrorCode_GENERAL
,
593 uno::Sequence
< uno::Any
>( 0 ),
595 OUString::createFromAscii( e
.what( ) ) );
601 uno::Any
Content::getBadArgExcept()
603 return uno::makeAny( lang::IllegalArgumentException(
604 "Wrong argument type!",
605 static_cast< cppu::OWeakObject
* >( this ), -1) );
608 libcmis::ObjectPtr
Content::updateProperties(
609 const uno::Any
& iCmisProps
,
610 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
612 // Convert iCmisProps to Cmis Properties;
613 uno::Sequence
< document::CmisProperty
> aPropsSeq
;
614 iCmisProps
>>= aPropsSeq
;
615 map
< string
, libcmis::PropertyPtr
> aProperties
;
617 for ( const auto& rProp
: std::as_const(aPropsSeq
) )
619 std::string id
= OUSTR_TO_STDSTR( rProp
.Id
);
620 libcmis::PropertyPtr prop
= lcl_unoToCmisProperty( rProp
);
621 aProperties
.insert( std::pair
<string
, libcmis::PropertyPtr
>( id
, prop
) );
623 libcmis::ObjectPtr updateObj
;
626 updateObj
= getObject( xEnv
)->updateProperties( aProperties
);
628 catch ( const libcmis::Exception
& e
)
630 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: "<< e
.what( ) );
636 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
637 const uno::Sequence
< beans::Property
>& rProperties
,
638 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
640 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
= new ::ucbhelper::PropertyValueSet( m_xContext
);
642 for( const beans::Property
& rProp
: rProperties
)
646 if ( rProp
.Name
== "IsDocument" )
650 libcmis::ObjectPtr obj
= getObject( xEnv
);
652 xRow
->appendBoolean( rProp
, obj
->getBaseType( ) == "cmis:document" );
654 catch ( const libcmis::Exception
& )
656 if ( m_pObjectType
.get( ) )
657 xRow
->appendBoolean( rProp
, getObjectType( xEnv
)->getBaseType()->getId( ) == "cmis:document" );
659 xRow
->appendVoid( rProp
);
662 else if ( rProp
.Name
== "IsFolder" )
666 libcmis::ObjectPtr obj
= getObject( xEnv
);
668 xRow
->appendBoolean( rProp
, obj
->getBaseType( ) == "cmis:folder" );
670 xRow
->appendBoolean( rProp
, false );
672 catch ( const libcmis::Exception
& )
674 if ( m_pObjectType
.get( ) )
675 xRow
->appendBoolean( rProp
, getObjectType( xEnv
)->getBaseType()->getId( ) == "cmis:folder" );
677 xRow
->appendVoid( rProp
);
680 else if ( rProp
.Name
== "Title" )
685 sTitle
= STD_TO_OUSTR( getObject( xEnv
)->getName() );
687 catch ( const libcmis::Exception
& )
689 if ( !m_pObjectProps
.empty() )
691 map
< string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
692 if ( it
!= m_pObjectProps
.end( ) )
694 vector
< string
> values
= it
->second
->getStrings( );
695 if ( !values
.empty() )
696 sTitle
= STD_TO_OUSTR( values
.front( ) );
701 // Nothing worked... get it from the path
702 if ( sTitle
.isEmpty( ) )
704 OUString sPath
= m_sObjectPath
;
706 // Get rid of the trailing slash problem
707 if ( sPath
.endsWith("/") )
708 sPath
= sPath
.copy( 0, sPath
.getLength() - 1 );
710 // Get the last segment
711 sal_Int32 nPos
= sPath
.lastIndexOf( '/' );
713 sTitle
= sPath
.copy( nPos
+ 1 );
716 if ( !sTitle
.isEmpty( ) )
717 xRow
->appendString( rProp
, sTitle
);
719 xRow
->appendVoid( rProp
);
721 else if ( rProp
.Name
== "ObjectId" )
726 sId
= STD_TO_OUSTR( getObject( xEnv
)->getId() );
728 catch ( const libcmis::Exception
& )
730 if ( !m_pObjectProps
.empty() )
732 map
< string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:objectId" );
733 if ( it
!= m_pObjectProps
.end( ) )
735 vector
< string
> values
= it
->second
->getStrings( );
736 if ( !values
.empty() )
737 sId
= STD_TO_OUSTR( values
.front( ) );
742 if ( !sId
.isEmpty( ) )
743 xRow
->appendString( rProp
, sId
);
745 xRow
->appendVoid( rProp
);
747 else if ( rProp
.Name
== "TitleOnServer" )
749 xRow
->appendString( rProp
, m_sObjectPath
);
751 else if ( rProp
.Name
== "IsReadOnly" )
753 boost::shared_ptr
< libcmis::AllowableActions
> allowableActions
= getObject( xEnv
)->getAllowableActions( );
754 bool bReadOnly
= false;
755 if ( !allowableActions
->isAllowed( libcmis::ObjectAction::SetContentStream
) &&
756 !allowableActions
->isAllowed( libcmis::ObjectAction::CheckIn
) )
759 xRow
->appendBoolean( rProp
, bReadOnly
);
761 else if ( rProp
.Name
== "DateCreated" )
763 util::DateTime aTime
= lcl_boostToUnoTime( getObject( xEnv
)->getCreationDate( ) );
764 xRow
->appendTimestamp( rProp
, aTime
);
766 else if ( rProp
.Name
== "DateModified" )
768 util::DateTime aTime
= lcl_boostToUnoTime( getObject( xEnv
)->getLastModificationDate( ) );
769 xRow
->appendTimestamp( rProp
, aTime
);
771 else if ( rProp
.Name
== "Size" )
775 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get( ) );
776 if ( nullptr != document
)
777 xRow
->appendLong( rProp
, document
->getContentLength() );
779 xRow
->appendVoid( rProp
);
781 catch ( const libcmis::Exception
& )
783 xRow
->appendVoid( rProp
);
786 else if ( rProp
.Name
== "CreatableContentsInfo" )
788 xRow
->appendObject( rProp
, uno::makeAny( queryCreatableContentsInfo( xEnv
) ) );
790 else if ( rProp
.Name
== "MediaType" )
794 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get( ) );
795 if ( nullptr != document
)
796 xRow
->appendString( rProp
, STD_TO_OUSTR( document
->getContentType() ) );
798 xRow
->appendVoid( rProp
);
800 catch ( const libcmis::Exception
& )
802 xRow
->appendVoid( rProp
);
805 else if ( rProp
.Name
== "IsVolume" )
807 xRow
->appendBoolean( rProp
, false );
809 else if ( rProp
.Name
== "IsRemote" )
811 xRow
->appendBoolean( rProp
, false );
813 else if ( rProp
.Name
== "IsRemoveable" )
815 xRow
->appendBoolean( rProp
, false );
817 else if ( rProp
.Name
== "IsFloppy" )
819 xRow
->appendBoolean( rProp
, false );
821 else if ( rProp
.Name
== "IsCompactDisc" )
823 xRow
->appendBoolean( rProp
, false );
825 else if ( rProp
.Name
== "IsHidden" )
827 xRow
->appendBoolean( rProp
, false );
829 else if ( rProp
.Name
== "TargetURL" )
831 xRow
->appendString( rProp
, "" );
833 else if ( rProp
.Name
== "BaseURI" )
835 xRow
->appendString( rProp
, m_aURL
.getBindingUrl( ) );
837 else if ( rProp
.Name
== "CmisProperties" )
841 libcmis::ObjectPtr object
= getObject( xEnv
);
842 map
< string
, libcmis::PropertyPtr
>& aProperties
= object
->getProperties( );
843 uno::Sequence
< document::CmisProperty
> aCmisProperties( aProperties
.size( ) );
844 document::CmisProperty
* pCmisProps
= aCmisProperties
.getArray( );
846 for ( const auto& [sId
, rProperty
] : aProperties
)
848 string sDisplayName
= rProperty
->getPropertyType()->getDisplayName( );
849 bool bUpdatable
= rProperty
->getPropertyType()->isUpdatable( );
850 bool bRequired
= rProperty
->getPropertyType()->isRequired( );
851 bool bMultiValued
= rProperty
->getPropertyType()->isMultiValued();
852 bool bOpenChoice
= rProperty
->getPropertyType()->isOpenChoice();
854 pCmisProps
[i
].Id
= STD_TO_OUSTR( sId
);
855 pCmisProps
[i
].Name
= STD_TO_OUSTR( sDisplayName
);
856 pCmisProps
[i
].Updatable
= bUpdatable
;
857 pCmisProps
[i
].Required
= bRequired
;
858 pCmisProps
[i
].MultiValued
= bMultiValued
;
859 pCmisProps
[i
].OpenChoice
= bOpenChoice
;
860 pCmisProps
[i
].Value
= lcl_cmisPropertyToUno( rProperty
);
861 switch ( rProperty
->getPropertyType( )->getType( ) )
864 case libcmis::PropertyType::String
:
865 pCmisProps
[i
].Type
= CMIS_TYPE_STRING
;
867 case libcmis::PropertyType::Integer
:
868 pCmisProps
[i
].Type
= CMIS_TYPE_INTEGER
;
870 case libcmis::PropertyType::Decimal
:
871 pCmisProps
[i
].Type
= CMIS_TYPE_DECIMAL
;
873 case libcmis::PropertyType::Bool
:
874 pCmisProps
[i
].Type
= CMIS_TYPE_BOOL
;
876 case libcmis::PropertyType::DateTime
:
877 pCmisProps
[i
].Type
= CMIS_TYPE_DATETIME
;
882 xRow
->appendObject( rProp
.Name
, uno::makeAny( aCmisProperties
) );
884 catch ( const libcmis::Exception
& )
886 xRow
->appendVoid( rProp
);
889 else if ( rProp
.Name
== "IsVersionable" )
893 libcmis::ObjectPtr object
= getObject( xEnv
);
894 bool bIsVersionable
= object
->getTypeDescription( )->isVersionable( );
895 xRow
->appendBoolean( rProp
, bIsVersionable
);
897 catch ( const libcmis::Exception
& )
899 xRow
->appendVoid( rProp
);
902 else if ( rProp
.Name
== "CanCheckOut" )
906 libcmis::ObjectPtr pObject
= getObject( xEnv
);
907 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
908 bool bAllowed
= false;
911 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckOut
);
913 xRow
->appendBoolean( rProp
, bAllowed
);
915 catch ( const libcmis::Exception
& )
917 xRow
->appendVoid( rProp
);
920 else if ( rProp
.Name
== "CanCancelCheckOut" )
924 libcmis::ObjectPtr pObject
= getObject( xEnv
);
925 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
926 bool bAllowed
= false;
929 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CancelCheckOut
);
931 xRow
->appendBoolean( rProp
, bAllowed
);
933 catch ( const libcmis::Exception
& )
935 xRow
->appendVoid( rProp
);
938 else if ( rProp
.Name
== "CanCheckIn" )
942 libcmis::ObjectPtr pObject
= getObject( xEnv
);
943 libcmis::AllowableActionsPtr aAllowables
= pObject
->getAllowableActions( );
944 bool bAllowed
= false;
947 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckIn
);
949 xRow
->appendBoolean( rProp
, bAllowed
);
951 catch ( const libcmis::Exception
& )
953 xRow
->appendVoid( rProp
);
957 SAL_INFO( "ucb.ucp.cmis", "Looking for unsupported property " << rProp
.Name
);
959 catch (const libcmis::Exception
&)
961 xRow
->appendVoid( rProp
);
968 uno::Any
Content::open(const ucb::OpenCommandArgument2
& rOpenCommand
,
969 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
971 bool bIsFolder
= isFolder( xEnv
);
973 // Handle the case of the non-existing file
974 if ( !getObject( xEnv
) )
976 uno::Sequence
< uno::Any
> aArgs( 1 );
977 aArgs
[ 0 ] <<= m_xIdentifier
->getContentIdentifier();
978 uno::Any aErr
= uno::makeAny(
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::makeAny ( 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::makeAny (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
< ostream
> pOut( new ostringstream ( ios_base::binary
| ios_base::in
| ios_base::out
) );
1067 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1068 copyData( xIn
, xOutput
);
1070 map
< 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 vector
< string
> aPaths
= pDoc
->getPaths( );
1091 if ( !aPaths
.empty() )
1093 string 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 string 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 vector
< string
> aPaths
= pPwc
->getPaths( );
1126 if ( !aPaths
.empty() )
1128 string 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 string 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 vector
< libcmis::DocumentPtr
> aVersions
= pPwc
->getAllVersions( );
1170 for ( const auto& rVersion
: aVersions
)
1172 libcmis::DocumentPtr pVersion
= rVersion
;
1173 map
< string
, libcmis::PropertyPtr
> aProps
= pVersion
->getProperties( );
1174 bool bIsLatestVersion
= false;
1175 map
< string
, libcmis::PropertyPtr
>::iterator propIt
= aProps
.find( 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 vector
< string
> aPaths
= pVersion
->getPaths( );
1186 if ( !aPaths
.empty() )
1188 string 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 string 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 vector
< libcmis::DocumentPtr
> aCmisVersions
= pDoc
->getAllVersions( );
1230 uno::Sequence
< document::CmisVersion
> aVersions( aCmisVersions
.size( ) );
1232 for ( const auto& rVersion
: aCmisVersions
)
1234 libcmis::DocumentPtr pVersion
= rVersion
;
1235 aVersions
[i
].Id
= STD_TO_OUSTR( pVersion
->getId( ) );
1236 aVersions
[i
].Author
= STD_TO_OUSTR( pVersion
->getCreatedBy( ) );
1237 aVersions
[i
].TimeStamp
= lcl_boostToUnoTime( pVersion
->getLastModificationDate( ) );
1238 aVersions
[i
].Comment
= STD_TO_OUSTR( pVersion
->getStringProperty("cmis:checkinComment") );
1243 catch ( const libcmis::Exception
& e
)
1245 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1246 ucbhelper::cancelCommandExecution(
1247 ucb::IOErrorCode_GENERAL
,
1248 uno::Sequence
< uno::Any
>( 0 ),
1250 o3tl::runtimeToOUString(e
.what()));
1252 return uno::Sequence
< document::CmisVersion
> ( );
1255 void Content::transfer( const ucb::TransferInfo
& rTransferInfo
,
1256 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1258 // If the source isn't on the same CMIS repository, then simply copy
1259 INetURLObject
aSourceUrl( rTransferInfo
.SourceURL
);
1260 if ( aSourceUrl
.GetProtocol() != INetProtocol::Cmis
)
1262 OUString sSrcBindingUrl
= URL( rTransferInfo
.SourceURL
).getBindingUrl( );
1263 if ( sSrcBindingUrl
!= m_aURL
.getBindingUrl( ) )
1265 ucbhelper::cancelCommandExecution(
1267 ucb::InteractiveBadTransferURLException(
1268 "Unsupported URL scheme!",
1269 static_cast< cppu::OWeakObject
* >( this ) ) ),
1274 SAL_INFO( "ucb.ucp.cmis", "TODO - Content::transfer()" );
1277 void Content::insert( const uno::Reference
< io::XInputStream
> & xInputStream
,
1278 bool bReplaceExisting
, std::u16string_view rMimeType
,
1279 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1281 if ( !xInputStream
.is() )
1283 ucbhelper::cancelCommandExecution( uno::makeAny
1284 ( ucb::MissingInputStreamException
1285 ( OUString(), static_cast< cppu::OWeakObject
* >( this ) ) ),
1289 // For transient content, the URL is the one of the parent
1290 if ( !m_bTransient
)
1295 // Try to get the object from the server if there is any
1296 libcmis::FolderPtr pFolder
;
1299 pFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>( getObject( xEnv
) );
1301 catch ( const libcmis::Exception
& )
1305 if ( pFolder
== nullptr )
1308 libcmis::ObjectPtr object
;
1309 map
< string
, libcmis::PropertyPtr
>::iterator it
= m_pObjectProps
.find( "cmis:name" );
1310 if ( it
== m_pObjectProps
.end( ) )
1312 ucbhelper::cancelCommandExecution( uno::makeAny
1313 ( uno::RuntimeException( "Missing name property",
1314 static_cast< cppu::OWeakObject
* >( this ) ) ),
1317 string newName
= it
->second
->getStrings( ).front( );
1318 string newPath
= OUSTR_TO_STDSTR( m_sObjectPath
);
1319 if ( !newPath
.empty( ) && newPath
[ newPath
.size( ) - 1 ] != '/' )
1324 if ( !m_sObjectId
.isEmpty( ) )
1325 object
= getSession( xEnv
)->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
1327 object
= getSession( xEnv
)->getObjectByPath( newPath
);
1328 sNewPath
= STD_TO_OUSTR( newPath
);
1330 catch ( const libcmis::Exception
& )
1332 // Nothing matched the path
1335 if ( nullptr != object
.get( ) )
1337 // Are the base type matching?
1338 if ( object
->getBaseType( ) != m_pObjectType
->getBaseType( )->getId() )
1340 ucbhelper::cancelCommandExecution( uno::makeAny
1341 ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
1342 static_cast< cppu::OWeakObject
* >( this ) ) ),
1346 // Update the existing object if it's a document
1347 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( object
.get( ) );
1348 if ( nullptr != document
)
1350 boost::shared_ptr
< ostream
> pOut( new ostringstream ( ios_base::binary
| ios_base::in
| ios_base::out
) );
1351 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1352 copyData( xInputStream
, xOutput
);
1355 document
->setContentStream( pOut
, OUSTR_TO_STDSTR( rMimeType
), string( ), bReplaceExisting
);
1357 catch ( const libcmis::Exception
& )
1359 ucbhelper::cancelCommandExecution( uno::makeAny
1360 ( uno::RuntimeException( "Error when setting document content",
1361 static_cast< cppu::OWeakObject
* >( this ) ) ),
1368 // We need to create a brand new object... either folder or document
1369 bool bIsFolder
= getObjectType( xEnv
)->getBaseType( )->getId( ) == "cmis:folder";
1370 setCmisProperty( "cmis:objectTypeId", getObjectType( xEnv
)->getId( ), xEnv
);
1376 pFolder
->createFolder( m_pObjectProps
);
1377 sNewPath
= STD_TO_OUSTR( newPath
);
1379 catch ( const libcmis::Exception
& )
1381 ucbhelper::cancelCommandExecution( uno::makeAny
1382 ( uno::RuntimeException( "Error when creating folder",
1383 static_cast< cppu::OWeakObject
* >( this ) ) ),
1389 boost::shared_ptr
< ostream
> pOut( new ostringstream ( ios_base::binary
| ios_base::in
| ios_base::out
) );
1390 uno::Reference
< io::XOutputStream
> xOutput
= new StdOutputStream( pOut
);
1391 copyData( xInputStream
, xOutput
);
1394 pFolder
->createDocument( m_pObjectProps
, pOut
, OUSTR_TO_STDSTR( rMimeType
), string() );
1395 sNewPath
= STD_TO_OUSTR( newPath
);
1397 catch ( const libcmis::Exception
& )
1399 ucbhelper::cancelCommandExecution( uno::makeAny
1400 ( uno::RuntimeException( "Error when creating document",
1401 static_cast< cppu::OWeakObject
* >( this ) ) ),
1407 if ( sNewPath
.isEmpty( ) && m_sObjectId
.isEmpty( ) )
1410 // Update the current content: it's no longer transient
1411 m_sObjectPath
= sNewPath
;
1413 aUrl
.setObjectPath( m_sObjectPath
);
1414 aUrl
.setObjectId( m_sObjectId
);
1415 m_sURL
= aUrl
.asString( );
1417 m_pObjectType
.reset( );
1418 m_pObjectProps
.clear( );
1419 m_bTransient
= false;
1423 const int TRANSFER_BUFFER_SIZE
= 65536;
1425 void Content::copyData(
1426 const uno::Reference
< io::XInputStream
>& xIn
,
1427 const uno::Reference
< io::XOutputStream
>& xOut
)
1429 uno::Sequence
< sal_Int8
> theData( TRANSFER_BUFFER_SIZE
);
1431 while ( xIn
->readBytes( theData
, TRANSFER_BUFFER_SIZE
) > 0 )
1432 xOut
->writeBytes( theData
);
1434 xOut
->closeOutput();
1437 uno::Sequence
< uno::Any
> Content::setPropertyValues(
1438 const uno::Sequence
< beans::PropertyValue
>& rValues
,
1439 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1443 // Get the already set properties if possible
1444 if ( !m_bTransient
&& getObject( xEnv
).get( ) )
1446 m_pObjectProps
.clear( );
1447 m_pObjectType
= getObject( xEnv
)->getTypeDescription();
1450 catch ( const libcmis::Exception
& e
)
1452 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1453 ucbhelper::cancelCommandExecution(
1454 ucb::IOErrorCode_GENERAL
,
1455 uno::Sequence
< uno::Any
>( 0 ),
1457 o3tl::runtimeToOUString(e
.what()));
1460 sal_Int32 nCount
= rValues
.getLength();
1461 uno::Sequence
< uno::Any
> aRet( nCount
);
1463 bool bChanged
= false;
1464 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
1465 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1467 const beans::PropertyValue
& rValue
= pValues
[ n
];
1468 if ( rValue
.Name
== "ContentType" ||
1469 rValue
.Name
== "MediaType" ||
1470 rValue
.Name
== "IsDocument" ||
1471 rValue
.Name
== "IsFolder" ||
1472 rValue
.Name
== "Size" ||
1473 rValue
.Name
== "CreatableContentsInfo" )
1475 lang::IllegalAccessException
e ( "Property is read-only!",
1476 static_cast< cppu::OWeakObject
* >( this ) );
1479 else if ( rValue
.Name
== "Title" )
1482 if (!( rValue
.Value
>>= aNewTitle
))
1484 aRet
[ n
] <<= beans::IllegalTypeException
1485 ( "Property value has wrong type!",
1486 static_cast< cppu::OWeakObject
* >( this ) );
1490 if ( aNewTitle
.isEmpty() )
1492 aRet
[ n
] <<= lang::IllegalArgumentException
1493 ( "Empty title not allowed!",
1494 static_cast< cppu::OWeakObject
* >( this ), -1 );
1499 setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle
), xEnv
);
1504 SAL_INFO( "ucb.ucp.cmis", "Couldn't set property: " << rValue
.Name
);
1505 lang::IllegalAccessException
e ( "Property is read-only!",
1506 static_cast< cppu::OWeakObject
* >( this ) );
1513 if ( !m_bTransient
&& bChanged
)
1515 getObject( xEnv
)->updateProperties( m_pObjectProps
);
1518 catch ( const libcmis::Exception
& e
)
1520 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1521 ucbhelper::cancelCommandExecution(
1522 ucb::IOErrorCode_GENERAL
,
1523 uno::Sequence
< uno::Any
>( 0 ),
1525 o3tl::runtimeToOUString(e
.what()));
1531 bool Content::feedSink( const uno::Reference
< uno::XInterface
>& xSink
,
1532 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1537 uno::Reference
< io::XOutputStream
> xOut(xSink
, uno::UNO_QUERY
);
1538 uno::Reference
< io::XActiveDataSink
> xDataSink(xSink
, uno::UNO_QUERY
);
1539 uno::Reference
< io::XActiveDataStreamer
> xDataStreamer( xSink
, uno::UNO_QUERY
);
1541 if ( !xOut
.is() && !xDataSink
.is() && ( !xDataStreamer
.is() || !xDataStreamer
->getStream().is() ) )
1544 if ( xDataStreamer
.is() && !xOut
.is() )
1545 xOut
= xDataStreamer
->getStream()->getOutputStream();
1549 libcmis::Document
* document
= dynamic_cast< libcmis::Document
* >( getObject( xEnv
).get() );
1554 boost::shared_ptr
< istream
> aIn
= document
->getContentStream( );
1556 uno::Reference
< io::XInputStream
> xIn
= new StdInputStream( aIn
);
1560 if ( xDataSink
.is() )
1561 xDataSink
->setInputStream( xIn
);
1562 else if ( xOut
.is() )
1563 copyData( xIn
, xOut
);
1565 catch ( const libcmis::Exception
& e
)
1567 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1568 ucbhelper::cancelCommandExecution(
1569 ucb::IOErrorCode_GENERAL
,
1570 uno::Sequence
< uno::Any
>( 0 ),
1572 o3tl::runtimeToOUString(e
.what()));
1578 uno::Sequence
< beans::Property
> Content::getProperties(
1579 const uno::Reference
< ucb::XCommandEnvironment
> & )
1581 static const beans::Property aGenericProperties
[] =
1583 beans::Property( "IsDocument",
1584 -1, cppu::UnoType
<bool>::get(),
1585 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1586 beans::Property( "IsFolder",
1587 -1, cppu::UnoType
<bool>::get(),
1588 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1589 beans::Property( "Title",
1590 -1, cppu::UnoType
<OUString
>::get(),
1591 beans::PropertyAttribute::BOUND
),
1592 beans::Property( "ObjectId",
1593 -1, cppu::UnoType
<OUString
>::get(),
1594 beans::PropertyAttribute::BOUND
),
1595 beans::Property( "TitleOnServer",
1596 -1, cppu::UnoType
<OUString
>::get(),
1597 beans::PropertyAttribute::BOUND
),
1598 beans::Property( "IsReadOnly",
1599 -1, cppu::UnoType
<bool>::get(),
1600 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1601 beans::Property( "DateCreated",
1602 -1, cppu::UnoType
<util::DateTime
>::get(),
1603 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1604 beans::Property( "DateModified",
1605 -1, cppu::UnoType
<util::DateTime
>::get(),
1606 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1607 beans::Property( "Size",
1608 -1, cppu::UnoType
<sal_Int64
>::get(),
1609 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1610 beans::Property( "CreatableContentsInfo",
1611 -1, cppu::UnoType
<uno::Sequence
< ucb::ContentInfo
>>::get(),
1612 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1613 beans::Property( "MediaType",
1614 -1, cppu::UnoType
<OUString
>::get(),
1615 beans::PropertyAttribute::BOUND
),
1616 beans::Property( "CmisProperties",
1617 -1, cppu::UnoType
<uno::Sequence
< document::CmisProperty
>>::get(),
1618 beans::PropertyAttribute::BOUND
),
1619 beans::Property( "IsVersionable",
1620 -1, cppu::UnoType
<bool>::get(),
1621 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1622 beans::Property( "CanCheckOut",
1623 -1, cppu::UnoType
<bool>::get(),
1624 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1625 beans::Property( "CanCancelCheckOut",
1626 -1, cppu::UnoType
<bool>::get(),
1627 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1628 beans::Property( "CanCheckIn",
1629 -1, cppu::UnoType
<bool>::get(),
1630 beans::PropertyAttribute::BOUND
| beans::PropertyAttribute::READONLY
),
1633 const int nProps
= SAL_N_ELEMENTS(aGenericProperties
);
1634 return uno::Sequence
< beans::Property
> ( aGenericProperties
, nProps
);
1637 uno::Sequence
< ucb::CommandInfo
> Content::getCommands(
1638 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1640 static const ucb::CommandInfo aCommandInfoTable
[] =
1642 // Required commands
1645 -1, cppu::UnoType
<void>::get() ),
1647 ( "getPropertySetInfo",
1648 -1, cppu::UnoType
<void>::get() ),
1650 ( "getPropertyValues",
1651 -1, cppu::UnoType
<uno::Sequence
< beans::Property
>>::get() ),
1653 ( "setPropertyValues",
1654 -1, cppu::UnoType
<uno::Sequence
< beans::PropertyValue
>>::get() ),
1656 // Optional standard commands
1659 -1, cppu::UnoType
<bool>::get() ),
1662 -1, cppu::UnoType
<ucb::InsertCommandArgument2
>::get() ),
1665 -1, cppu::UnoType
<ucb::OpenCommandArgument2
>::get() ),
1667 // Mandatory CMIS-only commands
1668 ucb::CommandInfo ( "checkout", -1, cppu::UnoType
<void>::get() ),
1669 ucb::CommandInfo ( "cancelCheckout", -1, cppu::UnoType
<void>::get() ),
1670 ucb::CommandInfo ( "checkIn", -1,
1671 cppu::UnoType
<ucb::TransferInfo
>::get() ),
1672 ucb::CommandInfo ( "updateProperties", -1, cppu::UnoType
<void>::get() ),
1675 -1, cppu::UnoType
<uno::Sequence
< document::CmisVersion
>>::get() ),
1678 // Folder Only, omitted if not a folder
1681 -1, cppu::UnoType
<ucb::TransferInfo
>::get() ),
1683 ( "createNewContent",
1684 -1, cppu::UnoType
<ucb::ContentInfo
>::get() )
1687 const int nProps
= SAL_N_ELEMENTS( aCommandInfoTable
);
1688 return uno::Sequence
< ucb::CommandInfo
>(aCommandInfoTable
, isFolder( xEnv
) ? nProps
: nProps
- 2);
1691 OUString
Content::getParentURL( )
1693 SAL_INFO( "ucb.ucp.cmis", "Content::getParentURL()" );
1694 OUString parentUrl
= "/";
1695 if ( m_sObjectPath
== "/" )
1699 INetURLObject
aUrl( m_sURL
);
1700 if ( aUrl
.getSegmentCount( ) > 0 )
1702 URL
aCmisUrl( m_sURL
);
1703 aUrl
.removeSegment( );
1704 aCmisUrl
.setObjectPath( aUrl
.GetURLPath( INetURLObject::DecodeMechanism::WithCharset
) );
1705 parentUrl
= aCmisUrl
.asString( );
1711 XTYPEPROVIDER_COMMON_IMPL( Content
);
1713 void SAL_CALL
Content::acquire() noexcept
1715 ContentImplHelper::acquire();
1718 void SAL_CALL
Content::release() noexcept
1720 ContentImplHelper::release();
1723 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
1725 uno::Any aRet
= cppu::queryInterface( rType
, static_cast< ucb::XContentCreator
* >( this ) );
1726 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface(rType
);
1729 OUString SAL_CALL
Content::getImplementationName()
1731 return "com.sun.star.comp.CmisContent";
1734 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
1736 uno::Sequence
<OUString
> aSNS
{ "com.sun.star.ucb.CmisContent" };
1740 OUString SAL_CALL
Content::getContentType()
1745 sRet
= isFolder( uno::Reference
< ucb::XCommandEnvironment
>() )
1746 ? std::u16string_view(u
"" CMIS_FOLDER_TYPE
)
1747 : std::u16string_view(u
"" CMIS_FILE_TYPE
);
1749 catch (const uno::RuntimeException
&)
1753 catch (const uno::Exception
& e
)
1755 uno::Any
a(cppu::getCaughtException());
1756 throw lang::WrappedTargetRuntimeException(
1757 "wrapped Exception " + e
.Message
,
1758 uno::Reference
<uno::XInterface
>(), a
);
1763 uno::Any SAL_CALL
Content::execute(
1764 const ucb::Command
& aCommand
,
1765 sal_Int32
/*CommandId*/,
1766 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1768 SAL_INFO( "ucb.ucp.cmis", "Content::execute( ) - " << aCommand
.Name
);
1771 if ( aCommand
.Name
== "getPropertyValues" )
1773 uno::Sequence
< beans::Property
> Properties
;
1774 if ( !( aCommand
.Argument
>>= Properties
) )
1775 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1776 aRet
<<= getPropertyValues( Properties
, xEnv
);
1778 else if ( aCommand
.Name
== "getPropertySetInfo" )
1779 aRet
<<= getPropertySetInfo( xEnv
, false );
1780 else if ( aCommand
.Name
== "getCommandInfo" )
1781 aRet
<<= getCommandInfo( xEnv
, false );
1782 else if ( aCommand
.Name
== "open" )
1784 ucb::OpenCommandArgument2 aOpenCommand
;
1785 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
1786 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1787 aRet
= open( aOpenCommand
, xEnv
);
1789 else if ( aCommand
.Name
== "transfer" )
1791 ucb::TransferInfo transferArgs
;
1792 if ( !( aCommand
.Argument
>>= transferArgs
) )
1793 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1794 transfer( transferArgs
, xEnv
);
1796 else if ( aCommand
.Name
== "setPropertyValues" )
1798 uno::Sequence
< beans::PropertyValue
> aProperties
;
1799 if ( !( aCommand
.Argument
>>= aProperties
) || !aProperties
.hasElements() )
1800 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1801 aRet
<<= setPropertyValues( aProperties
, xEnv
);
1803 else if (aCommand
.Name
== "createNewContent"
1804 && isFolder( xEnv
) )
1806 ucb::ContentInfo arg
;
1807 if ( !( aCommand
.Argument
>>= arg
) )
1808 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1809 aRet
<<= createNewContent( arg
);
1811 else if ( aCommand
.Name
== "insert" )
1813 ucb::InsertCommandArgument2 arg
;
1814 if ( !( aCommand
.Argument
>>= arg
) )
1816 ucb::InsertCommandArgument insertArg
;
1817 if ( !( aCommand
.Argument
>>= insertArg
) )
1818 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv
);
1820 arg
.Data
= insertArg
.Data
;
1821 arg
.ReplaceExisting
= insertArg
.ReplaceExisting
;
1823 // store the document id
1824 m_sObjectId
= arg
.DocumentId
;
1825 insert( arg
.Data
, arg
.ReplaceExisting
, arg
.MimeType
, xEnv
);
1827 else if ( aCommand
.Name
== "delete" )
1831 if ( !isFolder( xEnv
) )
1833 getObject( xEnv
)->remove( );
1837 libcmis::Folder
* folder
= dynamic_cast< libcmis::Folder
* >( getObject( xEnv
).get() );
1839 folder
->removeTree( );
1842 catch ( const libcmis::Exception
& e
)
1844 SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e
.what( ) );
1845 ucbhelper::cancelCommandExecution(
1846 ucb::IOErrorCode_GENERAL
,
1847 uno::Sequence
< uno::Any
>( 0 ),
1849 o3tl::runtimeToOUString(e
.what()));
1852 else if ( aCommand
.Name
== "checkout" )
1854 aRet
<<= checkOut( xEnv
);
1856 else if ( aCommand
.Name
== "cancelCheckout" )
1858 aRet
<<= cancelCheckOut( xEnv
);
1860 else if ( aCommand
.Name
== "checkin" )
1862 ucb::CheckinArgument aArg
;
1863 if ( !( aCommand
.Argument
>>= aArg
) )
1865 ucbhelper::cancelCommandExecution ( getBadArgExcept(), xEnv
);
1867 aRet
<<= checkIn( aArg
, xEnv
);
1869 else if ( aCommand
.Name
== "getAllVersions" )
1871 aRet
<<= getAllVersions( xEnv
);
1873 else if ( aCommand
.Name
== "updateProperties" )
1875 updateProperties( aCommand
.Argument
, xEnv
);
1879 SAL_INFO( "ucb.ucp.cmis", "Unknown command to execute" );
1881 ucbhelper::cancelCommandExecution
1882 ( uno::makeAny( ucb::UnsupportedCommandException
1884 static_cast< cppu::OWeakObject
* >( this ) ) ),
1891 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
1893 SAL_INFO( "ucb.ucp.cmis", "TODO - Content::abort()" );
1894 // TODO Implement me
1897 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
Content::queryCreatableContentsInfo()
1899 return queryCreatableContentsInfo( uno::Reference
< ucb::XCommandEnvironment
>() );
1902 uno::Reference
< ucb::XContent
> SAL_CALL
Content::createNewContent(
1903 const ucb::ContentInfo
& Info
)
1905 bool create_document
;
1907 if ( Info
.Type
== CMIS_FILE_TYPE
)
1908 create_document
= true;
1909 else if ( Info
.Type
== CMIS_FOLDER_TYPE
)
1910 create_document
= false;
1913 SAL_INFO( "ucb.ucp.cmis", "Unknown type of content to create" );
1914 return uno::Reference
< ucb::XContent
>();
1917 OUString sParentURL
= m_xIdentifier
->getContentIdentifier();
1919 // Set the parent URL for the transient objects
1920 uno::Reference
< ucb::XContentIdentifier
> xId(new ::ucbhelper::ContentIdentifier(sParentURL
));
1924 return new ::cmis::Content( m_xContext
, m_pProvider
, xId
, !create_document
);
1926 catch ( ucb::ContentCreationException
& )
1928 return uno::Reference
< ucb::XContent
>();
1932 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
1936 if ( isFolder( uno::Reference
< ucb::XCommandEnvironment
>() ) )
1938 static cppu::OTypeCollection s_aFolderCollection
1939 (CPPU_TYPE_REF( lang::XTypeProvider
),
1940 CPPU_TYPE_REF( lang::XServiceInfo
),
1941 CPPU_TYPE_REF( lang::XComponent
),
1942 CPPU_TYPE_REF( ucb::XContent
),
1943 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1944 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1945 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1946 CPPU_TYPE_REF( beans::XPropertyContainer
),
1947 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1948 CPPU_TYPE_REF( container::XChild
),
1949 CPPU_TYPE_REF( ucb::XContentCreator
) );
1950 return s_aFolderCollection
.getTypes();
1953 catch (const uno::RuntimeException
&)
1957 catch (const uno::Exception
& e
)
1959 uno::Any
a(cppu::getCaughtException());
1960 throw lang::WrappedTargetRuntimeException(
1961 "wrapped Exception " + e
.Message
,
1962 uno::Reference
<uno::XInterface
>(), a
);
1965 static cppu::OTypeCollection s_aFileCollection
1966 (CPPU_TYPE_REF( lang::XTypeProvider
),
1967 CPPU_TYPE_REF( lang::XServiceInfo
),
1968 CPPU_TYPE_REF( lang::XComponent
),
1969 CPPU_TYPE_REF( ucb::XContent
),
1970 CPPU_TYPE_REF( ucb::XCommandProcessor
),
1971 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
1972 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
1973 CPPU_TYPE_REF( beans::XPropertyContainer
),
1974 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
1975 CPPU_TYPE_REF( container::XChild
) );
1977 return s_aFileCollection
.getTypes();
1980 uno::Sequence
< ucb::ContentInfo
> Content::queryCreatableContentsInfo(
1981 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1985 if ( isFolder( xEnv
) )
1988 // Minimum set of props we really need
1989 uno::Sequence
< beans::Property
> props
1994 cppu::UnoType
<OUString
>::get(),
1995 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
2003 ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
|
2004 ucb::ContentInfoAttribute::KIND_DOCUMENT
),
2009 ucb::ContentInfoAttribute::KIND_FOLDER
,
2015 catch (const uno::RuntimeException
&)
2019 catch (const uno::Exception
& e
)
2021 uno::Any
a(cppu::getCaughtException());
2022 throw lang::WrappedTargetRuntimeException(
2023 "wrapped Exception " + e
.Message
,
2024 uno::Reference
<uno::XInterface
>(), a
);
2029 std::vector
< uno::Reference
< ucb::XContent
> > Content::getChildren( )
2031 std::vector
< uno::Reference
< ucb::XContent
> > results
;
2032 SAL_INFO( "ucb.ucp.cmis", "Content::getChildren() " << m_sURL
);
2034 libcmis::FolderPtr pFolder
= boost::dynamic_pointer_cast
< libcmis::Folder
>( getObject( uno::Reference
< ucb::XCommandEnvironment
>() ) );
2035 if ( nullptr != pFolder
)
2037 // Get the children from pObject
2040 vector
< libcmis::ObjectPtr
> children
= pFolder
->getChildren( );
2042 // Loop over the results
2043 for ( const auto& rChild
: children
)
2045 // TODO Cache the objects
2047 INetURLObject
aURL( m_sURL
);
2048 OUString sUser
= aURL
.GetUser( INetURLObject::DecodeMechanism::WithCharset
);
2051 OUString
sPath( m_sObjectPath
);
2052 if ( !sPath
.endsWith("/") )
2054 sPath
+= STD_TO_OUSTR( rChild
->getName( ) );
2055 OUString sId
= STD_TO_OUSTR( rChild
->getId( ) );
2057 aUrl
.setObjectId( sId
);
2058 aUrl
.setObjectPath( sPath
);
2059 aUrl
.setUsername( sUser
);
2061 uno::Reference
< ucb::XContentIdentifier
> xId
= new ucbhelper::ContentIdentifier( aUrl
.asString( ) );
2062 uno::Reference
< ucb::XContent
> xContent
= new Content( m_xContext
, m_pProvider
, xId
, rChild
);
2064 results
.push_back( xContent
);
2067 catch ( const libcmis::Exception
& e
)
2069 SAL_INFO( "ucb.ucp.cmis", "Exception thrown: " << e
.what() );
2076 void Content::setCmisProperty(const std::string
& rName
, const std::string
& rValue
, const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
2078 if ( !getObjectType( xEnv
).get( ) )
2081 map
< string
, libcmis::PropertyPtr
>::iterator propIt
= m_pObjectProps
.find(rName
);
2082 vector
< string
> values
;
2083 values
.push_back(rValue
);
2085 if ( propIt
== m_pObjectProps
.end( ) && getObjectType( xEnv
).get( ) )
2087 map
< string
, libcmis::PropertyTypePtr
> propsTypes
= getObjectType( xEnv
)->getPropertiesTypes( );
2088 map
< 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
, values
) );
2094 m_pObjectProps
.insert(pair
< string
, libcmis::PropertyPtr
>(rName
, property
));
2097 else if ( propIt
!= m_pObjectProps
.end( ) )
2099 propIt
->second
->setValues( values
);
2104 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */