Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
10 : #include <cstdio>
11 :
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/document/CmisProperty.hpp>
17 : #include <com/sun/star/io/XActiveDataSink.hpp>
18 : #include <com/sun/star/io/XActiveDataStreamer.hpp>
19 : #include <com/sun/star/lang/IllegalAccessException.hpp>
20 : #include <com/sun/star/task/InteractionClassification.hpp>
21 : #include <com/sun/star/ucb/ContentInfo.hpp>
22 : #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
23 : #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
24 : #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
25 : #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
26 : #include <com/sun/star/ucb/MissingInputStreamException.hpp>
27 : #include <com/sun/star/ucb/NameClash.hpp>
28 : #include <com/sun/star/ucb/NameClashException.hpp>
29 : #include <com/sun/star/ucb/OpenMode.hpp>
30 : #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
31 : #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
32 : #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
33 : #include <com/sun/star/ucb/XCommandInfo.hpp>
34 : #include <com/sun/star/ucb/XDynamicResultSet.hpp>
35 :
36 : #include <comphelper/processfactory.hxx>
37 : #include <config_oauth2.h>
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>
45 :
46 : #include "auth_provider.hxx"
47 : #include "certvalidation_handler.hxx"
48 : #include "cmis_content.hxx"
49 : #include "cmis_provider.hxx"
50 : #include "cmis_resultset.hxx"
51 : #include "cmis_strings.hxx"
52 :
53 : #define OUSTR_TO_STDSTR(s) string( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ).getStr() )
54 : #define STD_TO_OUSTR( str ) OUString( str.c_str(), str.length( ), RTL_TEXTENCODING_UTF8 )
55 :
56 : using namespace com::sun::star;
57 : using namespace std;
58 :
59 : namespace
60 : {
61 0 : util::DateTime lcl_boostToUnoTime( boost::posix_time::ptime boostTime )
62 : {
63 0 : util::DateTime unoTime;
64 0 : unoTime.Year = boostTime.date().year();
65 0 : unoTime.Month = boostTime.date().month();
66 0 : unoTime.Day = boostTime.date().day();
67 0 : unoTime.Hours = boostTime.time_of_day().hours();
68 0 : unoTime.Minutes = boostTime.time_of_day().minutes();
69 0 : unoTime.Seconds = boostTime.time_of_day().seconds();
70 :
71 : // TODO FIXME maybe we should compile with BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
72 : // to actually get nanosecond precision in boostTime?
73 : // use this way rather than total_nanos to avoid overflows with 32-bit long
74 0 : const long ticks = boostTime.time_of_day().fractional_seconds();
75 0 : long nanoSeconds = ticks * ( 1000000000 / boost::posix_time::time_duration::ticks_per_second());
76 :
77 0 : unoTime.NanoSeconds = nanoSeconds;
78 :
79 0 : return unoTime;
80 : }
81 :
82 0 : uno::Any lcl_cmisPropertyToUno( libcmis::PropertyPtr pProperty )
83 : {
84 0 : uno::Any aValue;
85 0 : switch ( pProperty->getPropertyType( )->getType( ) )
86 : {
87 : default:
88 : case libcmis::PropertyType::String:
89 : {
90 0 : vector< string > aCmisStrings = pProperty->getStrings( );
91 0 : uno::Sequence< OUString > aStrings( aCmisStrings.size( ) );
92 0 : OUString* aStringsArr = aStrings.getArray( );
93 0 : sal_Int32 i = 0;
94 0 : for ( vector< string >::iterator it = aCmisStrings.begin( );
95 0 : it != aCmisStrings.end( ); ++it, ++i )
96 : {
97 0 : string str = *it;
98 0 : aStringsArr[i] = STD_TO_OUSTR( str );
99 0 : }
100 0 : aValue <<= aStrings;
101 : }
102 0 : break;
103 : case libcmis::PropertyType::Integer:
104 : {
105 0 : vector< long > aCmisLongs = pProperty->getLongs( );
106 0 : uno::Sequence< sal_Int64 > aLongs( aCmisLongs.size( ) );
107 0 : sal_Int64* aLongsArr = aLongs.getArray( );
108 0 : sal_Int32 i = 0;
109 0 : for ( vector< long >::iterator it = aCmisLongs.begin( );
110 0 : it != aCmisLongs.end( ); ++it, ++i )
111 : {
112 0 : aLongsArr[i] = *it;
113 : }
114 0 : aValue <<= aLongs;
115 : }
116 0 : break;
117 : case libcmis::PropertyType::Decimal:
118 : {
119 0 : vector< double > aCmisDoubles = pProperty->getDoubles( );
120 0 : uno::Sequence< double > aDoubles( aCmisDoubles.size( ) );
121 0 : double* aDoublesArr = aDoubles.getArray( );
122 0 : sal_Int32 i = 0;
123 0 : for ( vector< double >::iterator it = aCmisDoubles.begin( );
124 0 : it != aCmisDoubles.end( ); ++it, ++i )
125 : {
126 0 : aDoublesArr[i] = *it;
127 : }
128 0 : aValue <<= aDoubles;
129 : }
130 0 : break;
131 : case libcmis::PropertyType::Bool:
132 : {
133 0 : vector< bool > aCmisBools = pProperty->getBools( );
134 0 : uno::Sequence< sal_Bool > aBools( aCmisBools.size( ) );
135 0 : sal_Bool* aBoolsArr = aBools.getArray( );
136 0 : sal_Int32 i = 0;
137 0 : for ( vector< bool >::iterator it = aCmisBools.begin( );
138 0 : it != aCmisBools.end( ); ++it, ++i )
139 : {
140 0 : aBoolsArr[i] = *it;
141 : }
142 0 : aValue <<= aBools;
143 : }
144 0 : break;
145 : case libcmis::PropertyType::DateTime:
146 : {
147 0 : vector< boost::posix_time::ptime > aCmisTimes = pProperty->getDateTimes( );
148 0 : uno::Sequence< util::DateTime > aTimes( aCmisTimes.size( ) );
149 0 : util::DateTime* aTimesArr = aTimes.getArray( );
150 0 : sal_Int32 i = 0;
151 0 : for ( vector< boost::posix_time::ptime >::iterator it = aCmisTimes.begin( );
152 0 : it != aCmisTimes.end( ); ++it, ++i )
153 : {
154 0 : aTimesArr[i] = lcl_boostToUnoTime( *it );
155 : }
156 0 : aValue <<= aTimes;
157 : }
158 0 : break;
159 : }
160 0 : return aValue;
161 : }
162 :
163 0 : libcmis::PropertyPtr lcl_unoToCmisProperty( document::CmisProperty prop )
164 : {
165 0 : libcmis::PropertyTypePtr propertyType( new libcmis::PropertyType( ) );
166 :
167 0 : OUString id = prop.Id;
168 0 : OUString name = prop.Name;
169 0 : bool bUpdatable = prop.Updatable;
170 0 : bool bRequired = prop.Required;
171 0 : bool bMultiValued = prop.MultiValued;
172 0 : bool bOpenChoice = prop.OpenChoice;
173 0 : uno::Any value = prop.Value;
174 0 : libcmis::PropertyType::Type type = libcmis::PropertyType::String;
175 0 : if ( prop.Type == CMIS_TYPE_STRING )
176 0 : type = libcmis::PropertyType::String;
177 0 : else if ( prop.Type == CMIS_TYPE_BOOL )
178 0 : type = libcmis::PropertyType::Bool;
179 0 : else if ( prop.Type == CMIS_TYPE_INTEGER )
180 0 : type = libcmis::PropertyType::Integer;
181 0 : else if ( prop.Type == CMIS_TYPE_DECIMAL )
182 0 : type = libcmis::PropertyType::Decimal;
183 0 : else if ( prop.Type == CMIS_TYPE_DATETIME )
184 0 : type = libcmis::PropertyType::DateTime;
185 :
186 0 : propertyType->setId( OUSTR_TO_STDSTR( id ));
187 0 : propertyType->setDisplayName( OUSTR_TO_STDSTR( name ) );
188 0 : propertyType->setUpdatable( bUpdatable );
189 0 : propertyType->setRequired( bRequired );
190 0 : propertyType->setMultiValued( bMultiValued );
191 0 : propertyType->setOpenChoice( bOpenChoice );
192 0 : propertyType->setType( type );
193 :
194 0 : std::vector< std::string > values;
195 :
196 : // convert UNO value to string vector
197 0 : uno::Sequence< OUString > aStrings;
198 0 : value >>= aStrings;
199 0 : sal_Int32 len = aStrings.getLength( );
200 0 : for ( sal_Int32 i = 0; i < len; i++ )
201 : {
202 0 : string str = OUSTR_TO_STDSTR( aStrings[i] );
203 0 : values.push_back( str );
204 0 : }
205 :
206 0 : libcmis::PropertyPtr property( new libcmis::Property( propertyType, values ) );
207 :
208 0 : return property;
209 : }
210 :
211 : }
212 :
213 : namespace cmis
214 : {
215 0 : Content::Content( const uno::Reference< uno::XComponentContext >& rxContext,
216 : ContentProvider *pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier,
217 : libcmis::ObjectPtr pObject )
218 : throw ( ucb::ContentCreationException )
219 : : ContentImplHelper( rxContext, pProvider, Identifier ),
220 : m_pProvider( pProvider ),
221 : m_pSession( NULL ),
222 : m_pObject( pObject ),
223 0 : m_sURL( Identifier->getContentIdentifier( ) ),
224 0 : m_aURL( Identifier->getContentIdentifier( ) ),
225 : m_bTransient( false ),
226 0 : m_bIsFolder( false )
227 : {
228 : SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL );
229 :
230 0 : m_sObjectPath = m_aURL.getObjectPath( );
231 0 : m_sObjectId = m_aURL.getObjectId( );
232 0 : }
233 :
234 0 : Content::Content( const uno::Reference< uno::XComponentContext >& rxContext, ContentProvider *pProvider,
235 : const uno::Reference< ucb::XContentIdentifier >& Identifier,
236 : sal_Bool bIsFolder )
237 : throw ( ucb::ContentCreationException )
238 : : ContentImplHelper( rxContext, pProvider, Identifier ),
239 : m_pProvider( pProvider ),
240 : m_pSession( NULL ),
241 0 : m_sURL( Identifier->getContentIdentifier( ) ),
242 0 : m_aURL( Identifier->getContentIdentifier( ) ),
243 : m_bTransient( true ),
244 0 : m_bIsFolder( bIsFolder )
245 : {
246 : SAL_INFO( "ucb.ucp.cmis", "Content::Content() " << m_sURL );
247 :
248 0 : m_sObjectPath = m_aURL.getObjectPath( );
249 0 : m_sObjectId = m_aURL.getObjectId( );
250 0 : }
251 :
252 0 : Content::~Content()
253 : {
254 0 : }
255 :
256 0 : libcmis::Session* Content::getSession( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
257 : {
258 : // Set the proxy if needed. We are doing that all times as the proxy data shouldn't be cached.
259 0 : ucbhelper::InternetProxyDecider aProxyDecider( m_xContext );
260 0 : INetURLObject aBindingUrl( m_aURL.getBindingUrl( ) );
261 : const ucbhelper::InternetProxyServer& rProxy = aProxyDecider.getProxy(
262 0 : INetURLObject::GetScheme( aBindingUrl.GetProtocol( ) ), aBindingUrl.GetHost(), aBindingUrl.GetPort() );
263 0 : OUString sProxy = rProxy.aName;
264 0 : if ( rProxy.nPort > 0 )
265 0 : sProxy += ":" + OUString::number( rProxy.nPort );
266 0 : libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy ), string(), string(), string() );
267 :
268 : // Look for a cached session, key is binding url + repo id
269 0 : OUString sSessionId = m_aURL.getBindingUrl( ) + m_aURL.getRepositoryId( );
270 0 : if ( NULL == m_pSession )
271 0 : m_pSession = m_pProvider->getSession( sSessionId );
272 :
273 0 : if ( NULL == m_pSession )
274 : {
275 : // Set the SSL Validation handler
276 : libcmis::CertValidationHandlerPtr certHandler(
277 0 : new CertValidationHandler( xEnv, m_xContext, aBindingUrl.GetHost( ) ) );
278 0 : libcmis::SessionFactory::setCertificateValidationHandler( certHandler );
279 :
280 : // Get the auth credentials
281 0 : AuthProvider authProvider( xEnv, m_xIdentifier->getContentIdentifier( ), m_aURL.getBindingUrl( ) );
282 :
283 0 : string rUsername = OUSTR_TO_STDSTR( m_aURL.getUsername( ) );
284 0 : string rPassword = OUSTR_TO_STDSTR( m_aURL.getPassword( ) );
285 0 : if ( authProvider.authenticationQuery( rUsername, rPassword ) )
286 : {
287 : // Initiate a CMIS session and register it as we found nothing
288 0 : libcmis::OAuth2DataPtr oauth2Data;
289 0 : if ( m_aURL.getBindingUrl( ) == GDRIVE_BASE_URL )
290 : oauth2Data.reset( new libcmis::OAuth2Data(
291 : GDRIVE_AUTH_URL, GDRIVE_TOKEN_URL,
292 : GDRIVE_SCOPE, GDRIVE_REDIRECT_URI,
293 0 : GDRIVE_CLIENT_ID, GDRIVE_CLIENT_SECRET ) );
294 0 : if ( m_aURL.getBindingUrl().startsWith( ALFRESCO_CLOUD_BASE_URL ) )
295 : oauth2Data.reset( new libcmis::OAuth2Data(
296 : ALFRESCO_CLOUD_AUTH_URL, ALFRESCO_CLOUD_TOKEN_URL,
297 : ALFRESCO_CLOUD_SCOPE, ALFRESCO_CLOUD_REDIRECT_URI,
298 0 : ALFRESCO_CLOUD_CLIENT_ID, ALFRESCO_CLOUD_CLIENT_SECRET ) );
299 :
300 : m_pSession = libcmis::SessionFactory::createSession(
301 0 : OUSTR_TO_STDSTR( m_aURL.getBindingUrl( ) ),
302 0 : rUsername, rPassword, OUSTR_TO_STDSTR( m_aURL.getRepositoryId( ) ), false, oauth2Data );
303 0 : if ( m_pSession == NULL )
304 : ucbhelper::cancelCommandExecution(
305 : ucb::IOErrorCode_INVALID_DEVICE,
306 : uno::Sequence< uno::Any >( 0 ),
307 : xEnv,
308 0 : OUString( ) );
309 0 : m_pProvider->registerSession( sSessionId, m_pSession );
310 : }
311 : else
312 : {
313 : // Silently fail as the user cancelled the authentication
314 0 : throw uno::RuntimeException( );
315 0 : }
316 : }
317 0 : return m_pSession;
318 : }
319 :
320 0 : libcmis::ObjectTypePtr Content::getObjectType( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
321 : {
322 0 : if ( NULL == m_pObjectType.get( ) && m_bTransient )
323 : {
324 0 : string typeId = m_bIsFolder ? "cmis:folder" : "cmis:document";
325 : // The type to create needs to be fetched from the possible children types
326 : // defined in the parent folder. Then, we'll pick up the first one we find matching
327 : // cmis:folder or cmis:document (depending what we need to create).
328 : // The easy case will work in most cases, but not on some servers (like Lotus Live)
329 0 : libcmis::Folder* pParent = NULL;
330 0 : bool bTypeRestricted = false;
331 : try
332 : {
333 0 : pParent = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get( ) );
334 : }
335 0 : catch ( const libcmis::Exception& )
336 : {
337 : }
338 :
339 0 : if ( pParent )
340 : {
341 0 : map< string, libcmis::PropertyPtr >& aProperties = pParent->getProperties( );
342 0 : map< string, libcmis::PropertyPtr >::iterator it = aProperties.find( "cmis:allowedChildObjectTypeIds" );
343 0 : if ( it != aProperties.end( ) )
344 : {
345 0 : libcmis::PropertyPtr pProperty = it->second;
346 0 : if ( pProperty )
347 : {
348 0 : vector< string > typesIds = pProperty->getStrings( );
349 0 : for ( vector< string >::iterator typeIt = typesIds.begin();
350 0 : typeIt != typesIds.end() && !m_pObjectType; ++typeIt )
351 : {
352 0 : bTypeRestricted = true;
353 0 : libcmis::ObjectTypePtr type = getSession( xEnv )->getType( *typeIt );
354 :
355 : // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis
356 0 : if ( type->getBaseType( )->getId( ) == typeId )
357 0 : m_pObjectType = type;
358 0 : }
359 0 : }
360 : }
361 : }
362 :
363 0 : if ( !bTypeRestricted )
364 0 : m_pObjectType = getSession( xEnv )->getType( typeId );
365 : }
366 0 : return m_pObjectType;
367 : }
368 :
369 :
370 0 : libcmis::ObjectPtr Content::getObject( const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw ( libcmis::Exception )
371 : {
372 : // can't get the session for some reason
373 : // the recent file openning at start up is an example.
374 : try
375 : {
376 0 : if ( !getSession( xEnv ) )
377 0 : return m_pObject;
378 : }
379 0 : catch ( uno::RuntimeException& )
380 : {
381 0 : return m_pObject;
382 : }
383 0 : if ( !m_pObject.get() )
384 : {
385 0 : if ( !m_sObjectId.isEmpty( ) )
386 : {
387 : try
388 : {
389 0 : m_pObject = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId ) );
390 : }
391 0 : catch ( const libcmis::Exception& )
392 : {
393 0 : throw libcmis::Exception( "Object not found" );
394 : }
395 : }
396 0 : else if ( !m_sObjectPath.isEmpty( ) )
397 : {
398 : try
399 : {
400 0 : m_pObject = getSession( xEnv )->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath ) );
401 : }
402 0 : catch ( const libcmis::Exception& )
403 : {
404 : // In some cases, getting the object from the path doesn't work,
405 : // but getting the parent from its path and the get the child in the list is OK.
406 : // It's weird, but needed to handle case where the path isn't the folders/files
407 : // names separated by '/' (as in Lotus Live)
408 0 : INetURLObject aParentUrl( m_sURL );
409 0 : string sName = OUSTR_TO_STDSTR( aParentUrl.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ) );
410 0 : aParentUrl.removeSegment( );
411 0 : OUString sParentUrl = aParentUrl.GetMainURL( INetURLObject::NO_DECODE );
412 :
413 0 : Content aParent( m_xContext, m_pProvider, new ucbhelper::ContentIdentifier( sParentUrl ) );
414 0 : libcmis::FolderPtr pParentFolder = boost::dynamic_pointer_cast< libcmis::Folder >( aParent.getObject( xEnv ) );
415 0 : if ( pParentFolder )
416 : {
417 0 : vector< libcmis::ObjectPtr > children = pParentFolder->getChildren( );
418 0 : for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
419 0 : it != children.end() && !m_pObject; ++it )
420 : {
421 0 : if ( ( *it )->getName( ) == sName )
422 0 : m_pObject = *it;
423 0 : }
424 : }
425 :
426 0 : if ( !m_pObject )
427 0 : throw libcmis::Exception( "Object not found" );
428 : }
429 : }
430 : else
431 : {
432 0 : m_pObject = getSession( xEnv )->getRootFolder( );
433 0 : m_sObjectPath = "/";
434 0 : m_sObjectId = OUString( );
435 : }
436 : }
437 :
438 0 : return m_pObject;
439 : }
440 :
441 0 : bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv )
442 : {
443 0 : bool bIsFolder = false;
444 : try
445 : {
446 0 : libcmis::ObjectPtr obj = getObject( xEnv );
447 0 : if ( obj )
448 0 : bIsFolder = obj->getBaseType( ) == "cmis:folder";
449 : }
450 0 : catch ( const libcmis::Exception& e )
451 : {
452 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
453 : ucbhelper::cancelCommandExecution(
454 : ucb::IOErrorCode_GENERAL,
455 : uno::Sequence< uno::Any >( 0 ),
456 : xEnv,
457 0 : OUString::createFromAscii( e.what( ) ) );
458 : }
459 0 : return bIsFolder;
460 : }
461 :
462 0 : uno::Any Content::getBadArgExcept()
463 : {
464 : return uno::makeAny( lang::IllegalArgumentException(
465 : OUString("Wrong argument type!"),
466 0 : static_cast< cppu::OWeakObject * >( this ), -1) );
467 : }
468 :
469 0 : libcmis::ObjectPtr Content::updateProperties(
470 : const uno::Any& iCmisProps,
471 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
472 : {
473 : // Convert iCmisProps to Cmis Properties;
474 0 : uno::Sequence< document::CmisProperty > aPropsSeq;
475 0 : iCmisProps >>= aPropsSeq;
476 0 : map< string, libcmis::PropertyPtr > aProperties;
477 :
478 0 : sal_Int32 propsLen = aPropsSeq.getLength( );
479 0 : for ( sal_Int32 i = 0; i< propsLen; i++ )
480 : {
481 0 : std::string id = OUSTR_TO_STDSTR( aPropsSeq[i].Id );
482 0 : libcmis::PropertyPtr prop = lcl_unoToCmisProperty( aPropsSeq[i] );
483 0 : aProperties.insert( std::pair<string, libcmis::PropertyPtr>( id, prop ) );
484 0 : }
485 0 : libcmis::ObjectPtr updateObj;
486 : try
487 : {
488 0 : updateObj = getObject( xEnv )->updateProperties( aProperties );
489 : }
490 0 : catch ( const libcmis::Exception& e )
491 : {
492 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: "<< e.what( ) );
493 : }
494 :
495 0 : return updateObj;
496 : }
497 :
498 0 : uno::Reference< sdbc::XRow > Content::getPropertyValues(
499 : const uno::Sequence< beans::Property >& rProperties,
500 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
501 : {
502 0 : rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xContext );
503 :
504 : sal_Int32 nProps;
505 : const beans::Property* pProps;
506 :
507 0 : nProps = rProperties.getLength();
508 0 : pProps = rProperties.getConstArray();
509 :
510 0 : for( sal_Int32 n = 0; n < nProps; ++n )
511 : {
512 0 : const beans::Property& rProp = pProps[ n ];
513 :
514 : try
515 : {
516 0 : if ( rProp.Name == "IsDocument" )
517 : {
518 : try
519 : {
520 0 : libcmis::ObjectPtr obj = getObject( xEnv );
521 0 : if ( obj )
522 0 : xRow->appendBoolean( rProp, obj->getBaseType( ) == "cmis:document" );
523 : }
524 0 : catch ( const libcmis::Exception& )
525 : {
526 0 : if ( m_pObjectType.get( ) )
527 0 : xRow->appendBoolean( rProp, getObjectType( xEnv )->getBaseType()->getId( ) == "cmis:document" );
528 : else
529 0 : xRow->appendVoid( rProp );
530 : }
531 : }
532 0 : else if ( rProp.Name == "IsFolder" )
533 : {
534 : try
535 : {
536 0 : libcmis::ObjectPtr obj = getObject( xEnv );
537 0 : if ( obj )
538 0 : xRow->appendBoolean( rProp, obj->getBaseType( ) == "cmis:folder" );
539 : else
540 0 : xRow->appendBoolean( rProp, false );
541 : }
542 0 : catch ( const libcmis::Exception& )
543 : {
544 0 : if ( m_pObjectType.get( ) )
545 0 : xRow->appendBoolean( rProp, getObjectType( xEnv )->getBaseType()->getId( ) == "cmis:folder" );
546 : else
547 0 : xRow->appendVoid( rProp );
548 : }
549 : }
550 0 : else if ( rProp.Name == "Title" )
551 : {
552 0 : OUString sTitle;
553 : try
554 : {
555 0 : sTitle = STD_TO_OUSTR( getObject( xEnv )->getName() );
556 : }
557 0 : catch ( const libcmis::Exception& )
558 : {
559 0 : if ( !m_pObjectProps.empty() )
560 : {
561 0 : map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
562 0 : if ( it != m_pObjectProps.end( ) )
563 : {
564 0 : vector< string > values = it->second->getStrings( );
565 0 : if ( !values.empty() )
566 0 : sTitle = STD_TO_OUSTR( values.front( ) );
567 : }
568 : }
569 : }
570 :
571 : // Nothing worked... get it from the path
572 0 : if ( sTitle.isEmpty( ) )
573 : {
574 0 : OUString sPath = m_sObjectPath;
575 :
576 : // Get rid of the trailing slash problem
577 0 : if ( sPath.endsWith("/") )
578 0 : sPath = sPath.copy( 0, sPath.getLength() - 1 );
579 :
580 : // Get the last segment
581 0 : sal_Int32 nPos = sPath.lastIndexOf( '/' );
582 0 : if ( nPos >= 0 )
583 0 : sTitle = sPath.copy( nPos + 1 );
584 : }
585 :
586 0 : if ( !sTitle.isEmpty( ) )
587 0 : xRow->appendString( rProp, sTitle );
588 : else
589 0 : xRow->appendVoid( rProp );
590 : }
591 0 : else if ( rProp.Name == "ObjectId" )
592 : {
593 0 : OUString sId;
594 : try
595 : {
596 0 : sId = STD_TO_OUSTR( getObject( xEnv )->getId() );
597 : }
598 0 : catch ( const libcmis::Exception& )
599 : {
600 0 : if ( !m_pObjectProps.empty() )
601 : {
602 0 : map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:objectId" );
603 0 : if ( it != m_pObjectProps.end( ) )
604 : {
605 0 : vector< string > values = it->second->getStrings( );
606 0 : if ( !values.empty() )
607 0 : sId = STD_TO_OUSTR( values.front( ) );
608 : }
609 : }
610 : }
611 :
612 0 : if ( !sId.isEmpty( ) )
613 0 : xRow->appendString( rProp, sId );
614 : else
615 0 : xRow->appendVoid( rProp );
616 : }
617 0 : else if ( rProp.Name == "TitleOnServer" )
618 : {
619 0 : xRow->appendString( rProp, m_sObjectPath);
620 : }
621 0 : else if ( rProp.Name == "IsReadOnly" )
622 : {
623 0 : boost::shared_ptr< libcmis::AllowableActions > allowableActions = getObject( xEnv )->getAllowableActions( );
624 0 : sal_Bool bReadOnly = sal_False;
625 0 : if ( !allowableActions->isAllowed( libcmis::ObjectAction::SetContentStream ) &&
626 0 : !allowableActions->isAllowed( libcmis::ObjectAction::CheckIn ) )
627 0 : bReadOnly = sal_True;
628 :
629 0 : xRow->appendBoolean( rProp, bReadOnly );
630 : }
631 0 : else if ( rProp.Name == "DateCreated" )
632 : {
633 0 : util::DateTime aTime = lcl_boostToUnoTime( getObject( xEnv )->getCreationDate( ) );
634 0 : xRow->appendTimestamp( rProp, aTime );
635 : }
636 0 : else if ( rProp.Name == "DateModified" )
637 : {
638 0 : util::DateTime aTime = lcl_boostToUnoTime( getObject( xEnv )->getLastModificationDate( ) );
639 0 : xRow->appendTimestamp( rProp, aTime );
640 : }
641 0 : else if ( rProp.Name == "Size" )
642 : {
643 : try
644 : {
645 0 : libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get( ) );
646 0 : if ( NULL != document )
647 0 : xRow->appendLong( rProp, document->getContentLength() );
648 : else
649 0 : xRow->appendVoid( rProp );
650 : }
651 0 : catch ( const libcmis::Exception& )
652 : {
653 0 : xRow->appendVoid( rProp );
654 : }
655 : }
656 0 : else if ( rProp.Name == "CreatableContentsInfo" )
657 : {
658 0 : xRow->appendObject( rProp, uno::makeAny( queryCreatableContentsInfo( xEnv ) ) );
659 : }
660 0 : else if ( rProp.Name == "MediaType" )
661 : {
662 : try
663 : {
664 0 : libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get( ) );
665 0 : if ( NULL != document )
666 0 : xRow->appendString( rProp, STD_TO_OUSTR( document->getContentType() ) );
667 : else
668 0 : xRow->appendVoid( rProp );
669 : }
670 0 : catch ( const libcmis::Exception& )
671 : {
672 0 : xRow->appendVoid( rProp );
673 : }
674 : }
675 0 : else if ( rProp.Name == "IsVolume" )
676 : {
677 0 : xRow->appendBoolean( rProp, false );
678 : }
679 0 : else if ( rProp.Name == "IsRemote" )
680 : {
681 0 : xRow->appendBoolean( rProp, false );
682 : }
683 0 : else if ( rProp.Name == "IsRemoveable" )
684 : {
685 0 : xRow->appendBoolean( rProp, false );
686 : }
687 0 : else if ( rProp.Name == "IsFloppy" )
688 : {
689 0 : xRow->appendBoolean( rProp, false );
690 : }
691 0 : else if ( rProp.Name == "IsCompactDisc" )
692 : {
693 0 : xRow->appendBoolean( rProp, false );
694 : }
695 0 : else if ( rProp.Name == "IsHidden" )
696 : {
697 0 : xRow->appendBoolean( rProp, false );
698 : }
699 0 : else if ( rProp.Name == "TargetURL" )
700 : {
701 0 : xRow->appendString( rProp, "" );
702 : }
703 0 : else if ( rProp.Name == "BaseURI" )
704 : {
705 0 : xRow->appendString( rProp, m_aURL.getBindingUrl( ) );
706 : }
707 0 : else if ( rProp.Name == "CmisProperties" )
708 : {
709 : try
710 : {
711 0 : libcmis::ObjectPtr object = getObject( xEnv );
712 0 : map< string, libcmis::PropertyPtr >& aProperties = object->getProperties( );
713 0 : uno::Sequence< document::CmisProperty > aCmisProperties( aProperties.size( ) );
714 0 : document::CmisProperty* pCmisProps = aCmisProperties.getArray( );
715 0 : sal_Int32 i = 0;
716 0 : for ( map< string, libcmis::PropertyPtr >::iterator it = aProperties.begin();
717 0 : it != aProperties.end( ); ++it, ++i )
718 : {
719 0 : string sId = it->first;
720 0 : string sDisplayName = it->second->getPropertyType()->getDisplayName( );
721 0 : bool bUpdatable = it->second->getPropertyType()->isUpdatable( );
722 0 : bool bRequired = it->second->getPropertyType()->isRequired( );
723 0 : bool bMultiValued = it->second->getPropertyType()->isMultiValued();
724 0 : bool bOpenChoice = it->second->getPropertyType()->isOpenChoice();
725 :
726 0 : pCmisProps[i].Id = STD_TO_OUSTR( sId );
727 0 : pCmisProps[i].Name = STD_TO_OUSTR( sDisplayName );
728 0 : pCmisProps[i].Updatable = bUpdatable;
729 0 : pCmisProps[i].Required = bRequired;
730 0 : pCmisProps[i].MultiValued = bMultiValued;
731 0 : pCmisProps[i].OpenChoice = bOpenChoice;
732 0 : pCmisProps[i].Value = lcl_cmisPropertyToUno( it->second );
733 0 : switch ( it->second->getPropertyType( )->getType( ) )
734 : {
735 : default:
736 : case libcmis::PropertyType::String:
737 0 : pCmisProps[i].Type = CMIS_TYPE_STRING;
738 0 : break;
739 : case libcmis::PropertyType::Integer:
740 0 : pCmisProps[i].Type = CMIS_TYPE_INTEGER;
741 0 : break;
742 : case libcmis::PropertyType::Decimal:
743 0 : pCmisProps[i].Type = CMIS_TYPE_DECIMAL;
744 0 : break;
745 : case libcmis::PropertyType::Bool:
746 0 : pCmisProps[i].Type = CMIS_TYPE_BOOL;
747 0 : break;
748 : case libcmis::PropertyType::DateTime:
749 0 : pCmisProps[i].Type = CMIS_TYPE_DATETIME;
750 0 : break;
751 : }
752 :
753 0 : }
754 0 : xRow->appendObject( rProp.Name, uno::makeAny( aCmisProperties ) );
755 : }
756 0 : catch ( const libcmis::Exception& )
757 : {
758 0 : xRow->appendVoid( rProp );
759 : }
760 : }
761 0 : else if ( rProp.Name == "IsVersionable" )
762 : {
763 : try
764 : {
765 0 : libcmis::ObjectPtr object = getObject( xEnv );
766 0 : sal_Bool bIsVersionable = object->getTypeDescription( )->isVersionable( );
767 0 : xRow->appendBoolean( rProp, bIsVersionable );
768 : }
769 0 : catch ( const libcmis::Exception& )
770 : {
771 0 : xRow->appendVoid( rProp );
772 : }
773 : }
774 0 : else if ( rProp.Name == "CanCheckOut" )
775 : {
776 : try
777 : {
778 0 : libcmis::ObjectPtr pObject = getObject( xEnv );
779 0 : libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
780 0 : bool bAllowed = false;
781 0 : if ( aAllowables )
782 : {
783 0 : bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckOut );
784 : }
785 0 : xRow->appendBoolean( rProp, bAllowed );
786 : }
787 0 : catch ( const libcmis::Exception& )
788 : {
789 0 : xRow->appendVoid( rProp );
790 : }
791 : }
792 0 : else if ( rProp.Name == "CanCancelCheckOut" )
793 : {
794 : try
795 : {
796 0 : libcmis::ObjectPtr pObject = getObject( xEnv );
797 0 : libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
798 0 : bool bAllowed = false;
799 0 : if ( aAllowables )
800 : {
801 0 : bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CancelCheckOut );
802 : }
803 0 : xRow->appendBoolean( rProp, bAllowed );
804 : }
805 0 : catch ( const libcmis::Exception& )
806 : {
807 0 : xRow->appendVoid( rProp );
808 : }
809 : }
810 0 : else if ( rProp.Name == "CanCheckIn" )
811 : {
812 : try
813 : {
814 0 : libcmis::ObjectPtr pObject = getObject( xEnv );
815 0 : libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
816 0 : bool bAllowed = false;
817 0 : if ( aAllowables )
818 : {
819 0 : bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckIn );
820 : }
821 0 : xRow->appendBoolean( rProp, bAllowed );
822 : }
823 0 : catch ( const libcmis::Exception& )
824 : {
825 0 : xRow->appendVoid( rProp );
826 : }
827 : }
828 : else
829 : SAL_INFO( "ucb.ucp.cmis", "Looking for unsupported property " << rProp.Name );
830 : }
831 0 : catch (const libcmis::Exception&)
832 : {
833 0 : xRow->appendVoid( rProp );
834 : }
835 : }
836 :
837 0 : return uno::Reference< sdbc::XRow >( xRow.get() );
838 : }
839 :
840 0 : uno::Any Content::open(const ucb::OpenCommandArgument2 & rOpenCommand,
841 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
842 : throw( uno::Exception )
843 : {
844 0 : bool bIsFolder = isFolder( xEnv );
845 :
846 : // Handle the case of the non-existing file
847 0 : if ( !getObject( xEnv ) )
848 : {
849 0 : uno::Sequence< uno::Any > aArgs( 1 );
850 0 : aArgs[ 0 ] <<= m_xIdentifier->getContentIdentifier();
851 : uno::Any aErr = uno::makeAny(
852 : ucb::InteractiveAugmentedIOException(OUString(), static_cast< cppu::OWeakObject * >( this ),
853 : task::InteractionClassification_ERROR,
854 : bIsFolder ? ucb::IOErrorCode_NOT_EXISTING_PATH : ucb::IOErrorCode_NOT_EXISTING, aArgs)
855 0 : );
856 :
857 0 : ucbhelper::cancelCommandExecution(aErr, xEnv);
858 : }
859 :
860 0 : uno::Any aRet;
861 :
862 : sal_Bool bOpenFolder = (
863 0 : ( rOpenCommand.Mode == ucb::OpenMode::ALL ) ||
864 0 : ( rOpenCommand.Mode == ucb::OpenMode::FOLDERS ) ||
865 0 : ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENTS )
866 0 : );
867 :
868 0 : if ( bOpenFolder && bIsFolder )
869 : {
870 : uno::Reference< ucb::XDynamicResultSet > xSet
871 0 : = new DynamicResultSet(m_xContext, this, rOpenCommand, xEnv );
872 0 : aRet <<= xSet;
873 : }
874 0 : else if ( rOpenCommand.Sink.is() )
875 : {
876 0 : if (
877 0 : ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
878 0 : ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
879 : )
880 : {
881 : ucbhelper::cancelCommandExecution(
882 : uno::makeAny ( ucb::UnsupportedOpenModeException
883 : ( OUString(), static_cast< cppu::OWeakObject * >( this ),
884 : sal_Int16( rOpenCommand.Mode ) ) ),
885 0 : xEnv );
886 : }
887 :
888 0 : if ( !feedSink( rOpenCommand.Sink, xEnv ) )
889 : {
890 : // Note: rOpenCommand.Sink may contain an XStream
891 : // implementation. Support for this type of
892 : // sink is optional...
893 : SAL_INFO( "ucb.ucp.cmis", "Failed to copy data to sink" );
894 :
895 : ucbhelper::cancelCommandExecution(
896 : uno::makeAny (ucb::UnsupportedDataSinkException
897 : ( OUString(), static_cast< cppu::OWeakObject * >( this ),
898 : rOpenCommand.Sink ) ),
899 0 : xEnv );
900 : }
901 : }
902 : else
903 : SAL_INFO( "ucb.ucp.cmis", "Open falling through ..." );
904 :
905 0 : return aRet;
906 : }
907 :
908 0 : OUString Content::checkIn( const ucb::CheckinArgument& rArg,
909 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
910 : throw( uno::Exception )
911 : {
912 0 : ucbhelper::Content aSourceContent( rArg.SourceURL, xEnv, comphelper::getProcessComponentContext( ) );
913 0 : uno::Reference< io::XInputStream > xIn = aSourceContent.openStream( );
914 :
915 0 : libcmis::ObjectPtr object;
916 : try
917 : {
918 0 : object = getObject( xEnv );
919 : }
920 0 : catch ( const libcmis::Exception& )
921 : {
922 : }
923 :
924 0 : libcmis::Document* pPwc = dynamic_cast< libcmis::Document* >( object.get( ) );
925 0 : if ( !pPwc )
926 : {
927 : ucbhelper::cancelCommandExecution(
928 : ucb::IOErrorCode_GENERAL,
929 : uno::Sequence< uno::Any >( 0 ),
930 : xEnv,
931 0 : "Checkin only supported by documents" );
932 : }
933 :
934 0 : boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
935 0 : uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
936 0 : copyData( xIn, xOutput );
937 :
938 0 : map< string, libcmis::PropertyPtr > newProperties;
939 : libcmis::DocumentPtr pDoc = pPwc->checkIn( rArg.MajorVersion, OUSTR_TO_STDSTR( rArg.VersionComment ), newProperties,
940 0 : pOut, OUSTR_TO_STDSTR( rArg.MimeType ), OUSTR_TO_STDSTR( rArg.NewTitle ) );
941 :
942 : // Get the URL and send it back as a result
943 0 : URL aCmisUrl( m_sURL );
944 0 : vector< string > aPaths = pDoc->getPaths( );
945 0 : if ( !aPaths.empty() )
946 : {
947 0 : string sPath = aPaths.front( );
948 0 : aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
949 : }
950 : else
951 : {
952 : // We may have unfiled document depending on the server, those
953 : // won't have any path, use their ID instead
954 0 : string sId = pDoc->getId( );
955 0 : aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
956 : }
957 0 : return aCmisUrl.asString( );
958 : }
959 :
960 0 : OUString Content::checkOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
961 : throw( uno::Exception )
962 : {
963 0 : OUString aRet;
964 : try
965 : {
966 : // Checkout the document if possible
967 0 : libcmis::DocumentPtr pDoc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
968 0 : if ( pDoc.get( ) == NULL )
969 : {
970 : ucbhelper::cancelCommandExecution(
971 : ucb::IOErrorCode_GENERAL,
972 : uno::Sequence< uno::Any >( 0 ),
973 : xEnv,
974 0 : "Checkout only supported by documents" );
975 : }
976 0 : libcmis::DocumentPtr pPwc = pDoc->checkOut( );
977 :
978 : // Compute the URL of the Private Working Copy (PWC)
979 0 : URL aCmisUrl( m_sURL );
980 0 : vector< string > aPaths = pPwc->getPaths( );
981 0 : if ( !aPaths.empty() )
982 : {
983 0 : string sPath = aPaths.front( );
984 0 : aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
985 : }
986 : else
987 : {
988 : // We may have unfiled PWC depending on the server, those
989 : // won't have any path, use their ID instead
990 0 : string sId = pPwc->getId( );
991 0 : aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
992 : }
993 0 : aRet = aCmisUrl.asString( );
994 : }
995 0 : catch ( const libcmis::Exception& e )
996 : {
997 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
998 : ucbhelper::cancelCommandExecution(
999 : ucb::IOErrorCode_GENERAL,
1000 : uno::Sequence< uno::Any >( 0 ),
1001 : xEnv,
1002 0 : OUString::createFromAscii( e.what() ) );
1003 : }
1004 0 : return aRet;
1005 : }
1006 :
1007 0 : OUString Content::cancelCheckOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1008 : throw( uno::Exception )
1009 : {
1010 0 : OUString aRet;
1011 : try
1012 : {
1013 0 : libcmis::DocumentPtr pPwc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
1014 0 : if ( pPwc.get( ) == NULL )
1015 : {
1016 : ucbhelper::cancelCommandExecution(
1017 : ucb::IOErrorCode_GENERAL,
1018 : uno::Sequence< uno::Any >( 0 ),
1019 : xEnv,
1020 0 : "CancelCheckout only supported by documents" );
1021 : }
1022 0 : pPwc->cancelCheckout( );
1023 :
1024 : // Get the Original document (latest version)
1025 0 : vector< libcmis::DocumentPtr > aVersions = pPwc->getAllVersions( );
1026 0 : bool bFound = false;
1027 0 : for ( vector< libcmis::DocumentPtr >::iterator it = aVersions.begin();
1028 0 : it != aVersions.end( ) && !bFound; ++it )
1029 : {
1030 0 : libcmis::DocumentPtr pVersion = *it;
1031 0 : map< string, libcmis::PropertyPtr > aProps = pVersion->getProperties( );
1032 0 : bool bIsLatestVersion = false;
1033 0 : map< string, libcmis::PropertyPtr >::iterator propIt = aProps.find( string( "cmis:isLatestVersion" ) );
1034 0 : if ( propIt != aProps.end( ) && !propIt->second->getBools( ).empty( ) )
1035 : {
1036 0 : bIsLatestVersion = propIt->second->getBools( ).front( );
1037 : }
1038 :
1039 0 : if ( bIsLatestVersion )
1040 : {
1041 0 : bFound = true;
1042 : // Compute the URL of the Document
1043 0 : URL aCmisUrl( m_sURL );
1044 0 : vector< string > aPaths = pVersion->getPaths( );
1045 0 : if ( !aPaths.empty() )
1046 : {
1047 0 : string sPath = aPaths.front( );
1048 0 : aCmisUrl.setObjectPath( STD_TO_OUSTR( sPath ) );
1049 : }
1050 : else
1051 : {
1052 : // We may have unfiled doc depending on the server, those
1053 : // won't have any path, use their ID instead
1054 0 : string sId = pVersion->getId( );
1055 0 : aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
1056 : }
1057 0 : aRet = aCmisUrl.asString( );
1058 : }
1059 0 : }
1060 : }
1061 0 : catch ( const libcmis::Exception& e )
1062 : {
1063 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1064 : ucbhelper::cancelCommandExecution(
1065 : ucb::IOErrorCode_GENERAL,
1066 : uno::Sequence< uno::Any >( 0 ),
1067 : xEnv,
1068 0 : OUString::createFromAscii( e.what() ) );
1069 : }
1070 0 : return aRet;
1071 : }
1072 :
1073 0 : uno::Sequence< document::CmisVersion> Content::getAllVersions( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1074 : throw( uno::Exception, std::exception )
1075 : {
1076 : try
1077 : {
1078 : // get the document
1079 0 : libcmis::DocumentPtr pDoc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
1080 0 : if ( pDoc.get( ) == NULL )
1081 : {
1082 : ucbhelper::cancelCommandExecution(
1083 : ucb::IOErrorCode_GENERAL,
1084 : uno::Sequence< uno::Any >( 0 ),
1085 : xEnv,
1086 0 : "Can not get the document" );
1087 : }
1088 0 : vector< libcmis::DocumentPtr > aCmisVersions = pDoc->getAllVersions( );
1089 0 : uno::Sequence< document::CmisVersion > aVersions( aCmisVersions.size( ) );
1090 0 : int i = 0;
1091 0 : for ( vector< libcmis::DocumentPtr >::iterator it = aCmisVersions.begin();
1092 0 : it != aCmisVersions.end( ); ++it, ++i )
1093 : {
1094 0 : libcmis::DocumentPtr pVersion = *it;
1095 0 : aVersions[i].Id = STD_TO_OUSTR( pVersion->getId( ) );
1096 0 : aVersions[i].Author = STD_TO_OUSTR( pVersion->getCreatedBy( ) );
1097 0 : aVersions[i].TimeStamp = lcl_boostToUnoTime( pVersion->getLastModificationDate( ) );
1098 0 : aVersions[i].Comment = STD_TO_OUSTR( pVersion->getStringProperty("cmis:checkinComment") );
1099 0 : }
1100 0 : return aVersions;
1101 : }
1102 0 : catch ( const libcmis::Exception& e )
1103 : {
1104 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1105 : ucbhelper::cancelCommandExecution(
1106 : ucb::IOErrorCode_GENERAL,
1107 : uno::Sequence< uno::Any >( 0 ),
1108 : xEnv,
1109 0 : OUString::createFromAscii( e.what() ) );
1110 : }
1111 0 : return uno::Sequence< document::CmisVersion > ( );
1112 : }
1113 :
1114 0 : void Content::transfer( const ucb::TransferInfo& rTransferInfo,
1115 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1116 : throw( uno::Exception )
1117 : {
1118 : // If the source isn't on the same CMIS repository, then simply copy
1119 0 : INetURLObject aSourceUrl( rTransferInfo.SourceURL );
1120 0 : if ( aSourceUrl.GetProtocol() != INET_PROT_CMIS )
1121 : {
1122 0 : OUString sSrcBindingUrl = URL( rTransferInfo.SourceURL ).getBindingUrl( );
1123 0 : if ( sSrcBindingUrl != m_aURL.getBindingUrl( ) )
1124 : {
1125 : ucbhelper::cancelCommandExecution(
1126 : uno::makeAny(
1127 : ucb::InteractiveBadTransferURLException(
1128 : OUString("Unsupported URL scheme!"),
1129 : static_cast< cppu::OWeakObject * >( this ) ) ),
1130 0 : xEnv );
1131 0 : }
1132 : }
1133 :
1134 0 : SAL_INFO( "ucb.ucp.cmis", "TODO - Content::transfer()" );
1135 0 : }
1136 :
1137 0 : void Content::insert( const uno::Reference< io::XInputStream > & xInputStream,
1138 : sal_Bool bReplaceExisting, const OUString& rMimeType,
1139 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1140 : throw( uno::Exception )
1141 : {
1142 0 : if ( !xInputStream.is() )
1143 : {
1144 : ucbhelper::cancelCommandExecution( uno::makeAny
1145 : ( ucb::MissingInputStreamException
1146 : ( OUString(), static_cast< cppu::OWeakObject * >( this ) ) ),
1147 0 : xEnv );
1148 : }
1149 :
1150 : // For transient content, the URL is the one of the parent
1151 0 : if ( m_bTransient )
1152 : {
1153 0 : OUString sNewPath;
1154 :
1155 : // Try to get the object from the server if there is any
1156 0 : libcmis::FolderPtr pFolder;
1157 : try
1158 : {
1159 0 : pFolder = boost::dynamic_pointer_cast< libcmis::Folder >( getObject( xEnv ) );
1160 : }
1161 0 : catch ( const libcmis::Exception& )
1162 : {
1163 : }
1164 :
1165 0 : if ( pFolder != 0 )
1166 : {
1167 0 : libcmis::ObjectPtr object;
1168 0 : map< string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
1169 0 : if ( it == m_pObjectProps.end( ) )
1170 : {
1171 : ucbhelper::cancelCommandExecution( uno::makeAny
1172 : ( uno::RuntimeException( "Missing name property",
1173 : static_cast< cppu::OWeakObject * >( this ) ) ),
1174 0 : xEnv );
1175 : }
1176 0 : string newName = it->second->getStrings( ).front( );
1177 0 : string newPath = OUSTR_TO_STDSTR( m_sObjectPath );
1178 0 : if ( !newPath.empty( ) && newPath[ newPath.size( ) - 1 ] != '/' )
1179 0 : newPath += "/";
1180 0 : newPath += newName;
1181 : try
1182 : {
1183 0 : if ( !m_sObjectId.isEmpty( ) )
1184 0 : object = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId) );
1185 : else
1186 0 : object = getSession( xEnv )->getObjectByPath( newPath );
1187 0 : sNewPath = STD_TO_OUSTR( newPath );
1188 : }
1189 0 : catch ( const libcmis::Exception& )
1190 : {
1191 : // Nothing matched the path
1192 : }
1193 :
1194 0 : if ( NULL != object.get( ) )
1195 : {
1196 : // Are the base type matching?
1197 0 : if ( object->getBaseType( ) != m_pObjectType->getBaseType( )->getId() )
1198 : {
1199 : ucbhelper::cancelCommandExecution( uno::makeAny
1200 : ( uno::RuntimeException( "Can't change a folder into a document and vice-versa.",
1201 : static_cast< cppu::OWeakObject * >( this ) ) ),
1202 0 : xEnv );
1203 : }
1204 :
1205 : // Update the existing object if it's a document
1206 0 : libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get( ) );
1207 0 : if ( NULL != document )
1208 : {
1209 0 : boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
1210 0 : uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
1211 0 : copyData( xInputStream, xOutput );
1212 : try
1213 : {
1214 0 : document->setContentStream( pOut, OUSTR_TO_STDSTR( rMimeType ), string( ), bReplaceExisting );
1215 : }
1216 0 : catch ( const libcmis::Exception& )
1217 : {
1218 : ucbhelper::cancelCommandExecution( uno::makeAny
1219 : ( uno::RuntimeException( "Error when setting document content",
1220 : static_cast< cppu::OWeakObject * >( this ) ) ),
1221 0 : xEnv );
1222 0 : }
1223 : }
1224 : }
1225 : else
1226 : {
1227 : // We need to create a brand new object... either folder or document
1228 0 : bool bIsFolder = getObjectType( xEnv )->getBaseType( )->getId( ) == "cmis:folder";
1229 0 : setCmisProperty( "cmis:objectTypeId", getObjectType( xEnv )->getId( ), xEnv );
1230 :
1231 0 : if ( bIsFolder )
1232 : {
1233 : try
1234 : {
1235 0 : libcmis::FolderPtr pNew = pFolder->createFolder( m_pObjectProps );
1236 0 : sNewPath = STD_TO_OUSTR( newPath );
1237 : }
1238 0 : catch ( const libcmis::Exception& )
1239 : {
1240 : ucbhelper::cancelCommandExecution( uno::makeAny
1241 : ( uno::RuntimeException( "Error when creating folder",
1242 : static_cast< cppu::OWeakObject * >( this ) ) ),
1243 0 : xEnv );
1244 : }
1245 : }
1246 : else
1247 : {
1248 0 : boost::shared_ptr< ostream > pOut( new ostringstream ( ios_base::binary | ios_base::in | ios_base::out ) );
1249 0 : uno::Reference < io::XOutputStream > xOutput = new ucbhelper::StdOutputStream( pOut );
1250 0 : copyData( xInputStream, xOutput );
1251 : try
1252 : {
1253 0 : pFolder->createDocument( m_pObjectProps, pOut, OUSTR_TO_STDSTR( rMimeType ), string() );
1254 0 : sNewPath = STD_TO_OUSTR( newPath );
1255 : }
1256 0 : catch ( const libcmis::Exception& )
1257 : {
1258 : ucbhelper::cancelCommandExecution( uno::makeAny
1259 : ( uno::RuntimeException( "Error when creating document",
1260 : static_cast< cppu::OWeakObject * >( this ) ) ),
1261 0 : xEnv );
1262 0 : }
1263 : }
1264 : }
1265 :
1266 0 : if ( !sNewPath.isEmpty( ) || !m_sObjectId.isEmpty( ) )
1267 : {
1268 : // Update the current content: it's no longer transient
1269 0 : m_sObjectPath = sNewPath;
1270 0 : URL aUrl( m_sURL );
1271 0 : aUrl.setObjectPath( m_sObjectPath );
1272 0 : aUrl.setObjectId( m_sObjectId );
1273 0 : m_sURL = aUrl.asString( );
1274 0 : m_pObject.reset( );
1275 0 : m_pObjectType.reset( );
1276 0 : m_pObjectProps.clear( );
1277 0 : m_bTransient = false;
1278 0 : inserted();
1279 0 : }
1280 0 : }
1281 : }
1282 0 : }
1283 :
1284 : const int TRANSFER_BUFFER_SIZE = 65536;
1285 :
1286 0 : void Content::copyData(
1287 : uno::Reference< io::XInputStream > xIn,
1288 : uno::Reference< io::XOutputStream > xOut )
1289 : {
1290 0 : uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );
1291 :
1292 0 : while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
1293 0 : xOut->writeBytes( theData );
1294 :
1295 0 : xOut->closeOutput();
1296 0 : }
1297 :
1298 0 : uno::Sequence< uno::Any > Content::setPropertyValues(
1299 : const uno::Sequence< beans::PropertyValue >& rValues,
1300 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1301 : {
1302 : try
1303 : {
1304 : // Get the already set properties if possible
1305 0 : if ( !m_bTransient && getObject( xEnv ).get( ) )
1306 : {
1307 0 : m_pObjectProps.clear( );
1308 0 : m_pObjectType = getObject( xEnv )->getTypeDescription();
1309 : }
1310 : }
1311 0 : catch ( const libcmis::Exception& e )
1312 : {
1313 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1314 : ucbhelper::cancelCommandExecution(
1315 : ucb::IOErrorCode_GENERAL,
1316 : uno::Sequence< uno::Any >( 0 ),
1317 : xEnv,
1318 0 : OUString::createFromAscii( e.what() ) );
1319 : }
1320 :
1321 0 : sal_Int32 nCount = rValues.getLength();
1322 0 : uno::Sequence< uno::Any > aRet( nCount );
1323 :
1324 0 : bool bChanged = false;
1325 0 : const beans::PropertyValue* pValues = rValues.getConstArray();
1326 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
1327 : {
1328 0 : const beans::PropertyValue& rValue = pValues[ n ];
1329 0 : if ( rValue.Name == "ContentType" ||
1330 0 : rValue.Name == "MediaType" ||
1331 0 : rValue.Name == "IsDocument" ||
1332 0 : rValue.Name == "IsFolder" ||
1333 0 : rValue.Name == "Size" ||
1334 0 : rValue.Name == "CreatableContentsInfo" )
1335 : {
1336 : lang::IllegalAccessException e ( OUString("Property is read-only!"),
1337 0 : static_cast< cppu::OWeakObject* >( this ) );
1338 0 : aRet[ n ] <<= e;
1339 : }
1340 0 : else if ( rValue.Name == "Title" )
1341 : {
1342 0 : OUString aNewTitle;
1343 0 : if (!( rValue.Value >>= aNewTitle ))
1344 : {
1345 0 : aRet[ n ] <<= beans::IllegalTypeException
1346 : ( OUString("Property value has wrong type!"),
1347 0 : static_cast< cppu::OWeakObject * >( this ) );
1348 0 : continue;
1349 : }
1350 :
1351 0 : if ( aNewTitle.getLength() <= 0 )
1352 : {
1353 0 : aRet[ n ] <<= lang::IllegalArgumentException
1354 : ( OUString("Empty title not allowed!"),
1355 0 : static_cast< cppu::OWeakObject * >( this ), -1 );
1356 0 : continue;
1357 :
1358 : }
1359 :
1360 0 : setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle ), xEnv );
1361 0 : bChanged = true;
1362 : }
1363 : else
1364 : {
1365 : SAL_INFO( "ucb.ucp.cmis", "Couln't set property: " << rValue.Name );
1366 : lang::IllegalAccessException e ( OUString("Property is read-only!"),
1367 0 : static_cast< cppu::OWeakObject* >( this ) );
1368 0 : aRet[ n ] <<= e;
1369 : }
1370 : }
1371 :
1372 : try
1373 : {
1374 0 : if ( !m_bTransient && bChanged )
1375 : {
1376 0 : getObject( xEnv )->updateProperties( m_pObjectProps );
1377 : }
1378 : }
1379 0 : catch ( const libcmis::Exception& e )
1380 : {
1381 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1382 : ucbhelper::cancelCommandExecution(
1383 : ucb::IOErrorCode_GENERAL,
1384 : uno::Sequence< uno::Any >( 0 ),
1385 : xEnv,
1386 0 : OUString::createFromAscii( e.what() ) );
1387 : }
1388 :
1389 0 : return aRet;
1390 : }
1391 :
1392 0 : sal_Bool Content::feedSink( uno::Reference< uno::XInterface> xSink,
1393 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1394 : {
1395 0 : if ( !xSink.is() )
1396 0 : return sal_False;
1397 :
1398 0 : uno::Reference< io::XOutputStream > xOut = uno::Reference< io::XOutputStream >(xSink, uno::UNO_QUERY );
1399 0 : uno::Reference< io::XActiveDataSink > xDataSink = uno::Reference< io::XActiveDataSink >(xSink, uno::UNO_QUERY );
1400 0 : uno::Reference< io::XActiveDataStreamer > xDataStreamer = uno::Reference< io::XActiveDataStreamer >( xSink, uno::UNO_QUERY );
1401 :
1402 0 : if ( !xOut.is() && !xDataSink.is() && ( !xDataStreamer.is() || !xDataStreamer->getStream().is() ) )
1403 0 : return sal_False;
1404 :
1405 0 : if ( xDataStreamer.is() && !xOut.is() )
1406 0 : xOut = xDataStreamer->getStream()->getOutputStream();
1407 :
1408 : try
1409 : {
1410 0 : libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get() );
1411 :
1412 0 : if (!document)
1413 0 : return sal_False;
1414 :
1415 0 : boost::shared_ptr< istream > aIn = document->getContentStream( );
1416 :
1417 0 : uno::Reference< io::XInputStream > xIn = new ucbhelper::StdInputStream( aIn );
1418 0 : if( !xIn.is( ) )
1419 0 : return sal_False;
1420 :
1421 0 : if ( xDataSink.is() )
1422 0 : xDataSink->setInputStream( xIn );
1423 0 : else if ( xOut.is() )
1424 0 : copyData( xIn, xOut );
1425 : }
1426 0 : catch ( const libcmis::Exception& e )
1427 : {
1428 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1429 : ucbhelper::cancelCommandExecution(
1430 : ucb::IOErrorCode_GENERAL,
1431 : uno::Sequence< uno::Any >( 0 ),
1432 : xEnv,
1433 0 : OUString::createFromAscii( e.what() ) );
1434 : }
1435 :
1436 0 : return sal_True;
1437 : }
1438 :
1439 0 : uno::Sequence< beans::Property > Content::getProperties(
1440 : const uno::Reference< ucb::XCommandEnvironment > & )
1441 : {
1442 : static const beans::Property aGenericProperties[] =
1443 : {
1444 : beans::Property( OUString( "IsDocument" ),
1445 0 : -1, getCppuBooleanType(),
1446 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1447 : beans::Property( OUString( "IsFolder" ),
1448 0 : -1, getCppuBooleanType(),
1449 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1450 : beans::Property( OUString( "Title" ),
1451 0 : -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1452 : beans::PropertyAttribute::BOUND ),
1453 : beans::Property( OUString( "ObjectId" ),
1454 0 : -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1455 : beans::PropertyAttribute::BOUND ),
1456 : beans::Property( OUString( "TitleOnServer" ),
1457 0 : -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1458 : beans::PropertyAttribute::BOUND ),
1459 : beans::Property( OUString( "IsReadOnly" ),
1460 0 : -1, getCppuBooleanType(),
1461 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1462 : beans::Property( OUString( "DateCreated" ),
1463 0 : -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ),
1464 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1465 : beans::Property( OUString( "DateModified" ),
1466 0 : -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ),
1467 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1468 : beans::Property( OUString( "Size" ),
1469 0 : -1, getCppuType( static_cast< const sal_Int64 * >( 0 ) ),
1470 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1471 : beans::Property( OUString( "CreatableContentsInfo" ),
1472 0 : -1, getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
1473 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1474 : beans::Property( OUString( "MediaType" ),
1475 0 : -1, getCppuType( static_cast< const OUString * >( 0 ) ),
1476 : beans::PropertyAttribute::BOUND ),
1477 : beans::Property( OUString( "CmisProperties" ),
1478 0 : -1, getCppuType( static_cast< const uno::Sequence< document::CmisProperty> * >( 0 ) ),
1479 : beans::PropertyAttribute::BOUND ),
1480 : beans::Property( OUString( "IsVersionable" ),
1481 0 : -1, getCppuBooleanType(),
1482 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1483 : beans::Property( OUString( "CanCheckOut" ),
1484 0 : -1, getCppuBooleanType(),
1485 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1486 : beans::Property( OUString( "CanCancelCheckOut" ),
1487 0 : -1, getCppuBooleanType(),
1488 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1489 : beans::Property( OUString( "CanCheckIn" ),
1490 0 : -1, getCppuBooleanType(),
1491 : beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ),
1492 0 : };
1493 :
1494 0 : const int nProps = SAL_N_ELEMENTS(aGenericProperties);
1495 0 : return uno::Sequence< beans::Property > ( aGenericProperties, nProps );
1496 : }
1497 :
1498 0 : uno::Sequence< ucb::CommandInfo > Content::getCommands(
1499 : const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1500 : {
1501 : static const ucb::CommandInfo aCommandInfoTable[] =
1502 : {
1503 : // Required commands
1504 : ucb::CommandInfo
1505 : ( OUString( "getCommandInfo" ),
1506 0 : -1, getCppuVoidType() ),
1507 : ucb::CommandInfo
1508 : ( OUString( "getPropertySetInfo" ),
1509 0 : -1, getCppuVoidType() ),
1510 : ucb::CommandInfo
1511 : ( OUString( "getPropertyValues" ),
1512 0 : -1, getCppuType( static_cast<uno::Sequence< beans::Property > * >( 0 ) ) ),
1513 : ucb::CommandInfo
1514 : ( OUString( "setPropertyValues" ),
1515 0 : -1, getCppuType( static_cast<uno::Sequence< beans::PropertyValue > * >( 0 ) ) ),
1516 :
1517 : // Optional standard commands
1518 : ucb::CommandInfo
1519 : ( OUString( "delete" ),
1520 0 : -1, getCppuBooleanType() ),
1521 : ucb::CommandInfo
1522 : ( OUString( "insert" ),
1523 0 : -1, getCppuType( static_cast<ucb::InsertCommandArgument2 * >( 0 ) ) ),
1524 : ucb::CommandInfo
1525 : ( OUString( "open" ),
1526 0 : -1, getCppuType( static_cast<ucb::OpenCommandArgument2 * >( 0 ) ) ),
1527 :
1528 : // Mandatory CMIS-only commands
1529 0 : ucb::CommandInfo ( OUString( "checkout" ), -1, getCppuVoidType() ),
1530 0 : ucb::CommandInfo ( OUString( "cancelCheckout" ), -1, getCppuVoidType() ),
1531 : ucb::CommandInfo ( OUString( "checkIn" ), -1,
1532 0 : getCppuType( static_cast<ucb::TransferInfo * >( 0 ) ) ),
1533 0 : ucb::CommandInfo ( OUString( "updateProperties" ), -1, getCppuVoidType() ),
1534 : ucb::CommandInfo
1535 : ( OUString( "getAllVersions" ),
1536 0 : -1, getCppuType( static_cast<uno::Sequence< document::CmisVersion > * >( 0 ) ) ),
1537 :
1538 :
1539 : // Folder Only, omitted if not a folder
1540 : ucb::CommandInfo
1541 : ( OUString( "transfer" ),
1542 0 : -1, getCppuType( static_cast<ucb::TransferInfo * >( 0 ) ) ),
1543 : ucb::CommandInfo
1544 : ( OUString( "createNewContent" ),
1545 0 : -1, getCppuType( static_cast<ucb::ContentInfo * >( 0 ) ) )
1546 0 : };
1547 :
1548 0 : const int nProps = SAL_N_ELEMENTS( aCommandInfoTable );
1549 0 : return uno::Sequence< ucb::CommandInfo >(aCommandInfoTable, isFolder( xEnv ) ? nProps : nProps - 2);
1550 : }
1551 :
1552 0 : OUString Content::getParentURL( )
1553 : {
1554 : SAL_INFO( "ucb.ucp.cmis", "Content::getParentURL()" );
1555 0 : OUString parentUrl = "/";
1556 0 : if ( m_sObjectPath == "/" )
1557 0 : return parentUrl;
1558 : else
1559 : {
1560 0 : INetURLObject aUrl( m_sURL );
1561 0 : if ( aUrl.getSegmentCount( ) > 0 )
1562 : {
1563 0 : URL aCmisUrl( m_sURL );
1564 0 : aUrl.removeSegment( );
1565 0 : aCmisUrl.setObjectPath( aUrl.GetURLPath( INetURLObject::DECODE_WITH_CHARSET ) );
1566 0 : parentUrl = aCmisUrl.asString( );
1567 0 : }
1568 : }
1569 0 : return parentUrl;
1570 : }
1571 :
1572 0 : XTYPEPROVIDER_COMMON_IMPL( Content );
1573 :
1574 0 : void SAL_CALL Content::acquire() throw()
1575 : {
1576 0 : ContentImplHelper::acquire();
1577 0 : }
1578 :
1579 0 : void SAL_CALL Content::release() throw()
1580 : {
1581 0 : ContentImplHelper::release();
1582 0 : }
1583 :
1584 0 : uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) throw ( uno::RuntimeException, std::exception )
1585 : {
1586 0 : uno::Any aRet = cppu::queryInterface( rType, static_cast< ucb::XContentCreator * >( this ) );
1587 0 : return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface(rType);
1588 : }
1589 :
1590 0 : OUString SAL_CALL Content::getImplementationName() throw( uno::RuntimeException, std::exception )
1591 : {
1592 0 : return OUString("com.sun.star.comp.CmisContent");
1593 : }
1594 :
1595 0 : uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
1596 : throw( uno::RuntimeException, std::exception )
1597 : {
1598 0 : uno::Sequence< OUString > aSNS( 1 );
1599 0 : aSNS.getArray()[ 0 ] = "com.sun.star.ucb.CmisContent";
1600 0 : return aSNS;
1601 : }
1602 :
1603 0 : OUString SAL_CALL Content::getContentType() throw( uno::RuntimeException, std::exception )
1604 : {
1605 0 : return isFolder( uno::Reference< ucb::XCommandEnvironment >() )
1606 : ? OUString(CMIS_FOLDER_TYPE)
1607 0 : : OUString(CMIS_FILE_TYPE);
1608 : }
1609 :
1610 0 : uno::Any SAL_CALL Content::execute(
1611 : const ucb::Command& aCommand,
1612 : sal_Int32 /*CommandId*/,
1613 : const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1614 : throw( uno::Exception, ucb::CommandAbortedException, uno::RuntimeException, std::exception )
1615 : {
1616 : SAL_INFO( "ucb.ucp.cmis", "Content::execute( ) - " << aCommand.Name );
1617 0 : uno::Any aRet;
1618 :
1619 0 : if ( aCommand.Name == "getPropertyValues" )
1620 : {
1621 0 : uno::Sequence< beans::Property > Properties;
1622 0 : if ( !( aCommand.Argument >>= Properties ) )
1623 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1624 0 : aRet <<= getPropertyValues( Properties, xEnv );
1625 : }
1626 0 : else if ( aCommand.Name == "getPropertySetInfo" )
1627 0 : aRet <<= getPropertySetInfo( xEnv, false );
1628 0 : else if ( aCommand.Name == "getCommandInfo" )
1629 0 : aRet <<= getCommandInfo( xEnv, false );
1630 0 : else if ( aCommand.Name == "open" )
1631 : {
1632 0 : ucb::OpenCommandArgument2 aOpenCommand;
1633 0 : if ( !( aCommand.Argument >>= aOpenCommand ) )
1634 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1635 0 : aRet = open( aOpenCommand, xEnv );
1636 : }
1637 0 : else if ( aCommand.Name == "transfer" )
1638 : {
1639 0 : ucb::TransferInfo transferArgs;
1640 0 : if ( !( aCommand.Argument >>= transferArgs ) )
1641 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1642 0 : transfer( transferArgs, xEnv );
1643 : }
1644 0 : else if ( aCommand.Name == "setPropertyValues" )
1645 : {
1646 0 : uno::Sequence< beans::PropertyValue > aProperties;
1647 0 : if ( !( aCommand.Argument >>= aProperties ) || !aProperties.getLength() )
1648 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1649 0 : aRet <<= setPropertyValues( aProperties, xEnv );
1650 : }
1651 0 : else if (aCommand.Name == "createNewContent"
1652 0 : && isFolder( xEnv ) )
1653 : {
1654 0 : ucb::ContentInfo arg;
1655 0 : if ( !( aCommand.Argument >>= arg ) )
1656 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1657 0 : aRet <<= createNewContent( arg );
1658 : }
1659 0 : else if ( aCommand.Name == "insert" )
1660 : {
1661 0 : ucb::InsertCommandArgument2 arg;
1662 0 : if ( !( aCommand.Argument >>= arg ) )
1663 : {
1664 0 : ucb::InsertCommandArgument insertArg;
1665 0 : if ( !( aCommand.Argument >>= insertArg ) )
1666 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
1667 :
1668 0 : arg.Data = insertArg.Data;
1669 0 : arg.ReplaceExisting = insertArg.ReplaceExisting;
1670 : }
1671 : // store the document id
1672 0 : m_sObjectId = arg.DocumentId;
1673 0 : insert( arg.Data, arg.ReplaceExisting, arg.MimeType, xEnv );
1674 : }
1675 0 : else if ( aCommand.Name == "delete" )
1676 : {
1677 : try
1678 : {
1679 0 : if ( !isFolder( xEnv ) )
1680 : {
1681 0 : getObject( xEnv )->remove( );
1682 : }
1683 : else
1684 : {
1685 0 : libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get() );
1686 0 : if (folder)
1687 0 : folder->removeTree( );
1688 : }
1689 : }
1690 0 : catch ( const libcmis::Exception& e )
1691 : {
1692 : SAL_INFO( "ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what( ) );
1693 : ucbhelper::cancelCommandExecution(
1694 : ucb::IOErrorCode_GENERAL,
1695 : uno::Sequence< uno::Any >( 0 ),
1696 : xEnv,
1697 0 : OUString::createFromAscii( e.what() ) );
1698 : }
1699 : }
1700 0 : else if ( aCommand.Name == "checkout" )
1701 : {
1702 0 : aRet <<= checkOut( xEnv );
1703 : }
1704 0 : else if ( aCommand.Name == "cancelCheckout" )
1705 : {
1706 0 : aRet <<= cancelCheckOut( xEnv );
1707 : }
1708 0 : else if ( aCommand.Name == "checkin" )
1709 : {
1710 0 : ucb::CheckinArgument aArg;
1711 0 : if ( !( aCommand.Argument >>= aArg ) )
1712 : {
1713 0 : ucbhelper::cancelCommandExecution ( getBadArgExcept(), xEnv );
1714 : }
1715 0 : aRet <<= checkIn( aArg, xEnv );
1716 : }
1717 0 : else if ( aCommand.Name == "getAllVersions" )
1718 : {
1719 0 : aRet <<= getAllVersions( xEnv );
1720 : }
1721 0 : else if ( aCommand.Name == "updateProperties" )
1722 : {
1723 0 : updateProperties( aCommand.Argument, xEnv );
1724 : }
1725 : else
1726 : {
1727 : SAL_INFO( "ucb.ucp.cmis", "Unknown command to execute" );
1728 :
1729 : ucbhelper::cancelCommandExecution
1730 : ( uno::makeAny( ucb::UnsupportedCommandException
1731 : ( OUString(),
1732 : static_cast< cppu::OWeakObject * >( this ) ) ),
1733 0 : xEnv );
1734 : }
1735 :
1736 0 : return aRet;
1737 : }
1738 :
1739 0 : void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) throw( uno::RuntimeException, std::exception )
1740 : {
1741 : SAL_INFO( "ucb.ucp.cmis", "TODO - Content::abort()" );
1742 : // TODO Implement me
1743 0 : }
1744 :
1745 0 : uno::Sequence< ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo()
1746 : throw( uno::RuntimeException, std::exception )
1747 : {
1748 0 : return queryCreatableContentsInfo( uno::Reference< ucb::XCommandEnvironment >() );
1749 : }
1750 :
1751 0 : uno::Reference< ucb::XContent > SAL_CALL Content::createNewContent(
1752 : const ucb::ContentInfo& Info ) throw( uno::RuntimeException, std::exception )
1753 : {
1754 : bool create_document;
1755 :
1756 0 : if ( Info.Type == CMIS_FILE_TYPE )
1757 0 : create_document = true;
1758 0 : else if ( Info.Type == CMIS_FOLDER_TYPE )
1759 0 : create_document = false;
1760 : else
1761 : {
1762 : SAL_INFO( "ucb.ucp.cmis", "Unknown type of content to create" );
1763 0 : return uno::Reference< ucb::XContent >();
1764 : }
1765 :
1766 0 : OUString sParentURL = m_xIdentifier->getContentIdentifier();
1767 0 : URL aParentURL( sParentURL );
1768 :
1769 : // Set the parent URL for the transient objects
1770 0 : uno::Reference< ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(sParentURL));
1771 :
1772 : try
1773 : {
1774 0 : return new ::cmis::Content( m_xContext, m_pProvider, xId, !create_document );
1775 : }
1776 0 : catch ( ucb::ContentCreationException & )
1777 : {
1778 0 : return uno::Reference< ucb::XContent >();
1779 0 : }
1780 : }
1781 :
1782 0 : uno::Sequence< uno::Type > SAL_CALL Content::getTypes() throw( uno::RuntimeException, std::exception )
1783 : {
1784 0 : if ( isFolder( uno::Reference< ucb::XCommandEnvironment >() ) )
1785 : {
1786 : static cppu::OTypeCollection aFolderCollection
1787 0 : (CPPU_TYPE_REF( lang::XTypeProvider ),
1788 0 : CPPU_TYPE_REF( lang::XServiceInfo ),
1789 0 : CPPU_TYPE_REF( lang::XComponent ),
1790 0 : CPPU_TYPE_REF( ucb::XContent ),
1791 0 : CPPU_TYPE_REF( ucb::XCommandProcessor ),
1792 0 : CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
1793 0 : CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
1794 0 : CPPU_TYPE_REF( beans::XPropertyContainer ),
1795 0 : CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
1796 0 : CPPU_TYPE_REF( container::XChild ),
1797 0 : CPPU_TYPE_REF( ucb::XContentCreator ) );
1798 0 : return aFolderCollection.getTypes();
1799 : }
1800 : else
1801 : {
1802 : static cppu::OTypeCollection aFileCollection
1803 0 : (CPPU_TYPE_REF( lang::XTypeProvider ),
1804 0 : CPPU_TYPE_REF( lang::XServiceInfo ),
1805 0 : CPPU_TYPE_REF( lang::XComponent ),
1806 0 : CPPU_TYPE_REF( ucb::XContent ),
1807 0 : CPPU_TYPE_REF( ucb::XCommandProcessor ),
1808 0 : CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
1809 0 : CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
1810 0 : CPPU_TYPE_REF( beans::XPropertyContainer ),
1811 0 : CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
1812 0 : CPPU_TYPE_REF( container::XChild ) );
1813 :
1814 0 : return aFileCollection.getTypes();
1815 : }
1816 : }
1817 :
1818 :
1819 0 : uno::Sequence< ucb::ContentInfo > Content::queryCreatableContentsInfo(
1820 : const uno::Reference< ucb::XCommandEnvironment >& xEnv)
1821 : throw( uno::RuntimeException )
1822 : {
1823 0 : if ( isFolder( xEnv ) )
1824 : {
1825 0 : uno::Sequence< ucb::ContentInfo > seq(2);
1826 :
1827 : // Minimum set of props we really need
1828 0 : uno::Sequence< beans::Property > props( 1 );
1829 0 : props[0] = beans::Property(
1830 : OUString("Title"),
1831 : -1,
1832 0 : getCppuType( static_cast< OUString* >( 0 ) ),
1833 0 : beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND );
1834 :
1835 : // file
1836 0 : seq[0].Type = CMIS_FILE_TYPE;
1837 0 : seq[0].Attributes = ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM |
1838 0 : ucb::ContentInfoAttribute::KIND_DOCUMENT );
1839 0 : seq[0].Properties = props;
1840 :
1841 : // folder
1842 0 : seq[1].Type = CMIS_FOLDER_TYPE;
1843 0 : seq[1].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER;
1844 0 : seq[1].Properties = props;
1845 :
1846 0 : return seq;
1847 : }
1848 : else
1849 : {
1850 0 : return uno::Sequence< ucb::ContentInfo >();
1851 : }
1852 : }
1853 :
1854 0 : list< uno::Reference< ucb::XContent > > Content::getChildren( )
1855 : {
1856 0 : list< uno::Reference< ucb::XContent > > results;
1857 : SAL_INFO( "ucb.ucp.cmis", "Content::getChildren() " << m_sURL );
1858 :
1859 0 : libcmis::FolderPtr pFolder = boost::dynamic_pointer_cast< libcmis::Folder >( getObject( uno::Reference< ucb::XCommandEnvironment >() ) );
1860 0 : if ( 0 != pFolder )
1861 : {
1862 : // Get the children from pObject
1863 : try
1864 : {
1865 0 : vector< libcmis::ObjectPtr > children = pFolder->getChildren( );
1866 :
1867 : // Loop over the results
1868 0 : for ( vector< libcmis::ObjectPtr >::iterator it = children.begin();
1869 0 : it != children.end(); ++it )
1870 : {
1871 : // TODO Cache the objects
1872 :
1873 0 : URL aUrl( m_sURL );
1874 0 : OUString sPath( m_sObjectPath );
1875 0 : if ( !sPath.endsWith("/") )
1876 0 : sPath += "/";
1877 0 : sPath += STD_TO_OUSTR( ( *it )->getName( ) );
1878 0 : OUString sId = STD_TO_OUSTR( ( *it )->getId( ) );
1879 0 : aUrl.setObjectId( sId );
1880 0 : aUrl.setObjectPath( sPath );
1881 0 : uno::Reference< ucb::XContentIdentifier > xId = new ucbhelper::ContentIdentifier( aUrl.asString( ) );
1882 0 : uno::Reference< ucb::XContent > xContent = new Content( m_xContext, m_pProvider, xId, *it );
1883 :
1884 0 : results.push_back( xContent );
1885 0 : }
1886 : }
1887 0 : catch ( const libcmis::Exception& e )
1888 : {
1889 : SAL_INFO( "ucb.ucp.cmis", "Exception thrown: " << e.what() );
1890 : }
1891 : }
1892 :
1893 0 : return results;
1894 : }
1895 :
1896 0 : void Content::setCmisProperty( std::string sName, std::string sValue, const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1897 : {
1898 0 : if ( getObjectType( xEnv ).get( ) )
1899 : {
1900 0 : map< string, libcmis::PropertyPtr >::iterator propIt = m_pObjectProps.find( sName );
1901 0 : vector< string > values;
1902 0 : values.push_back( sValue );
1903 :
1904 0 : if ( propIt == m_pObjectProps.end( ) && getObjectType( xEnv ).get( ) )
1905 : {
1906 0 : map< string, libcmis::PropertyTypePtr > propsTypes = getObjectType( xEnv )->getPropertiesTypes( );
1907 0 : map< string, libcmis::PropertyTypePtr >::iterator typeIt = propsTypes.find( sName );
1908 :
1909 0 : if ( typeIt != propsTypes.end( ) )
1910 : {
1911 0 : libcmis::PropertyTypePtr propType = typeIt->second;
1912 0 : libcmis::PropertyPtr property( new libcmis::Property( propType, values ) );
1913 0 : m_pObjectProps.insert( pair< string, libcmis::PropertyPtr >( sName, property ) );
1914 0 : }
1915 : }
1916 0 : else if ( propIt != m_pObjectProps.end( ) )
1917 : {
1918 0 : propIt->second->setValues( values );
1919 0 : }
1920 : }
1921 0 : }
1922 0 : }
1923 :
1924 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|