bump product version to 7.2.5.1
[LibreOffice.git] / ucb / source / ucp / cmis / cmis_content.cxx
blobb5fb4ac3bda3c58ac6f627bf2c62127654912ae3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <cstdio>
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>
36 #ifndef SYSTEM_CURL
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>
40 #endif
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;
72 using namespace std;
74 namespace
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;
94 return unoTime;
97 uno::Any lcl_cmisPropertyToUno( const libcmis::PropertyPtr& pProperty )
99 uno::Any aValue;
100 switch ( pProperty->getPropertyType( )->getType( ) )
102 default:
103 case libcmis::PropertyType::String:
105 vector< string > aCmisStrings = pProperty->getStrings( );
106 uno::Sequence< OUString > aStrings( aCmisStrings.size( ) );
107 OUString* aStringsArr = aStrings.getArray( );
108 sal_Int32 i = 0;
109 for ( const auto& rCmisStr : aCmisStrings )
111 aStringsArr[i++] = STD_TO_OUSTR( rCmisStr );
113 aValue <<= aStrings;
115 break;
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( );
121 sal_Int32 i = 0;
122 for ( const auto& rCmisLong : aCmisLongs )
124 aLongsArr[i++] = rCmisLong;
126 aValue <<= aLongs;
128 break;
129 case libcmis::PropertyType::Decimal:
131 vector< double > aCmisDoubles = pProperty->getDoubles( );
132 uno::Sequence< double > aDoubles = comphelper::containerToSequence(aCmisDoubles);
133 aValue <<= aDoubles;
135 break;
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( );
141 sal_Int32 i = 0;
142 for ( bool bCmisBool : aCmisBools )
144 aBoolsArr[i++] = bCmisBool;
146 aValue <<= aBools;
148 break;
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( );
154 sal_Int32 i = 0;
155 for ( const auto& rCmisTime : aCmisTimes )
157 aTimesArr[i++] = lcl_boostToUnoTime( rCmisTime );
159 aValue <<= aTimes;
161 break;
163 return aValue;
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;
183 value >>= 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;
191 value >>= 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;
199 value >>= 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;
207 value >>= 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;
215 value >>= 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 ) );
235 return property;
238 uno::Sequence< uno::Any > generateErrorArguments( const cmis::URL & rURL )
240 uno::Sequence< uno::Any > aArguments(3);
242 size_t i = 0;
243 aArguments[i++] <<= beans::PropertyValue(
244 "Binding URL",
245 - 1,
246 uno::makeAny( rURL.getBindingUrl() ),
247 beans::PropertyState_DIRECT_VALUE );
249 aArguments[i++] <<= beans::PropertyValue(
250 "Username",
252 uno::makeAny( rURL.getUsername() ),
253 beans::PropertyState_DIRECT_VALUE );
255 aArguments[i++] <<= beans::PropertyValue(
256 "Repository Id",
258 uno::makeAny( rURL.getRepositoryId() ),
259 beans::PropertyState_DIRECT_VALUE );
261 return aArguments;
265 namespace cmis
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 ),
277 m_bIsFolder( 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,
287 bool bIsFolder )
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( );
302 Content::~Content()
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 )
325 #ifndef SYSTEM_CURL
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 );
335 #endif
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
356 // user experience
357 bSkipInitialPWAuth = true;
358 rPassword = aAuthProvider.getRefreshToken(rUsername);
361 bool bIsDone = false;
363 while ( !bIsDone )
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),
406 xEnv);
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),
414 xEnv,
415 "error accessing a repository");
417 else
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());
428 bIsDone = true;
430 catch( const libcmis::Exception & e )
432 if ( e.getType() != "permissionDenied" )
434 SAL_INFO("ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what());
435 throw;
439 else
441 // Silently fail as the user cancelled the authentication
442 ucbhelper::cancelCommandExecution(
443 ucb::IOErrorCode_ABORT,
444 uno::Sequence< uno::Any >( 0 ),
445 xEnv );
446 throw uno::RuntimeException( );
450 return m_pSession;
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& )
472 if ( pParent )
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;
479 if ( pProperty )
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;
491 break;
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 ) )
512 return m_pObject;
514 catch ( uno::RuntimeException& )
516 return m_pObject;
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));
553 if (pParentFolder)
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())
559 m_pObject = *it;
563 if ( !m_pObject )
564 throw libcmis::Exception( "Object not found" );
567 else
569 m_pObject = getSession( xEnv )->getRootFolder( );
570 m_sObjectPath = "/";
571 m_sObjectId = OUString( );
575 return m_pObject;
578 bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv )
580 bool bIsFolder = false;
583 libcmis::ObjectPtr obj = getObject( xEnv );
584 if ( obj )
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 ),
594 xEnv,
595 OUString::createFromAscii( e.what( ) ) );
598 return bIsFolder;
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( ) );
633 return updateObj;
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 );
651 if ( obj )
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" );
658 else
659 xRow->appendVoid( rProp );
662 else if ( rProp.Name == "IsFolder" )
666 libcmis::ObjectPtr obj = getObject( xEnv );
667 if ( obj )
668 xRow->appendBoolean( rProp, obj->getBaseType( ) == "cmis:folder" );
669 else
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" );
676 else
677 xRow->appendVoid( rProp );
680 else if ( rProp.Name == "Title" )
682 OUString sTitle;
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( '/' );
712 if ( nPos >= 0 )
713 sTitle = sPath.copy( nPos + 1 );
716 if ( !sTitle.isEmpty( ) )
717 xRow->appendString( rProp, sTitle );
718 else
719 xRow->appendVoid( rProp );
721 else if ( rProp.Name == "ObjectId" )
723 OUString sId;
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 );
744 else
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 ) )
757 bReadOnly = true;
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() );
778 else
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() ) );
797 else
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( );
845 sal_Int32 i = 0;
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( ) )
863 default:
864 case libcmis::PropertyType::String:
865 pCmisProps[i].Type = CMIS_TYPE_STRING;
866 break;
867 case libcmis::PropertyType::Integer:
868 pCmisProps[i].Type = CMIS_TYPE_INTEGER;
869 break;
870 case libcmis::PropertyType::Decimal:
871 pCmisProps[i].Type = CMIS_TYPE_DECIMAL;
872 break;
873 case libcmis::PropertyType::Bool:
874 pCmisProps[i].Type = CMIS_TYPE_BOOL;
875 break;
876 case libcmis::PropertyType::DateTime:
877 pCmisProps[i].Type = CMIS_TYPE_DATETIME;
878 break;
880 ++i;
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;
909 if ( aAllowables )
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;
927 if ( aAllowables )
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;
945 if ( aAllowables )
947 bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckIn );
949 xRow->appendBoolean( rProp, bAllowed );
951 catch ( const libcmis::Exception& )
953 xRow->appendVoid( rProp );
956 else
957 SAL_INFO( "ucb.ucp.cmis", "Looking for unsupported property " << rProp.Name );
959 catch (const libcmis::Exception&)
961 xRow->appendVoid( rProp );
965 return xRow;
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);
987 uno::Any aRet;
989 bool bOpenFolder = (
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 );
999 aRet <<= xSet;
1001 else if ( rOpenCommand.Sink.is() )
1003 if (
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 ) ) ),
1012 xEnv );
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 ) ),
1026 xEnv );
1029 else
1030 SAL_INFO( "ucb.ucp.cmis", "Open falling through ..." );
1032 return aRet;
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 ),
1052 xEnv,
1053 OUString::createFromAscii( e.what() ) );
1056 libcmis::Document* pPwc = dynamic_cast< libcmis::Document* >( object.get( ) );
1057 if ( !pPwc )
1059 ucbhelper::cancelCommandExecution(
1060 ucb::IOErrorCode_GENERAL,
1061 uno::Sequence< uno::Any >( 0 ),
1062 xEnv,
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 ),
1084 xEnv,
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 ) );
1096 else
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 )
1108 OUString aRet;
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 ),
1118 xEnv,
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 ) );
1131 else
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 ),
1146 xEnv,
1147 o3tl::runtimeToOUString(e.what()));
1149 return aRet;
1152 OUString Content::cancelCheckOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1154 OUString aRet;
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 ),
1163 xEnv,
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 ) );
1191 else
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( );
1199 break;
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 ),
1209 xEnv,
1210 o3tl::runtimeToOUString(e.what()));
1212 return aRet;
1215 uno::Sequence< document::CmisVersion> Content::getAllVersions( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1219 // get the document
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 ),
1226 xEnv,
1227 "Can not get the document" );
1229 vector< libcmis::DocumentPtr > aCmisVersions = pDoc->getAllVersions( );
1230 uno::Sequence< document::CmisVersion > aVersions( aCmisVersions.size( ) );
1231 int i = 0;
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") );
1239 ++i;
1241 return aVersions;
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 ),
1249 xEnv,
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(
1266 uno::makeAny(
1267 ucb::InteractiveBadTransferURLException(
1268 "Unsupported URL scheme!",
1269 static_cast< cppu::OWeakObject * >( this ) ) ),
1270 xEnv );
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 ) ) ),
1286 xEnv );
1289 // For transient content, the URL is the one of the parent
1290 if ( !m_bTransient )
1291 return;
1293 OUString sNewPath;
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 )
1306 return;
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 ) ) ),
1315 xEnv );
1317 string newName = it->second->getStrings( ).front( );
1318 string newPath = OUSTR_TO_STDSTR( m_sObjectPath );
1319 if ( !newPath.empty( ) && newPath[ newPath.size( ) - 1 ] != '/' )
1320 newPath += "/";
1321 newPath += newName;
1324 if ( !m_sObjectId.isEmpty( ) )
1325 object = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId) );
1326 else
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 ) ) ),
1343 xEnv );
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 ) ) ),
1362 xEnv );
1366 else
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 );
1372 if ( bIsFolder )
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 ) ) ),
1384 xEnv );
1387 else
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 ) ) ),
1402 xEnv );
1407 if ( sNewPath.isEmpty( ) && m_sObjectId.isEmpty( ) )
1408 return;
1410 // Update the current content: it's no longer transient
1411 m_sObjectPath = sNewPath;
1412 URL aUrl( m_sURL );
1413 aUrl.setObjectPath( m_sObjectPath );
1414 aUrl.setObjectId( m_sObjectId );
1415 m_sURL = aUrl.asString( );
1416 m_pObject.reset( );
1417 m_pObjectType.reset( );
1418 m_pObjectProps.clear( );
1419 m_bTransient = false;
1420 inserted();
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 ),
1456 xEnv,
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 ) );
1477 aRet[ n ] <<= e;
1479 else if ( rValue.Name == "Title" )
1481 OUString aNewTitle;
1482 if (!( rValue.Value >>= aNewTitle ))
1484 aRet[ n ] <<= beans::IllegalTypeException
1485 ( "Property value has wrong type!",
1486 static_cast< cppu::OWeakObject * >( this ) );
1487 continue;
1490 if ( aNewTitle.isEmpty() )
1492 aRet[ n ] <<= lang::IllegalArgumentException
1493 ( "Empty title not allowed!",
1494 static_cast< cppu::OWeakObject * >( this ), -1 );
1495 continue;
1499 setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle ), xEnv );
1500 bChanged = true;
1502 else
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 ) );
1507 aRet[ n ] <<= e;
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 ),
1524 xEnv,
1525 o3tl::runtimeToOUString(e.what()));
1528 return aRet;
1531 bool Content::feedSink( const uno::Reference< uno::XInterface>& xSink,
1532 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1534 if ( !xSink.is() )
1535 return false;
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() ) )
1542 return false;
1544 if ( xDataStreamer.is() && !xOut.is() )
1545 xOut = xDataStreamer->getStream()->getOutputStream();
1549 libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get() );
1551 if (!document)
1552 return false;
1554 boost::shared_ptr< istream > aIn = document->getContentStream( );
1556 uno::Reference< io::XInputStream > xIn = new StdInputStream( aIn );
1557 if( !xIn.is( ) )
1558 return false;
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 ),
1571 xEnv,
1572 o3tl::runtimeToOUString(e.what()));
1575 return true;
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
1643 ucb::CommandInfo
1644 ( "getCommandInfo",
1645 -1, cppu::UnoType<void>::get() ),
1646 ucb::CommandInfo
1647 ( "getPropertySetInfo",
1648 -1, cppu::UnoType<void>::get() ),
1649 ucb::CommandInfo
1650 ( "getPropertyValues",
1651 -1, cppu::UnoType<uno::Sequence< beans::Property >>::get() ),
1652 ucb::CommandInfo
1653 ( "setPropertyValues",
1654 -1, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get() ),
1656 // Optional standard commands
1657 ucb::CommandInfo
1658 ( "delete",
1659 -1, cppu::UnoType<bool>::get() ),
1660 ucb::CommandInfo
1661 ( "insert",
1662 -1, cppu::UnoType<ucb::InsertCommandArgument2>::get() ),
1663 ucb::CommandInfo
1664 ( "open",
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() ),
1673 ucb::CommandInfo
1674 ( "getAllVersions",
1675 -1, cppu::UnoType<uno::Sequence< document::CmisVersion >>::get() ),
1678 // Folder Only, omitted if not a folder
1679 ucb::CommandInfo
1680 ( "transfer",
1681 -1, cppu::UnoType<ucb::TransferInfo>::get() ),
1682 ucb::CommandInfo
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 == "/" )
1696 return parentUrl;
1697 else
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( );
1708 return parentUrl;
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" };
1737 return aSNS;
1740 OUString SAL_CALL Content::getContentType()
1742 OUString sRet;
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&)
1751 throw;
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);
1760 return sRet;
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 );
1769 uno::Any aRet;
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( );
1835 else
1837 libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get() );
1838 if (folder)
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 ),
1848 xEnv,
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 );
1877 else
1879 SAL_INFO( "ucb.ucp.cmis", "Unknown command to execute" );
1881 ucbhelper::cancelCommandExecution
1882 ( uno::makeAny( ucb::UnsupportedCommandException
1883 ( OUString(),
1884 static_cast< cppu::OWeakObject * >( this ) ) ),
1885 xEnv );
1888 return aRet;
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;
1911 else
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&)
1955 throw;
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
1992 "Title",
1994 cppu::UnoType<OUString>::get(),
1995 beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND
1999 return
2002 CMIS_FILE_TYPE,
2003 ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM |
2004 ucb::ContentInfoAttribute::KIND_DOCUMENT ),
2005 props
2008 CMIS_FOLDER_TYPE,
2009 ucb::ContentInfoAttribute::KIND_FOLDER,
2010 props
2015 catch (const uno::RuntimeException&)
2017 throw;
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);
2026 return {};
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 );
2050 URL aUrl( m_sURL );
2051 OUString sPath( m_sObjectPath );
2052 if ( !sPath.endsWith("/") )
2053 sPath += "/";
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() );
2073 return results;
2076 void Content::setCmisProperty(const std::string& rName, const std::string& rValue, const uno::Reference< ucb::XCommandEnvironment >& xEnv )
2078 if ( !getObjectType( xEnv ).get( ) )
2079 return;
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: */