1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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
;
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
;
80 uno::Any
lcl_cmisPropertyToUno( libcmis::PropertyPtr pProperty
)
83 bool bMultiValued
= pProperty
->getPropertyType( )->isMultiValued( );
84 switch ( pProperty
->getPropertyType( )->getType( ) )
87 case libcmis::PropertyType::String
:
89 vector
< string
> aCmisStrings
= pProperty
->getStrings( );
92 uno::Sequence
< OUString
> aStrings( aCmisStrings
.size( ) );
93 OUString
* aStringsArr
= aStrings
.getArray( );
95 for ( vector
< string
>::iterator it
= aCmisStrings
.begin( );
96 it
!= aCmisStrings
.end( ); ++it
, ++i
)
99 aStringsArr
[i
] = STD_TO_OUSTR( str
);
103 else if ( !aCmisStrings
.empty( ) )
105 aValue
<<= STD_TO_OUSTR( aCmisStrings
.front( ) );
109 case libcmis::PropertyType::Integer
:
111 vector
< long > aCmisLongs
= pProperty
->getLongs( );
114 uno::Sequence
< sal_Int64
> aLongs( aCmisLongs
.size( ) );
115 sal_Int64
* aLongsArr
= aLongs
.getArray( );
117 for ( vector
< long >::iterator it
= aCmisLongs
.begin( );
118 it
!= aCmisLongs
.end( ); ++it
, ++i
)
124 else if ( !aCmisLongs
.empty( ) )
126 aValue
<<= aCmisLongs
.front( );
130 case libcmis::PropertyType::Decimal
:
132 vector
< double > aCmisDoubles
= pProperty
->getDoubles( );
135 uno::Sequence
< double > aDoubles( aCmisDoubles
.size( ) );
136 double* aDoublesArr
= aDoubles
.getArray( );
138 for ( vector
< double >::iterator it
= aCmisDoubles
.begin( );
139 it
!= aCmisDoubles
.end( ); ++it
, ++i
)
141 aDoublesArr
[i
] = *it
;
145 else if ( !aCmisDoubles
.empty( ) )
147 aValue
<<= aCmisDoubles
.front( );
151 case libcmis::PropertyType::Bool
:
153 vector
< bool > aCmisBools
= pProperty
->getBools( );
156 uno::Sequence
< sal_Bool
> aBools( aCmisBools
.size( ) );
157 sal_Bool
* aBoolsArr
= aBools
.getArray( );
159 for ( vector
< bool >::iterator it
= aCmisBools
.begin( );
160 it
!= aCmisBools
.end( ); ++it
, ++i
)
166 else if ( !aCmisBools
.empty( ) )
168 aValue
<<= sal_Bool( aCmisBools
.front( ) );
172 case libcmis::PropertyType::DateTime
:
174 vector
< boost::posix_time::ptime
> aCmisTimes
= pProperty
->getDateTimes( );
177 uno::Sequence
< util::DateTime
> aTimes( aCmisTimes
.size( ) );
178 util::DateTime
* aTimesArr
= aTimes
.getArray( );
180 for ( vector
< boost::posix_time::ptime
>::iterator it
= aCmisTimes
.begin( );
181 it
!= aCmisTimes
.end( ); ++it
, ++i
)
183 aTimesArr
[i
] = lcl_boostToUnoTime( *it
);
187 else if ( !aCmisTimes
.empty( ) )
189 aValue
<<= lcl_boostToUnoTime( aCmisTimes
.front( ) );
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
),
207 m_pObject( pObject
),
208 m_sURL( Identifier
->getContentIdentifier( ) ),
209 m_aURL( Identifier
->getContentIdentifier( ) ),
210 m_bTransient( 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
,
222 throw ( ucb::ContentCreationException
)
223 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
224 m_pProvider( pProvider
),
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( );
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 ),
277 m_pProvider
->registerSession( sSessionId
, m_pSession
);
281 // Silently fail as the user cancelled the authentication
282 throw uno::RuntimeException( );
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
& )
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
;
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
) );
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
)
373 throw libcmis::Exception( "Object not found" );
376 else if (!m_sObjectId
.isEmpty( ) )
377 m_pObject
= getSession( xEnv
)->getObject( OUSTR_TO_STDSTR( m_sObjectId
) );
380 m_pObject
= getSession( xEnv
)->getRootFolder( );
382 m_sObjectId
= OUString( );
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 ),
403 OUString::createFromAscii( e
.what( ) ) );
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
);
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" );
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" );
458 xRow
->appendVoid( rProp
);
461 else if ( rProp
.Name
== "Title" )
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( '/' );
494 sTitle
= sPath
.copy( nPos
+ 1 );
497 if ( !sTitle
.isEmpty( ) )
498 xRow
->appendString( rProp
, sTitle
);
500 xRow
->appendVoid( rProp
);
502 else if ( rProp
.Name
== "TitleOnServer" )
507 vector
< string
> paths
= getObject( xEnv
)->getPaths( );
508 if ( !paths
.empty( ) )
509 path
= paths
.front( );
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() );
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() ) );
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( );
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( );
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;
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;
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;
679 bAllowed
= aAllowables
->isAllowed( libcmis::ObjectAction::CheckIn
);
681 xRow
->appendBoolean( rProp
, bAllowed
);
683 catch ( const libcmis::Exception
& )
685 xRow
->appendVoid( rProp
);
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
);
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
);
734 else if ( rOpenCommand
.Sink
.is() )
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
) ) ),
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
) ),
763 SAL_INFO( "cmisucp", "Open falling through ..." );
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( ) );
787 ucbhelper::cancelCommandExecution(
788 ucb::IOErrorCode_GENERAL
,
789 uno::Sequence
< uno::Any
>( 0 ),
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
) );
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
)
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 ),
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
) );
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 ),
862 OUString::createFromAscii( e
.what() ) );
867 OUString
Content::cancelCheckOut( const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
868 throw( uno::Exception
)
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 ),
880 "CancelCheckout only supported by documents" );
882 pPwc
->cancelCheckout( );
884 // Get the Original document (latest version)
885 vector
< libcmis::DocumentPtr
> aVersions
= pPwc
->getAllVersions( );
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
)
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
) );
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 ),
928 OUString::createFromAscii( e
.what() ) );
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(
946 ucb::InteractiveBadTransferURLException(
947 OUString("Unsupported URL scheme!"),
948 static_cast< cppu::OWeakObject
* >( this ) ) ),
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 ) ) ),
969 // For transient content, the URL is the one of the parent
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 ) ) ),
994 string newName
= it
->second
->getStrings( ).front( );
995 string newPath
= pFolder
->getPath( );
996 if ( newPath
[ newPath
.size( ) - 1 ] != '/' )
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 ) ) ),
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 ) ) ),
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
);
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 ) ) ),
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 ) ) ),
1083 if ( !sNewPath
.isEmpty( ) )
1085 // Update the current content: it's no longer transient
1086 m_sObjectPath
= sNewPath
;
1088 aUrl
.setObjectPath( m_sObjectPath
);
1089 m_sURL
= aUrl
.asString( );
1091 m_pObjectType
.reset( );
1092 m_pObjectProps
.clear( );
1093 m_bTransient
= false;
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 ),
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 ) );
1157 else if ( rValue
.Name
== "Title" )
1160 if (!( rValue
.Value
>>= aNewTitle
))
1162 aRet
[ n
] <<= beans::IllegalTypeException
1163 ( OUString("Property value has wrong type!"),
1164 static_cast< cppu::OWeakObject
* >( this ) );
1168 if ( aNewTitle
.getLength() <= 0 )
1170 aRet
[ n
] <<= lang::IllegalArgumentException
1171 ( OUString("Empty title not allowed!"),
1172 static_cast< cppu::OWeakObject
* >( this ), -1 );
1177 setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle
), xEnv
);
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 ) );
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 ),
1203 OUString::createFromAscii( e
.what() ) );
1209 sal_Bool
Content::feedSink( uno::Reference
< uno::XInterface
> xSink
,
1210 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
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() ) )
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
);
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 ),
1246 OUString::createFromAscii( e
.what() ) );
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
1318 ( OUString( "getCommandInfo" ),
1319 -1, getCppuVoidType() ),
1321 ( OUString( "getPropertySetInfo" ),
1322 -1, getCppuVoidType() ),
1324 ( OUString( "getPropertyValues" ),
1325 -1, getCppuType( static_cast<uno::Sequence
< beans::Property
> * >( 0 ) ) ),
1327 ( OUString( "setPropertyValues" ),
1328 -1, getCppuType( static_cast<uno::Sequence
< beans::PropertyValue
> * >( 0 ) ) ),
1330 // Optional standard commands
1332 ( OUString( "delete" ),
1333 -1, getCppuBooleanType() ),
1335 ( OUString( "insert" ),
1336 -1, getCppuType( static_cast<ucb::InsertCommandArgument2
* >( 0 ) ) ),
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
1349 ( OUString( "transfer" ),
1350 -1, getCppuType( static_cast<ucb::TransferInfo
* >( 0 ) ) ),
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( )
1364 SAL_INFO( "cmisucp", "Content::getParentURL()" );
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( );
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
1390 if ( !parentPath
.empty() )
1393 aUrl
.setObjectPath( STD_TO_OUSTR( parentPath
) );
1394 sRet
= aUrl
.asString( );
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( );
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";
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
);
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( );
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 ),
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
);
1555 SAL_INFO( "cmisucp", "Unknown command to execute" );
1557 ucbhelper::cancelCommandExecution
1558 ( uno::makeAny( ucb::UnsupportedCommandException
1560 static_cast< cppu::OWeakObject
* >( this ) ) ),
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;
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();
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(
1660 getCppuType( static_cast< OUString
* >( 0 ) ),
1661 beans::PropertyAttribute::MAYBEVOID
| beans::PropertyAttribute::BOUND
);
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
;
1670 seq
[1].Type
= OUString(CMIS_FOLDER_TYPE
);
1671 seq
[1].Attributes
= ucb::ContentInfoAttribute::KIND_FOLDER
;
1672 seq
[1].Properties
= props
;
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
1702 OUString
sPath( m_sObjectPath
);
1703 if ( sPath
[sPath
.getLength( ) - 1] != '/' )
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() );
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: */