bump product version to 4.1.6.2
[LibreOffice.git] / ucb / source / ucp / cmis / cmis_content.cxx
blob1e4ff85cd18337cddb1cd6365f8600efc487596d
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>
12 #include <com/sun/star/beans/PropertyAttribute.hpp>
13 #include <com/sun/star/beans/PropertyValue.hpp>
14 #include <com/sun/star/beans/PropertyValues.hpp>
15 #include <com/sun/star/beans/XPropertySetInfo.hpp>
16 #include <com/sun/star/io/XActiveDataSink.hpp>
17 #include <com/sun/star/io/XActiveDataStreamer.hpp>
18 #include <com/sun/star/lang/IllegalAccessException.hpp>
19 #include <com/sun/star/task/InteractionClassification.hpp>
20 #include <com/sun/star/ucb/ContentInfo.hpp>
21 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
22 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
23 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
24 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
25 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
26 #include <com/sun/star/ucb/NameClash.hpp>
27 #include <com/sun/star/ucb/NameClashException.hpp>
28 #include <com/sun/star/ucb/OpenMode.hpp>
29 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
30 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
31 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
32 #include <com/sun/star/ucb/XCommandInfo.hpp>
33 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
35 #include <libcmis/document.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <ucbhelper/cancelcommandexecution.hxx>
39 #include <ucbhelper/content.hxx>
40 #include <ucbhelper/contentidentifier.hxx>
41 #include <ucbhelper/std_inputstream.hxx>
42 #include <ucbhelper/std_outputstream.hxx>
43 #include <ucbhelper/propertyvalueset.hxx>
44 #include <ucbhelper/proxydecider.hxx>
46 #include "auth_provider.hxx"
47 #include "cmis_content.hxx"
48 #include "cmis_provider.hxx"
49 #include "cmis_resultset.hxx"
51 #define OUSTR_TO_STDSTR(s) string( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() )
52 #define STD_TO_OUSTR( str ) OUString( str.c_str(), str.length( ), RTL_TEXTENCODING_UTF8 )
54 using namespace com::sun::star;
55 using namespace std;
57 namespace
59 util::DateTime lcl_boostToUnoTime( boost::posix_time::ptime boostTime )
61 util::DateTime unoTime;
62 unoTime.Year = boostTime.date().year();
63 unoTime.Month = boostTime.date().month();
64 unoTime.Day = boostTime.date().day();
65 unoTime.Hours = boostTime.time_of_day().hours();
66 unoTime.Minutes = boostTime.time_of_day().minutes();
67 unoTime.Seconds = boostTime.time_of_day().seconds();
69 // TODO FIXME maybe we should compile with BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
70 // to actually get nanosecond precision in boostTime?
71 // use this way rather than total_nanos to avoid overflows with 32-bit long
72 const long ticks = boostTime.time_of_day().fractional_seconds();
73 long nanoSeconds = ticks * ( 1000000000 / boost::posix_time::time_duration::ticks_per_second());
75 unoTime.NanoSeconds = nanoSeconds;
77 return unoTime;
80 uno::Any lcl_cmisPropertyToUno( libcmis::PropertyPtr pProperty )
82 uno::Any aValue;
83 bool bMultiValued = pProperty->getPropertyType( )->isMultiValued( );
84 switch ( pProperty->getPropertyType( )->getType( ) )
86 default:
87 case libcmis::PropertyType::String:
89 vector< string > aCmisStrings = pProperty->getStrings( );
90 if ( bMultiValued )
92 uno::Sequence< OUString > aStrings( aCmisStrings.size( ) );
93 OUString* aStringsArr = aStrings.getArray( );
94 sal_Int32 i = 0;
95 for ( vector< string >::iterator it = aCmisStrings.begin( );
96 it != aCmisStrings.end( ); ++it, ++i )
98 string str = *it;
99 aStringsArr[i] = STD_TO_OUSTR( str );
101 aValue <<= aStrings;
103 else if ( !aCmisStrings.empty( ) )
105 aValue <<= STD_TO_OUSTR( aCmisStrings.front( ) );
108 break;
109 case libcmis::PropertyType::Integer:
111 vector< long > aCmisLongs = pProperty->getLongs( );
112 if ( bMultiValued )
114 uno::Sequence< sal_Int64 > aLongs( aCmisLongs.size( ) );
115 sal_Int64* aLongsArr = aLongs.getArray( );
116 sal_Int32 i = 0;
117 for ( vector< long >::iterator it = aCmisLongs.begin( );
118 it != aCmisLongs.end( ); ++it, ++i )
120 aLongsArr[i] = *it;
122 aValue <<= aLongs;
124 else if ( !aCmisLongs.empty( ) )
126 aValue <<= aCmisLongs.front( );
129 break;
130 case libcmis::PropertyType::Decimal:
132 vector< double > aCmisDoubles = pProperty->getDoubles( );
133 if ( bMultiValued )
135 uno::Sequence< double > aDoubles( aCmisDoubles.size( ) );
136 double* aDoublesArr = aDoubles.getArray( );
137 sal_Int32 i = 0;
138 for ( vector< double >::iterator it = aCmisDoubles.begin( );
139 it != aCmisDoubles.end( ); ++it, ++i )
141 aDoublesArr[i] = *it;
143 aValue <<= aDoubles;
145 else if ( !aCmisDoubles.empty( ) )
147 aValue <<= aCmisDoubles.front( );
150 break;
151 case libcmis::PropertyType::Bool:
153 vector< bool > aCmisBools = pProperty->getBools( );
154 if ( bMultiValued )
156 uno::Sequence< sal_Bool > aBools( aCmisBools.size( ) );
157 sal_Bool* aBoolsArr = aBools.getArray( );
158 sal_Int32 i = 0;
159 for ( vector< bool >::iterator it = aCmisBools.begin( );
160 it != aCmisBools.end( ); ++it, ++i )
162 aBoolsArr[i] = *it;
164 aValue <<= aBools;
166 else if ( !aCmisBools.empty( ) )
168 aValue <<= sal_Bool( aCmisBools.front( ) );
171 break;
172 case libcmis::PropertyType::DateTime:
174 vector< boost::posix_time::ptime > aCmisTimes = pProperty->getDateTimes( );
175 if ( bMultiValued )
177 uno::Sequence< util::DateTime > aTimes( aCmisTimes.size( ) );
178 util::DateTime* aTimesArr = aTimes.getArray( );
179 sal_Int32 i = 0;
180 for ( vector< boost::posix_time::ptime >::iterator it = aCmisTimes.begin( );
181 it != aCmisTimes.end( ); ++it, ++i )
183 aTimesArr[i] = lcl_boostToUnoTime( *it );
185 aValue <<= aTimes;
187 else if ( !aCmisTimes.empty( ) )
189 aValue <<= lcl_boostToUnoTime( aCmisTimes.front( ) );
192 break;
194 return aValue;
198 namespace cmis
200 Content::Content( const uno::Reference< uno::XComponentContext >& rxContext,
201 ContentProvider *pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier,
202 libcmis::ObjectPtr pObject )
203 throw ( ucb::ContentCreationException )
204 : ContentImplHelper( rxContext, pProvider, Identifier ),
205 m_pProvider( pProvider ),
206 m_pSession( NULL ),
207 m_pObject( pObject ),
208 m_sURL( Identifier->getContentIdentifier( ) ),
209 m_aURL( Identifier->getContentIdentifier( ) ),
210 m_bTransient( false ),
211 m_bIsFolder( false )
213 SAL_INFO( "cmisucp", "Content::Content() " << m_sURL );
215 m_sObjectPath = m_aURL.getObjectPath( );
216 m_sObjectId = m_aURL.getObjectId( );
219 Content::Content( const uno::Reference< uno::XComponentContext >& rxContext, ContentProvider *pProvider,
220 const uno::Reference< ucb::XContentIdentifier >& Identifier,
221 sal_Bool bIsFolder )
222 throw ( ucb::ContentCreationException )
223 : ContentImplHelper( rxContext, pProvider, Identifier ),
224 m_pProvider( pProvider ),
225 m_pSession( NULL ),
226 m_sURL( Identifier->getContentIdentifier( ) ),
227 m_aURL( Identifier->getContentIdentifier( ) ),
228 m_bTransient( true ),
229 m_bIsFolder( bIsFolder )
231 SAL_INFO( "cmisucp", "Content::Content() " << m_sURL );
233 m_sObjectPath = m_aURL.getObjectPath( );
234 m_sObjectId = m_aURL.getObjectId( );
237 Content::~Content()
241 libcmis::Session* Content::getSession( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
243 // Set the proxy if needed. We are doing that all times as the proxy data shouldn't be cached.
244 ucbhelper::InternetProxyDecider aProxyDecider( m_xContext );
245 INetURLObject aBindingUrl( m_aURL.getBindingUrl( ) );
246 const ucbhelper::InternetProxyServer& rProxy = aProxyDecider.getProxy(
247 INetURLObject::GetScheme( aBindingUrl.GetProtocol( ) ), aBindingUrl.GetHost(), aBindingUrl.GetPort() );
248 OUString sProxy = rProxy.aName;
249 if ( rProxy.nPort > 0 )
250 sProxy += ":" + OUString::valueOf( rProxy.nPort );
251 libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy ), string(), string(), string() );
253 // Look for a cached session, key is binding url + repo id
254 OUString sSessionId = m_aURL.getBindingUrl( ) + m_aURL.getRepositoryId( );
255 if ( NULL == m_pSession )
256 m_pSession = m_pProvider->getSession( sSessionId );
258 if ( NULL == m_pSession )
260 // Get the auth credentials
261 AuthProvider authProvider( xEnv, m_xIdentifier->getContentIdentifier( ), m_aURL.getBindingUrl( ) );
263 string rUsername = OUSTR_TO_STDSTR( m_aURL.getUsername( ) );
264 string rPassword = OUSTR_TO_STDSTR( m_aURL.getPassword( ) );
265 if ( authProvider.authenticationQuery( rUsername, rPassword ) )
267 // Initiate a CMIS session and register it as we found nothing
268 m_pSession = libcmis::SessionFactory::createSession(
269 OUSTR_TO_STDSTR( m_aURL.getBindingUrl( ) ),
270 rUsername, rPassword, OUSTR_TO_STDSTR( m_aURL.getRepositoryId( ) ) );
271 if ( m_pSession == NULL )
272 ucbhelper::cancelCommandExecution(
273 ucb::IOErrorCode_INVALID_DEVICE,
274 uno::Sequence< uno::Any >( 0 ),
275 xEnv,
276 OUString( ) );
277 m_pProvider->registerSession( sSessionId, m_pSession );
279 else
281 // Silently fail as the user cancelled the authentication
282 throw uno::RuntimeException( );
285 return m_pSession;
288 libcmis::ObjectTypePtr Content::getObjectType( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
290 if ( NULL == m_pObjectType.get( ) && m_bTransient )
292 string typeId = m_bIsFolder ? "cmis:folder" : "cmis:document";
293 // The type to create needs to be fetched from the possible children types
294 // defined in the parent folder. Then, we'll pick up the first one we find matching
295 // cmis:folder or cmis:document (depending what we need to create).
296 // The easy case will work in most cases, but not on some servers (like Lotus Live)
297 libcmis::Folder* pParent = NULL;
298 bool bTypeRestricted = false;
301 pParent = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get( ) );
303 catch ( const libcmis::Exception& )
307 if ( pParent )
309 map< string, libcmis::PropertyPtr >& aProperties = pParent->getProperties( );
310 map< string, libcmis::PropertyPtr >::iterator it = aProperties.find( "cmis:allowedChildObjectTypeIds" );
311 if ( it != aProperties.end( ) )
313 libcmis::PropertyPtr pProperty = it->second;
314 if ( pProperty )
316 vector< string > typesIds = pProperty->getStrings( );
317 for ( vector< string >::iterator typeIt = typesIds.begin();
318 typeIt != typesIds.end() && !m_pObjectType; ++typeIt )
320 bTypeRestricted = true;
321 libcmis::ObjectTypePtr type = getSession( xEnv )->getType( *typeIt );
323 // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis
324 if ( type->getBaseType( )->getId( ) == typeId )
325 m_pObjectType = type;
331 if ( !bTypeRestricted )
332 m_pObjectType = getSession( xEnv )->getType( typeId );
334 return m_pObjectType;
338 libcmis::ObjectPtr Content::getObject( const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw ( libcmis::Exception )
340 if ( !m_pObject.get() )
342 if ( !m_sObjectPath.isEmpty( ) )
346 m_pObject = getSession( xEnv )->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath ) );
348 catch ( const libcmis::Exception& )
350 // In some cases, getting the object from the path doesn't work,
351 // but getting the parent from its path and the get the child in the list is OK.
352 // It's weird, but needed to handle case where the path isn't the folders/files
353 // names separated by '/' (as in Lotus Live)
354 INetURLObject aParentUrl( m_sURL );
355 string sName = OUSTR_TO_STDSTR( aParentUrl.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ) );
356 aParentUrl.removeSegment( );
357 OUString sParentUrl = aParentUrl.GetMainURL( INetURLObject::NO_DECODE );
359 Content aParent( m_xContext, m_pProvider, new ucbhelper::ContentIdentifier( sParentUrl ) );
360 libcmis::FolderPtr pParentFolder = boost::dynamic_pointer_cast< libcmis::Folder >( aParent.getObject( xEnv ) );
361 if ( pParentFolder )
363 vector< libcmis::ObjectPtr > children = pParentFolder->getChildren( );
364 for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
365 it != children.end() && !m_pObject; ++it )
367 if ( ( *it )->getName( ) == sName )
368 m_pObject = *it;
372 if ( !m_pObject )
373 throw libcmis::Exception( "Object not found" );
376 else if (!m_sObjectId.isEmpty( ) )
377 m_pObject = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId ) );
378 else
380 m_pObject = getSession( xEnv )->getRootFolder( );
381 m_sObjectPath = "/";
382 m_sObjectId = OUString( );
386 return m_pObject;
389 bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv )
391 bool bIsFolder = false;
394 bIsFolder = getObject( xEnv )->getBaseType( ) == "cmis:folder";
396 catch ( const libcmis::Exception& e )
398 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e.what( ) );
399 ucbhelper::cancelCommandExecution(
400 ucb::IOErrorCode_GENERAL,
401 uno::Sequence< uno::Any >( 0 ),
402 xEnv,
403 OUString::createFromAscii( e.what( ) ) );
405 return bIsFolder;
408 uno::Any Content::getBadArgExcept()
410 return uno::makeAny( lang::IllegalArgumentException(
411 OUString("Wrong argument type!"),
412 static_cast< cppu::OWeakObject * >( this ), -1) );
415 uno::Reference< sdbc::XRow > Content::getPropertyValues(
416 const uno::Sequence< beans::Property >& rProperties,
417 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
419 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xContext );
421 sal_Int32 nProps;
422 const beans::Property* pProps;
424 nProps = rProperties.getLength();
425 pProps = rProperties.getConstArray();
427 for( sal_Int32 n = 0; n < nProps; ++n )
429 const beans::Property& rProp = pProps[ n ];
433 if ( rProp.Name == "IsDocument" )
437 xRow->appendBoolean( rProp, getObject( xEnv )->getBaseType( ) == "cmis:document" );
439 catch ( const libcmis::Exception& )
441 if ( m_pObjectType.get( ) )
442 xRow->appendBoolean( rProp, getObjectType( xEnv )->getBaseType()->getId( ) == "cmis:document" );
443 else
444 xRow->appendVoid( rProp );
447 else if ( rProp.Name == "IsFolder" )
451 xRow->appendBoolean( rProp, getObject( xEnv )->getBaseType( ) == "cmis:folder" );
453 catch ( const libcmis::Exception& )
455 if ( m_pObjectType.get( ) )
456 xRow->appendBoolean( rProp, getObjectType( xEnv )->getBaseType()->getId( ) == "cmis:folder" );
457 else
458 xRow->appendVoid( rProp );
461 else if ( rProp.Name == "Title" )
463 OUString sTitle;
466 sTitle = STD_TO_OUSTR( getObject( xEnv )->getName() );
468 catch ( const libcmis::Exception& )
470 if ( !m_pObjectProps.empty() )
472 map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
473 if ( it != m_pObjectProps.end( ) )
475 vector< string > values = it->second->getStrings( );
476 if ( !values.empty() )
477 sTitle = STD_TO_OUSTR( values.front( ) );
482 // Nothing worked... get it from the path
483 if ( sTitle.isEmpty( ) )
485 OUString sPath = m_sObjectPath;
487 // Get rid of the trailing slash problem
488 if ( sPath[ sPath.getLength( ) - 1 ] == '/' )
489 sPath = sPath.copy( 0, sPath.getLength() - 1 );
491 // Get the last segment
492 sal_Int32 nPos = sPath.lastIndexOf( '/' );
493 if ( nPos >= 0 )
494 sTitle = sPath.copy( nPos + 1 );
497 if ( !sTitle.isEmpty( ) )
498 xRow->appendString( rProp, sTitle );
499 else
500 xRow->appendVoid( rProp );
502 else if ( rProp.Name == "TitleOnServer" )
504 string path;
507 vector< string > paths = getObject( xEnv )->getPaths( );
508 if ( !paths.empty( ) )
509 path = paths.front( );
510 else
511 path = getObject( xEnv )->getName( );
513 xRow->appendString( rProp, STD_TO_OUSTR( path ) );
515 catch ( const libcmis::Exception& )
517 xRow->appendVoid( rProp );
520 else if ( rProp.Name == "IsReadOnly" )
522 boost::shared_ptr< libcmis::AllowableActions > allowableActions = getObject( xEnv )->getAllowableActions( );
523 sal_Bool bReadOnly = sal_False;
524 if ( !allowableActions->isAllowed( libcmis::ObjectAction::SetContentStream ) &&
525 !allowableActions->isAllowed( libcmis::ObjectAction::CheckIn ) )
526 bReadOnly = sal_True;
528 xRow->appendBoolean( rProp, bReadOnly );
530 else if ( rProp.Name == "DateCreated" )
532 util::DateTime aTime = lcl_boostToUnoTime( getObject( xEnv )->getCreationDate( ) );
533 xRow->appendTimestamp( rProp, aTime );
535 else if ( rProp.Name == "DateModified" )
537 util::DateTime aTime = lcl_boostToUnoTime( getObject( xEnv )->getLastModificationDate( ) );
538 xRow->appendTimestamp( rProp, aTime );
540 else if ( rProp.Name == "Size" )
544 libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get( ) );
545 if ( NULL != document )
546 xRow->appendLong( rProp, document->getContentLength() );
547 else
548 xRow->appendVoid( rProp );
550 catch ( const libcmis::Exception& )
552 xRow->appendVoid( rProp );
555 else if ( rProp.Name == "CreatableContentsInfo" )
557 xRow->appendObject( rProp, uno::makeAny( queryCreatableContentsInfo( xEnv ) ) );
559 else if ( rProp.Name == "MediaType" )
563 libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get( ) );
564 if ( NULL != document )
565 xRow->appendString( rProp, STD_TO_OUSTR( document->getContentType() ) );
566 else
567 xRow->appendVoid( rProp );
569 catch ( const libcmis::Exception& )
571 xRow->appendVoid( rProp );
574 else if ( rProp.Name == "CmisPropertiesValues" )
578 libcmis::ObjectPtr object = getObject( xEnv );
579 map< string, libcmis::PropertyPtr >& aProperties = object->getProperties( );
580 beans::PropertyValues aCmisProperties( aProperties.size( ) );
581 beans::PropertyValue* pCmisProps = aCmisProperties.getArray( );
582 sal_Int32 i = 0;
583 for ( map< string, libcmis::PropertyPtr >::iterator it = aProperties.begin();
584 it != aProperties.end( ); ++it, ++i )
586 string name = it->first;
587 pCmisProps[i].Name = STD_TO_OUSTR( name );
588 pCmisProps[i].Value = lcl_cmisPropertyToUno( it->second );
590 xRow->appendObject( rProp.Name, uno::makeAny( aCmisProperties ) );
592 catch ( const libcmis::Exception& )
594 xRow->appendVoid( rProp );
597 else if ( rProp.Name == "CmisPropertiesDisplayNames" )
601 libcmis::ObjectPtr object = getObject( xEnv );
602 map< string, libcmis::PropertyPtr >& aProperties = object->getProperties( );
603 beans::PropertyValues aCmisProperties( aProperties.size( ) );
604 beans::PropertyValue* pCmisProps = aCmisProperties.getArray( );
605 sal_Int32 i = 0;
606 for ( map< string, libcmis::PropertyPtr >::iterator it = aProperties.begin();
607 it != aProperties.end( ); ++it, ++i )
609 string name = it->first;
610 string displayName = it->second->getPropertyType()->getDisplayName( );
611 pCmisProps[i].Name = STD_TO_OUSTR( name );
612 pCmisProps[i].Value = uno::makeAny( STD_TO_OUSTR( displayName ) );
614 xRow->appendObject( rProp.Name, uno::makeAny( aCmisProperties ) );
616 catch ( const libcmis::Exception& )
618 xRow->appendVoid( rProp );
621 else if ( rProp.Name == "IsVersionable" )
625 libcmis::ObjectPtr object = getObject( xEnv );
626 sal_Bool bIsVersionable = object->getTypeDescription( )->isVersionable( );
627 xRow->appendBoolean( rProp, bIsVersionable );
629 catch ( const libcmis::Exception& )
631 xRow->appendVoid( rProp );
634 else if ( rProp.Name == "CanCheckOut" )
638 libcmis::ObjectPtr pObject = getObject( xEnv );
639 libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
640 bool bAllowed = false;
641 if ( aAllowables )
643 bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckOut );
645 xRow->appendBoolean( rProp, bAllowed );
647 catch ( const libcmis::Exception& )
649 xRow->appendVoid( rProp );
652 else if ( rProp.Name == "CanCancelCheckOut" )
656 libcmis::ObjectPtr pObject = getObject( xEnv );
657 libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
658 bool bAllowed = false;
659 if ( aAllowables )
661 bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CancelCheckOut );
663 xRow->appendBoolean( rProp, bAllowed );
665 catch ( const libcmis::Exception& )
667 xRow->appendVoid( rProp );
670 else if ( rProp.Name == "CanCheckIn" )
674 libcmis::ObjectPtr pObject = getObject( xEnv );
675 libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
676 bool bAllowed = false;
677 if ( aAllowables )
679 bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckIn );
681 xRow->appendBoolean( rProp, bAllowed );
683 catch ( const libcmis::Exception& )
685 xRow->appendVoid( rProp );
688 else
689 SAL_INFO( "cmisucp", "Looking for unsupported property " << rProp.Name );
691 catch (const libcmis::Exception&)
693 xRow->appendVoid( rProp );
697 return uno::Reference< sdbc::XRow >( xRow.get() );
700 uno::Any Content::open(const ucb::OpenCommandArgument2 & rOpenCommand,
701 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
702 throw( uno::Exception )
704 bool bIsFolder = isFolder( xEnv );
706 // Handle the case of the non-existing file
707 if ( !getObject( xEnv ) )
709 uno::Sequence< uno::Any > aArgs( 1 );
710 aArgs[ 0 ] <<= m_xIdentifier->getContentIdentifier();
711 uno::Any aErr = uno::makeAny(
712 ucb::InteractiveAugmentedIOException(OUString(), static_cast< cppu::OWeakObject * >( this ),
713 task::InteractionClassification_ERROR,
714 bIsFolder ? ucb::IOErrorCode_NOT_EXISTING_PATH : ucb::IOErrorCode_NOT_EXISTING, aArgs)
717 ucbhelper::cancelCommandExecution(aErr, xEnv);
720 uno::Any aRet;
722 sal_Bool bOpenFolder = (
723 ( rOpenCommand.Mode == ucb::OpenMode::ALL ) ||
724 ( rOpenCommand.Mode == ucb::OpenMode::FOLDERS ) ||
725 ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENTS )
728 if ( bOpenFolder && bIsFolder )
730 uno::Reference< ucb::XDynamicResultSet > xSet
731 = new DynamicResultSet(m_xContext, this, rOpenCommand, xEnv );
732 aRet <<= xSet;
734 else if ( rOpenCommand.Sink.is() )
736 if (
737 ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
738 ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
741 ucbhelper::cancelCommandExecution(
742 uno::makeAny ( ucb::UnsupportedOpenModeException
743 ( OUString(), static_cast< cppu::OWeakObject * >( this ),
744 sal_Int16( rOpenCommand.Mode ) ) ),
745 xEnv );
748 if ( !feedSink( rOpenCommand.Sink, xEnv ) )
750 // Note: rOpenCommand.Sink may contain an XStream
751 // implementation. Support for this type of
752 // sink is optional...
753 SAL_INFO( "cmisucp", "Failed to copy data to sink" );
755 ucbhelper::cancelCommandExecution(
756 uno::makeAny (ucb::UnsupportedDataSinkException
757 ( OUString(), static_cast< cppu::OWeakObject * >( this ),
758 rOpenCommand.Sink ) ),
759 xEnv );
762 else
763 SAL_INFO( "cmisucp", "Open falling through ..." );
765 return aRet;
768 OUString Content::checkIn( const ucb::CheckinArgument& rArg,
769 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
770 throw( uno::Exception )
772 ucbhelper::Content aSourceContent( rArg.SourceURL, xEnv, comphelper::getProcessComponentContext( ) );
773 uno::Reference< io::XInputStream > xIn = aSourceContent.openStream( );
775 libcmis::ObjectPtr object;
778 object = getObject( xEnv );
780 catch ( const libcmis::Exception& )
784 libcmis::Document* pPwc = dynamic_cast< libcmis::Document* >( object.get( ) );
785 if ( !pPwc )
787 ucbhelper::cancelCommandExecution(
788 ucb::IOErrorCode_GENERAL,
789 uno::Sequence< uno::Any >( 0 ),
790 xEnv,
791 "Checkin only supported by documents" );
794 boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
795 uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
796 copyData( xIn, xOutput );
798 map< string, libcmis::PropertyPtr > newProperties;
799 libcmis::DocumentPtr pDoc = pPwc->checkIn( rArg.MajorVersion, OUSTR_TO_STDSTR( rArg.VersionComment ), newProperties,
800 pOut, OUSTR_TO_STDSTR( rArg.MimeType ), OUSTR_TO_STDSTR( rArg.NewTitle ) );
802 // Get the URL and send it back as a result
803 URL aCmisUrl( m_sURL );
804 vector< string > aPaths = pDoc->getPaths( );
805 if ( !aPaths.empty() )
807 string sPath = aPaths.front( );
808 aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
810 else
812 // We may have unfiled document depending on the server, those
813 // won't have any path, use their ID instead
814 string sId = pDoc->getId( );
815 aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
817 return aCmisUrl.asString( );
820 OUString Content::checkOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
821 throw( uno::Exception )
823 OUString aRet;
826 // Checkout the document if possible
827 libcmis::DocumentPtr pDoc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
828 if ( pDoc.get( ) == NULL )
830 ucbhelper::cancelCommandExecution(
831 ucb::IOErrorCode_GENERAL,
832 uno::Sequence< uno::Any >( 0 ),
833 xEnv,
834 "Checkout only supported by documents" );
836 libcmis::DocumentPtr pPwc = pDoc->checkOut( );
838 // Compute the URL of the Private Working Copy (PWC)
839 URL aCmisUrl( m_sURL );
840 vector< string > aPaths = pPwc->getPaths( );
841 if ( !aPaths.empty() )
843 string sPath = aPaths.front( );
844 aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
846 else
848 // We may have unfiled PWC depending on the server, those
849 // won't have any path, use their ID instead
850 string sId = pPwc->getId( );
851 aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
853 aRet = aCmisUrl.asString( );
855 catch ( const libcmis::Exception& e )
857 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e.what( ) );
858 ucbhelper::cancelCommandExecution(
859 ucb::IOErrorCode_GENERAL,
860 uno::Sequence< uno::Any >( 0 ),
861 xEnv,
862 OUString::createFromAscii( e.what() ) );
864 return aRet;
867 OUString Content::cancelCheckOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
868 throw( uno::Exception )
870 OUString aRet;
873 libcmis::DocumentPtr pPwc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
874 if ( pPwc.get( ) == NULL )
876 ucbhelper::cancelCommandExecution(
877 ucb::IOErrorCode_GENERAL,
878 uno::Sequence< uno::Any >( 0 ),
879 xEnv,
880 "CancelCheckout only supported by documents" );
882 pPwc->cancelCheckout( );
884 // Get the Original document (latest version)
885 vector< libcmis::DocumentPtr > aVersions = pPwc->getAllVersions( );
886 bool bFound = false;
887 for ( vector< libcmis::DocumentPtr >::iterator it = aVersions.begin();
888 it != aVersions.end( ) && !bFound; ++it )
890 libcmis::DocumentPtr pVersion = *it;
891 map< string, libcmis::PropertyPtr > aProps = pVersion->getProperties( );
892 bool bIsLatestVersion = false;
893 map< string, libcmis::PropertyPtr >::iterator propIt = aProps.find( string( "cmis:isLatestVersion" ) );
894 if ( propIt != aProps.end( ) && !propIt->second->getBools( ).empty( ) )
896 bIsLatestVersion = propIt->second->getBools( ).front( );
899 if ( bIsLatestVersion )
901 bFound = true;
902 // Compute the URL of the Document
903 URL aCmisUrl( m_sURL );
904 vector< string > aPaths = pVersion->getPaths( );
905 if ( !aPaths.empty() )
907 string sPath = aPaths.front( );
908 aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
910 else
912 // We may have unfiled doc depending on the server, those
913 // won't have any path, use their ID instead
914 string sId = pVersion->getId( );
915 aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
917 aRet = aCmisUrl.asString( );
921 catch ( const libcmis::Exception& e )
923 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e.what( ) );
924 ucbhelper::cancelCommandExecution(
925 ucb::IOErrorCode_GENERAL,
926 uno::Sequence< uno::Any >( 0 ),
927 xEnv,
928 OUString::createFromAscii( e.what() ) );
930 return aRet;
933 void Content::transfer( const ucb::TransferInfo& rTransferInfo,
934 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
935 throw( uno::Exception )
937 // If the source isn't on the same CMIS repository, then simply copy
938 INetURLObject aSourceUrl( rTransferInfo.SourceURL );
939 if ( aSourceUrl.GetProtocol() != INET_PROT_CMIS )
941 OUString sSrcBindingUrl = URL( rTransferInfo.SourceURL ).getBindingUrl( );
942 if ( sSrcBindingUrl != m_aURL.getBindingUrl( ) )
944 ucbhelper::cancelCommandExecution(
945 uno::makeAny(
946 ucb::InteractiveBadTransferURLException(
947 OUString("Unsupported URL scheme!"),
948 static_cast< cppu::OWeakObject * >( this ) ) ),
949 xEnv );
953 SAL_INFO( "cmisucp", "TODO - Content::transfer()" );
956 void Content::insert( const uno::Reference< io::XInputStream > & xInputStream,
957 sal_Bool bReplaceExisting, const OUString& rMimeType,
958 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
959 throw( uno::Exception )
961 if ( !xInputStream.is() )
963 ucbhelper::cancelCommandExecution( uno::makeAny
964 ( ucb::MissingInputStreamException
965 ( OUString(), static_cast< cppu::OWeakObject * >( this ) ) ),
966 xEnv );
969 // For transient content, the URL is the one of the parent
970 if ( m_bTransient )
972 OUString sNewPath;
974 // Try to get the object from the server if there is any
975 libcmis::Folder* pFolder = NULL;
978 pFolder = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get( ) );
980 catch ( const libcmis::Exception& )
984 if ( pFolder != NULL )
986 map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
987 if ( it == m_pObjectProps.end( ) )
989 ucbhelper::cancelCommandExecution( uno::makeAny
990 ( uno::RuntimeException( "Missing name property",
991 static_cast< cppu::OWeakObject * >( this ) ) ),
992 xEnv );
994 string newName = it->second->getStrings( ).front( );
995 string newPath = pFolder->getPath( );
996 if ( newPath[ newPath.size( ) - 1 ] != '/' )
997 newPath += "/";
998 newPath += newName;
1000 libcmis::ObjectPtr object;
1003 object = getSession( xEnv )->getObjectByPath( newPath );
1004 sNewPath = STD_TO_OUSTR( newPath );
1006 catch ( const libcmis::Exception& )
1008 // Nothing matched the path
1011 if ( NULL != object.get( ) )
1013 // Are the base type matching?
1014 if ( object->getBaseType( ) != m_pObjectType->getBaseType( )->getId() )
1016 ucbhelper::cancelCommandExecution( uno::makeAny
1017 ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
1018 static_cast< cppu::OWeakObject * >( this ) ) ),
1019 xEnv );
1022 // Update the existing object if it's a document
1023 libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get( ) );
1024 if ( NULL != document )
1026 boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
1027 uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
1028 copyData( xInputStream, xOutput );
1031 document->setContentStream( pOut, OUSTR_TO_STDSTR( rMimeType ), string( ), bReplaceExisting );
1033 catch ( const libcmis::Exception& )
1035 ucbhelper::cancelCommandExecution( uno::makeAny
1036 ( uno::RuntimeException( "Error when setting document content",
1037 static_cast< cppu::OWeakObject * >( this ) ) ),
1038 xEnv );
1042 else
1044 // We need to create a brand new object... either folder or document
1045 bool bIsFolder = getObjectType( xEnv )->getBaseType( )->getId( ) == "cmis:folder";
1046 setCmisProperty( "cmis:objectTypeId", getObjectType( xEnv )->getId( ), xEnv );
1048 if ( bIsFolder )
1052 libcmis::FolderPtr pNew = pFolder->createFolder( m_pObjectProps );
1053 sNewPath = STD_TO_OUSTR( newPath );
1055 catch ( const libcmis::Exception& )
1057 ucbhelper::cancelCommandExecution( uno::makeAny
1058 ( uno::RuntimeException( "Error when creating folder",
1059 static_cast< cppu::OWeakObject * >( this ) ) ),
1060 xEnv );
1063 else
1065 boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
1066 uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
1067 copyData( xInputStream, xOutput );
1070 pFolder->createDocument( m_pObjectProps, pOut, OUSTR_TO_STDSTR( rMimeType ), string() );
1071 sNewPath = STD_TO_OUSTR( newPath );
1073 catch ( const libcmis::Exception& )
1075 ucbhelper::cancelCommandExecution( uno::makeAny
1076 ( uno::RuntimeException( "Error when creating document",
1077 static_cast< cppu::OWeakObject * >( this ) ) ),
1078 xEnv );
1083 if ( !sNewPath.isEmpty( ) )
1085 // Update the current content: it's no longer transient
1086 m_sObjectPath = sNewPath;
1087 URL aUrl( m_sURL );
1088 aUrl.setObjectPath( m_sObjectPath );
1089 m_sURL = aUrl.asString( );
1090 m_pObject.reset( );
1091 m_pObjectType.reset( );
1092 m_pObjectProps.clear( );
1093 m_bTransient = false;
1095 inserted();
1101 const int TRANSFER_BUFFER_SIZE = 65536;
1103 void Content::copyData(
1104 uno::Reference< io::XInputStream > xIn,
1105 uno::Reference< io::XOutputStream > xOut )
1107 uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );
1109 while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
1110 xOut->writeBytes( theData );
1112 xOut->closeOutput();
1115 uno::Sequence< uno::Any > Content::setPropertyValues(
1116 const uno::Sequence< beans::PropertyValue >& rValues,
1117 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1121 // Get the already set properties if possible
1122 if ( !m_bTransient && getObject( xEnv ).get( ) )
1124 m_pObjectProps.clear( );
1125 m_pObjectType = getObject( xEnv )->getTypeDescription();
1128 catch ( const libcmis::Exception& e )
1130 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e.what( ) );
1131 ucbhelper::cancelCommandExecution(
1132 ucb::IOErrorCode_GENERAL,
1133 uno::Sequence< uno::Any >( 0 ),
1134 xEnv,
1135 OUString::createFromAscii( e.what() ) );
1138 sal_Int32 nCount = rValues.getLength();
1139 uno::Sequence< uno::Any > aRet( nCount );
1141 bool bChanged = false;
1142 const beans::PropertyValue* pValues = rValues.getConstArray();
1143 for ( sal_Int32 n = 0; n < nCount; ++n )
1145 const beans::PropertyValue& rValue = pValues[ n ];
1146 if ( rValue.Name == "ContentType" ||
1147 rValue.Name == "MediaType" ||
1148 rValue.Name == "IsDocument" ||
1149 rValue.Name == "IsFolder" ||
1150 rValue.Name == "Size" ||
1151 rValue.Name == "CreatableContentsInfo" )
1153 lang::IllegalAccessException e ( OUString("Property is read-only!"),
1154 static_cast< cppu::OWeakObject* >( this ) );
1155 aRet[ n ] <<= e;
1157 else if ( rValue.Name == "Title" )
1159 OUString aNewTitle;
1160 if (!( rValue.Value >>= aNewTitle ))
1162 aRet[ n ] <<= beans::IllegalTypeException
1163 ( OUString("Property value has wrong type!"),
1164 static_cast< cppu::OWeakObject * >( this ) );
1165 continue;
1168 if ( aNewTitle.getLength() <= 0 )
1170 aRet[ n ] <<= lang::IllegalArgumentException
1171 ( OUString("Empty title not allowed!"),
1172 static_cast< cppu::OWeakObject * >( this ), -1 );
1173 continue;
1177 setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle ), xEnv );
1178 bChanged = true;
1180 else
1182 SAL_INFO( "cmisucp", "Couln't set property: " << rValue.Name );
1183 lang::IllegalAccessException e ( OUString("Property is read-only!"),
1184 static_cast< cppu::OWeakObject* >( this ) );
1185 aRet[ n ] <<= e;
1191 if ( !m_bTransient && bChanged )
1193 getObject( xEnv )->updateProperties( m_pObjectProps );
1196 catch ( const libcmis::Exception& e )
1198 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e.what( ) );
1199 ucbhelper::cancelCommandExecution(
1200 ucb::IOErrorCode_GENERAL,
1201 uno::Sequence< uno::Any >( 0 ),
1202 xEnv,
1203 OUString::createFromAscii( e.what() ) );
1206 return aRet;
1209 sal_Bool Content::feedSink( uno::Reference< uno::XInterface> xSink,
1210 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1212 if ( !xSink.is() )
1213 return sal_False;
1215 uno::Reference< io::XOutputStream > xOut = uno::Reference< io::XOutputStream >(xSink, uno::UNO_QUERY );
1216 uno::Reference< io::XActiveDataSink > xDataSink = uno::Reference< io::XActiveDataSink >(xSink, uno::UNO_QUERY );
1217 uno::Reference< io::XActiveDataStreamer > xDataStreamer = uno::Reference< io::XActiveDataStreamer >( xSink, uno::UNO_QUERY );
1219 if ( !xOut.is() && !xDataSink.is() && ( !xDataStreamer.is() || !xDataStreamer->getStream().is() ) )
1220 return sal_False;
1222 if ( xDataStreamer.is() && !xOut.is() )
1223 xOut = xDataStreamer->getStream()->getOutputStream();
1227 libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get() );
1228 boost::shared_ptr< istream > aIn = document->getContentStream( );
1230 uno::Reference< io::XInputStream > xIn = new ucbhelper::StdInputStream( aIn );
1231 if( !xIn.is( ) )
1232 return sal_False;
1234 if ( xDataSink.is() )
1235 xDataSink->setInputStream( xIn );
1236 else if ( xOut.is() )
1237 copyData( xIn, xOut );
1239 catch ( const libcmis::Exception& e )
1241 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e.what( ) );
1242 ucbhelper::cancelCommandExecution(
1243 ucb::IOErrorCode_GENERAL,
1244 uno::Sequence< uno::Any >( 0 ),
1245 xEnv,
1246 OUString::createFromAscii( e.what() ) );
1249 return sal_True;
1252 uno::Sequence< beans::Property > Content::getProperties(
1253 const uno::Reference< ucb::XCommandEnvironment > & )
1255 static const beans::Property aGenericProperties[] =
1257 beans::Property( OUString( "IsDocument" ),
1258 -1, getCppuBooleanType(),
1259 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1260 beans::Property( OUString( "IsFolder" ),
1261 -1, getCppuBooleanType(),
1262 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1263 beans::Property( OUString( "Title" ),
1264 -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1265 beans::PropertyAttribute::BOUND ),
1266 beans::Property( OUString( "TitleOnServer" ),
1267 -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1268 beans::PropertyAttribute::BOUND ),
1269 beans::Property( OUString( "IsReadOnly" ),
1270 -1, getCppuBooleanType(),
1271 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1272 beans::Property( OUString( "DateCreated" ),
1273 -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ),
1274 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1275 beans::Property( OUString( "DateModified" ),
1276 -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ),
1277 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1278 beans::Property( OUString( "Size" ),
1279 -1, getCppuType( static_cast< const sal_Int64 * >( 0 ) ),
1280 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1281 beans::Property( OUString( "CreatableContentsInfo" ),
1282 -1, getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
1283 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1284 beans::Property( OUString( "MediaType" ),
1285 -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1286 beans::PropertyAttribute::BOUND ),
1287 beans::Property( OUString( "CmisPropertiesValues" ),
1288 -1, getCppuType( static_cast< const beans::PropertyValues * >( 0 ) ),
1289 beans::PropertyAttribute::BOUND ),
1290 beans::Property( OUString( "CmisPropertiesDisplayNames" ),
1291 -1, getCppuType( static_cast< const beans::PropertyValues * >( 0 ) ),
1292 beans::PropertyAttribute::BOUND ),
1293 beans::Property( OUString( "IsVersionable" ),
1294 -1, getCppuBooleanType(),
1295 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1296 beans::Property( OUString( "CanCheckOut" ),
1297 -1, getCppuBooleanType(),
1298 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1299 beans::Property( OUString( "CanCancelCheckOut" ),
1300 -1, getCppuBooleanType(),
1301 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1302 beans::Property( OUString( "CanCheckIn" ),
1303 -1, getCppuBooleanType(),
1304 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1307 const int nProps = SAL_N_ELEMENTS(aGenericProperties);
1308 return uno::Sequence< beans::Property > ( aGenericProperties, nProps );
1311 uno::Sequence< ucb::CommandInfo > Content::getCommands(
1312 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1314 static ucb::CommandInfo aCommandInfoTable[] =
1316 // Required commands
1317 ucb::CommandInfo
1318 ( OUString( "getCommandInfo" ),
1319 -1, getCppuVoidType() ),
1320 ucb::CommandInfo
1321 ( OUString( "getPropertySetInfo" ),
1322 -1, getCppuVoidType() ),
1323 ucb::CommandInfo
1324 ( OUString( "getPropertyValues" ),
1325 -1, getCppuType( static_cast<uno::Sequence< beans::Property > * >( 0 ) ) ),
1326 ucb::CommandInfo
1327 ( OUString( "setPropertyValues" ),
1328 -1, getCppuType( static_cast<uno::Sequence< beans::PropertyValue > * >( 0 ) ) ),
1330 // Optional standard commands
1331 ucb::CommandInfo
1332 ( OUString( "delete" ),
1333 -1, getCppuBooleanType() ),
1334 ucb::CommandInfo
1335 ( OUString( "insert" ),
1336 -1, getCppuType( static_cast<ucb::InsertCommandArgument2 * >( 0 ) ) ),
1337 ucb::CommandInfo
1338 ( OUString( "open" ),
1339 -1, getCppuType( static_cast<ucb::OpenCommandArgument2 * >( 0 ) ) ),
1341 // Mandatory CMIS-only commands
1342 ucb::CommandInfo ( OUString( "checkout" ), -1, getCppuVoidType() ),
1343 ucb::CommandInfo ( OUString( "cancelCheckout" ), -1, getCppuVoidType() ),
1344 ucb::CommandInfo ( OUString( "checkIn" ), -1,
1345 getCppuType( static_cast<ucb::TransferInfo * >( 0 ) ) ),
1347 // Folder Only, omitted if not a folder
1348 ucb::CommandInfo
1349 ( OUString( "transfer" ),
1350 -1, getCppuType( static_cast<ucb::TransferInfo * >( 0 ) ) ),
1351 ucb::CommandInfo
1352 ( OUString( "createNewContent" ),
1353 -1, getCppuType( static_cast<ucb::ContentInfo * >( 0 ) ) )
1356 const int nProps = SAL_N_ELEMENTS( aCommandInfoTable );
1357 return uno::Sequence< ucb::CommandInfo >(aCommandInfoTable, isFolder( xEnv ) ? nProps : nProps - 2);
1360 OUString Content::getParentURL( )
1362 OUString sRet;
1364 SAL_INFO( "cmisucp", "Content::getParentURL()" );
1366 string parentPath;
1369 libcmis::ObjectPtr pObj = getObject( uno::Reference< ucb::XCommandEnvironment >() );
1370 libcmis::Document* document = dynamic_cast< libcmis::Document* >( pObj.get( ) );
1371 if ( NULL != document )
1373 vector< boost::shared_ptr< libcmis::Folder > > parents = document->getParents( );
1374 if ( !parents.empty( ) )
1375 parentPath = parents.front( )->getPath( );
1377 else
1379 libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( pObj.get( ) );
1380 if ( NULL != folder )
1381 parentPath = folder->getFolderParent( )->getPath( );
1384 catch ( const libcmis::Exception & )
1386 // We may have an exception if we don't have the rights to
1387 // get the parents
1390 if ( !parentPath.empty() )
1392 URL aUrl( m_sURL );
1393 aUrl.setObjectPath( STD_TO_OUSTR( parentPath ) );
1394 sRet = aUrl.asString( );
1396 else
1398 INetURLObject aUrl( m_sURL );
1399 if ( aUrl.getSegmentCount( ) > 0 )
1401 URL aCmisUrl( m_sURL );
1402 aUrl.removeSegment( );
1403 aCmisUrl.setObjectPath( aUrl.GetURLPath( INetURLObject::DECODE_WITH_CHARSET ) );
1404 sRet = aCmisUrl.asString( );
1408 return sRet;
1411 XTYPEPROVIDER_COMMON_IMPL( Content );
1413 void SAL_CALL Content::acquire() throw()
1415 ContentImplHelper::acquire();
1418 void SAL_CALL Content::release() throw()
1420 ContentImplHelper::release();
1423 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) throw ( uno::RuntimeException )
1425 uno::Any aRet = cppu::queryInterface( rType, static_cast< ucb::XContentCreator * >( this ) );
1426 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface(rType);
1429 OUString SAL_CALL Content::getImplementationName() throw( uno::RuntimeException )
1431 return OUString("com.sun.star.comp.CmisContent");
1434 uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
1435 throw( uno::RuntimeException )
1437 uno::Sequence< OUString > aSNS( 1 );
1438 aSNS.getArray()[ 0 ] = "com.sun.star.ucb.CmisContent";
1439 return aSNS;
1442 OUString SAL_CALL Content::getContentType() throw( uno::RuntimeException )
1444 return isFolder( uno::Reference< ucb::XCommandEnvironment >() )
1445 ? OUString(CMIS_FOLDER_TYPE)
1446 : OUString(CMIS_FILE_TYPE);
1449 uno::Any SAL_CALL Content::execute(
1450 const ucb::Command& aCommand,
1451 sal_Int32 /*CommandId*/,
1452 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1453 throw( uno::Exception, ucb::CommandAbortedException, uno::RuntimeException )
1455 SAL_INFO( "cmisucp", "Content::execute( ) - " << aCommand.Name );
1456 uno::Any aRet;
1458 if ( aCommand.Name == "getPropertyValues" )
1460 uno::Sequence< beans::Property > Properties;
1461 if ( !( aCommand.Argument >>= Properties ) )
1462 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1463 aRet <<= getPropertyValues( Properties, xEnv );
1465 else if ( aCommand.Name == "getPropertySetInfo" )
1466 aRet <<= getPropertySetInfo( xEnv, sal_False );
1467 else if ( aCommand.Name == "getCommandInfo" )
1468 aRet <<= getCommandInfo( xEnv, sal_False );
1469 else if ( aCommand.Name == "open" )
1471 ucb::OpenCommandArgument2 aOpenCommand;
1472 if ( !( aCommand.Argument >>= aOpenCommand ) )
1473 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1474 aRet = open( aOpenCommand, xEnv );
1476 else if ( aCommand.Name == "transfer" )
1478 ucb::TransferInfo transferArgs;
1479 if ( !( aCommand.Argument >>= transferArgs ) )
1480 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1481 transfer( transferArgs, xEnv );
1483 else if ( aCommand.Name == "setPropertyValues" )
1485 uno::Sequence< beans::PropertyValue > aProperties;
1486 if ( !( aCommand.Argument >>= aProperties ) || !aProperties.getLength() )
1487 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1488 aRet <<= setPropertyValues( aProperties, xEnv );
1490 else if (aCommand.Name == "createNewContent"
1491 && isFolder( xEnv ) )
1493 ucb::ContentInfo arg;
1494 if ( !( aCommand.Argument >>= arg ) )
1495 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1496 aRet <<= createNewContent( arg );
1498 else if ( aCommand.Name == "insert" )
1500 ucb::InsertCommandArgument2 arg;
1501 if ( !( aCommand.Argument >>= arg ) )
1503 ucb::InsertCommandArgument insertArg;
1504 if ( !( aCommand.Argument >>= insertArg ) )
1505 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1507 arg.Data = insertArg.Data;
1508 arg.ReplaceExisting = insertArg.ReplaceExisting;
1510 insert( arg.Data, arg.ReplaceExisting, arg.MimeType, xEnv );
1512 else if ( aCommand.Name == "delete" )
1516 if ( !isFolder( xEnv ) )
1518 getObject( xEnv )->remove( );
1520 else
1522 libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get() );
1523 folder->removeTree( );
1526 catch ( const libcmis::Exception& e )
1528 SAL_INFO( "cmisucp", "Unexpected libcmis exception: " << e.what( ) );
1529 ucbhelper::cancelCommandExecution(
1530 ucb::IOErrorCode_GENERAL,
1531 uno::Sequence< uno::Any >( 0 ),
1532 xEnv,
1533 OUString::createFromAscii( e.what() ) );
1536 else if ( aCommand.Name == "checkout" )
1538 aRet <<= checkOut( xEnv );
1540 else if ( aCommand.Name == "cancelCheckout" )
1542 aRet <<= cancelCheckOut( xEnv );
1544 else if ( aCommand.Name == "checkin" )
1546 ucb::CheckinArgument aArg;
1547 if ( !( aCommand.Argument >>= aArg ) )
1549 ucbhelper::cancelCommandExecution ( getBadArgExcept(), xEnv );
1551 aRet <<= checkIn( aArg, xEnv );
1553 else
1555 SAL_INFO( "cmisucp", "Unknown command to execute" );
1557 ucbhelper::cancelCommandExecution
1558 ( uno::makeAny( ucb::UnsupportedCommandException
1559 ( OUString(),
1560 static_cast< cppu::OWeakObject * >( this ) ) ),
1561 xEnv );
1564 return aRet;
1567 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) throw( uno::RuntimeException )
1569 SAL_INFO( "cmisucp", "TODO - Content::abort()" );
1570 // TODO Implement me
1573 uno::Sequence< ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo()
1574 throw( uno::RuntimeException )
1576 return queryCreatableContentsInfo( uno::Reference< ucb::XCommandEnvironment >() );
1579 uno::Reference< ucb::XContent > SAL_CALL Content::createNewContent(
1580 const ucb::ContentInfo& Info ) throw( uno::RuntimeException )
1582 bool create_document;
1584 if ( Info.Type == CMIS_FILE_TYPE )
1585 create_document = true;
1586 else if ( Info.Type == CMIS_FOLDER_TYPE )
1587 create_document = false;
1588 else
1590 SAL_INFO( "cmisucp", "Unknown type of content to create" );
1591 return uno::Reference< ucb::XContent >();
1594 OUString sParentURL = m_xIdentifier->getContentIdentifier();
1595 URL aParentURL( sParentURL );
1597 // Set the parent URL for the transient objects
1598 uno::Reference< ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(sParentURL));
1602 return new ::cmis::Content( m_xContext, m_pProvider, xId, !create_document );
1604 catch ( ucb::ContentCreationException & )
1606 return uno::Reference< ucb::XContent >();
1610 uno::Sequence< uno::Type > SAL_CALL Content::getTypes() throw( uno::RuntimeException )
1612 if ( isFolder( uno::Reference< ucb::XCommandEnvironment >() ) )
1614 static cppu::OTypeCollection aFolderCollection
1615 (CPPU_TYPE_REF( lang::XTypeProvider ),
1616 CPPU_TYPE_REF( lang::XServiceInfo ),
1617 CPPU_TYPE_REF( lang::XComponent ),
1618 CPPU_TYPE_REF( ucb::XContent ),
1619 CPPU_TYPE_REF( ucb::XCommandProcessor ),
1620 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
1621 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
1622 CPPU_TYPE_REF( beans::XPropertyContainer ),
1623 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
1624 CPPU_TYPE_REF( container::XChild ),
1625 CPPU_TYPE_REF( ucb::XContentCreator ) );
1626 return aFolderCollection.getTypes();
1628 else
1630 static cppu::OTypeCollection aFileCollection
1631 (CPPU_TYPE_REF( lang::XTypeProvider ),
1632 CPPU_TYPE_REF( lang::XServiceInfo ),
1633 CPPU_TYPE_REF( lang::XComponent ),
1634 CPPU_TYPE_REF( ucb::XContent ),
1635 CPPU_TYPE_REF( ucb::XCommandProcessor ),
1636 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
1637 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
1638 CPPU_TYPE_REF( beans::XPropertyContainer ),
1639 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
1640 CPPU_TYPE_REF( container::XChild ) );
1642 return aFileCollection.getTypes();
1647 uno::Sequence< ucb::ContentInfo > Content::queryCreatableContentsInfo(
1648 const uno::Reference< ucb::XCommandEnvironment >& xEnv)
1649 throw( uno::RuntimeException )
1651 if ( isFolder( xEnv ) )
1653 uno::Sequence< ucb::ContentInfo > seq(2);
1655 // Minimum set of props we really need
1656 uno::Sequence< beans::Property > props( 1 );
1657 props[0] = beans::Property(
1658 OUString("Title"),
1660 getCppuType( static_cast< OUString* >( 0 ) ),
1661 beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND );
1663 // file
1664 seq[0].Type = OUString(CMIS_FILE_TYPE);
1665 seq[0].Attributes = ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM |
1666 ucb::ContentInfoAttribute::KIND_DOCUMENT );
1667 seq[0].Properties = props;
1669 // folder
1670 seq[1].Type = OUString(CMIS_FOLDER_TYPE);
1671 seq[1].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1672 seq[1].Properties = props;
1674 return seq;
1676 else
1678 return uno::Sequence< ucb::ContentInfo >();
1682 list< uno::Reference< ucb::XContent > > Content::getChildren( )
1684 list< uno::Reference< ucb::XContent > > results;
1685 SAL_INFO( "cmisucp", "Content::getChildren() " << m_sURL );
1687 libcmis::Folder* pFolder = dynamic_cast< libcmis::Folder* >( getObject( uno::Reference< ucb::XCommandEnvironment >() ).get( ) );
1688 if ( NULL != pFolder )
1690 // Get the children from pObject
1693 vector< libcmis::ObjectPtr > children = pFolder->getChildren( );
1695 // Loop over the results
1696 for ( vector< libcmis::ObjectPtr >::iterator it = children.begin();
1697 it != children.end(); ++it )
1699 // TODO Cache the objects
1701 URL aUrl( m_sURL );
1702 OUString sPath( m_sObjectPath );
1703 if ( sPath[sPath.getLength( ) - 1] != '/' )
1704 sPath += "/";
1705 sPath += STD_TO_OUSTR( ( *it )->getName( ) );
1706 aUrl.setObjectPath( sPath );
1707 uno::Reference< ucb::XContentIdentifier > xId = new ucbhelper::ContentIdentifier( aUrl.asString( ) );
1708 uno::Reference< ucb::XContent > xContent = new Content( m_xContext, m_pProvider, xId, *it );
1710 results.push_back( xContent );
1713 catch ( const libcmis::Exception& e )
1715 SAL_INFO( "cmisucp", "Exception thrown: " << e.what() );
1719 return results;
1722 void Content::setCmisProperty( std::string sName, std::string sValue, const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1724 if ( getObjectType( xEnv ).get( ) )
1726 map< string, libcmis::PropertyPtr >::iterator propIt = m_pObjectProps.find( sName );
1727 vector< string > values;
1728 values.push_back( sValue );
1730 if ( propIt == m_pObjectProps.end( ) && getObjectType( xEnv ).get( ) )
1732 map< string, libcmis::PropertyTypePtr > propsTypes = getObjectType( xEnv )->getPropertiesTypes( );
1733 map< string, libcmis::PropertyTypePtr >::iterator typeIt = propsTypes.find( sName );
1735 if ( typeIt != propsTypes.end( ) )
1737 libcmis::PropertyTypePtr propType = typeIt->second;
1738 libcmis::PropertyPtr property( new libcmis::Property( propType, values ) );
1739 m_pObjectProps.insert( pair< string, libcmis::PropertyPtr >( sName, property ) );
1742 else if ( propIt != m_pObjectProps.end( ) )
1744 propIt->second->setValues( values );
1750 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */