xref: /aoo42x/main/ucb/source/ucp/tdoc/tdoc_content.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_ucb.hxx"
30 
31 /**************************************************************************
32                                 TODO
33  **************************************************************************
34 
35  *************************************************************************/
36 
37 #include "osl/diagnose.h"
38 #include "osl/doublecheckedlocking.h"
39 #include "rtl/ustrbuf.hxx"
40 
41 #include "com/sun/star/beans/PropertyAttribute.hpp"
42 #include "com/sun/star/beans/PropertyValue.hpp"
43 #include "com/sun/star/beans/XPropertySet.hpp"
44 #include "com/sun/star/embed/ElementModes.hpp"
45 #include "com/sun/star/embed/XStorage.hpp"
46 #include "com/sun/star/embed/XTransactedObject.hpp"
47 #include "com/sun/star/io/XActiveDataSink.hpp"
48 #include "com/sun/star/io/XActiveDataStreamer.hpp"
49 #include "com/sun/star/lang/IllegalAccessException.hpp"
50 #include "com/sun/star/sdbc/XRow.hpp"
51 #include "com/sun/star/ucb/ContentAction.hpp"
52 #include "com/sun/star/ucb/ContentInfoAttribute.hpp"
53 #include "com/sun/star/ucb/InsertCommandArgument.hpp"
54 #include "com/sun/star/ucb/InteractiveBadTransferURLException.hpp"
55 #include "com/sun/star/ucb/MissingInputStreamException.hpp"
56 #include "com/sun/star/ucb/MissingPropertiesException.hpp"
57 #include "com/sun/star/ucb/NameClash.hpp"
58 #include "com/sun/star/ucb/NameClashException.hpp"
59 #include "com/sun/star/ucb/OpenCommandArgument2.hpp"
60 #include "com/sun/star/ucb/OpenMode.hpp"
61 #include "com/sun/star/ucb/TransferInfo.hpp"
62 #include "com/sun/star/ucb/UnsupportedCommandException.hpp"
63 #include "com/sun/star/ucb/UnsupportedDataSinkException.hpp"
64 #include "com/sun/star/ucb/UnsupportedNameClashException.hpp"
65 #include "com/sun/star/ucb/UnsupportedOpenModeException.hpp"
66 #include "com/sun/star/ucb/XCommandInfo.hpp"
67 #include "com/sun/star/ucb/XPersistentPropertySet.hpp"
68 
69 #include "ucbhelper/cancelcommandexecution.hxx"
70 #include "ucbhelper/contentidentifier.hxx"
71 #include "ucbhelper/propertyvalueset.hxx"
72 
73 #include "tdoc_content.hxx"
74 #include "tdoc_resultset.hxx"
75 #include "tdoc_passwordrequest.hxx"
76 
77 #include "../inc/urihelper.hxx"
78 
79 using namespace com::sun::star;
80 using namespace tdoc_ucp;
81 
82 //=========================================================================
83 static ContentType lcl_getContentType( const rtl::OUString & rType )
84 {
85     if ( rType.equalsAsciiL(
86                 RTL_CONSTASCII_STRINGPARAM( TDOC_ROOT_CONTENT_TYPE ) ) )
87         return ROOT;
88     else if ( rType.equalsAsciiL(
89                 RTL_CONSTASCII_STRINGPARAM( TDOC_DOCUMENT_CONTENT_TYPE ) ) )
90         return DOCUMENT;
91     else if ( rType.equalsAsciiL(
92                 RTL_CONSTASCII_STRINGPARAM( TDOC_FOLDER_CONTENT_TYPE ) ) )
93         return FOLDER;
94     else if ( rType.equalsAsciiL(
95                 RTL_CONSTASCII_STRINGPARAM( TDOC_STREAM_CONTENT_TYPE ) ) )
96         return STREAM;
97     else
98     {
99         OSL_ENSURE( sal_False,
100                     "Content::Content - unsupported content type string" );
101         return STREAM;
102     }
103 }
104 
105 //=========================================================================
106 //=========================================================================
107 //
108 // Content Implementation.
109 //
110 //=========================================================================
111 //=========================================================================
112 
113 // static ( "virtual" ctor )
114 Content* Content::create(
115             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
116             ContentProvider* pProvider,
117             const uno::Reference< ucb::XContentIdentifier >& Identifier )
118 {
119     // Fail, if resource does not exist.
120     ContentProperties aProps;
121     if ( !Content::loadData( pProvider,
122                              Uri( Identifier->getContentIdentifier() ),
123                              aProps ) )
124         return 0;
125 
126     return new Content( rxSMgr, pProvider, Identifier, aProps );
127 }
128 
129 //=========================================================================
130 // static ( "virtual" ctor )
131 Content* Content::create(
132             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
133             ContentProvider* pProvider,
134             const uno::Reference< ucb::XContentIdentifier >& Identifier,
135             const ucb::ContentInfo& Info )
136 {
137     if ( !Info.Type.getLength() )
138         return 0;
139 
140     if ( !Info.Type.equalsAsciiL(
141             RTL_CONSTASCII_STRINGPARAM( TDOC_FOLDER_CONTENT_TYPE ) ) &&
142          !Info.Type.equalsAsciiL(
143             RTL_CONSTASCII_STRINGPARAM( TDOC_STREAM_CONTENT_TYPE ) ) )
144     {
145         OSL_ENSURE( sal_False, "Content::create - unsupported content type!" );
146         return 0;
147     }
148 
149 #if 0
150     // Fail, if content does exist.
151     if ( Content::hasData( pProvider,
152                            Uri( Identifier->getContentIdentifier() ) ) )
153         return 0;
154 #endif
155 
156     return new Content( rxSMgr, pProvider, Identifier, Info );
157 }
158 
159 //=========================================================================
160 Content::Content(
161             const uno::Reference< lang::XMultiServiceFactory > & rxSMgr,
162             ContentProvider * pProvider,
163             const uno::Reference< ucb::XContentIdentifier > & Identifier,
164             const ContentProperties & rProps )
165 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
166   m_aProps( rProps ),
167   m_eState( PERSISTENT ),
168   m_pProvider( pProvider )
169 {
170 }
171 
172 //=========================================================================
173 // ctor for a content just created via XContentCreator::createNewContent()
174 Content::Content(
175             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
176             ContentProvider* pProvider,
177             const uno::Reference< ucb::XContentIdentifier >& Identifier,
178             const ucb::ContentInfo& Info )
179   : ContentImplHelper( rxSMgr, pProvider, Identifier ),
180   m_aProps( lcl_getContentType( Info.Type ), rtl::OUString() ), // no Title (yet)
181   m_eState( TRANSIENT ),
182   m_pProvider( pProvider )
183 {
184 }
185 
186 //=========================================================================
187 // virtual
188 Content::~Content()
189 {
190 }
191 
192 //=========================================================================
193 //
194 // XInterface methods.
195 //
196 //=========================================================================
197 
198 // virtual
199 void SAL_CALL Content::acquire()
200     throw( )
201 {
202     ContentImplHelper::acquire();
203 }
204 
205 //=========================================================================
206 // virtual
207 void SAL_CALL Content::release()
208     throw( )
209 {
210     ContentImplHelper::release();
211 }
212 
213 //=========================================================================
214 // virtual
215 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
216     throw ( uno::RuntimeException )
217 {
218     uno::Any aRet = ContentImplHelper::queryInterface( rType );
219 
220     if ( !aRet.hasValue() )
221     {
222         aRet = cppu::queryInterface(
223                 rType, static_cast< ucb::XContentCreator * >( this ) );
224         if ( aRet.hasValue() )
225         {
226             if ( !m_aProps.isContentCreator() )
227                 return uno::Any();
228         }
229     }
230 
231     return aRet;
232 }
233 
234 //=========================================================================
235 //
236 // XTypeProvider methods.
237 //
238 //=========================================================================
239 
240 XTYPEPROVIDER_COMMON_IMPL( Content );
241 
242 //=========================================================================
243 // virtual
244 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
245     throw( uno::RuntimeException )
246 {
247     cppu::OTypeCollection * pCollection = 0;
248 
249     if ( m_aProps.isContentCreator() )
250     {
251         static cppu::OTypeCollection* pFolderTypes = 0;
252 
253         pCollection = pFolderTypes;
254         if ( !pCollection )
255         {
256             osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
257 
258             pCollection = pFolderTypes;
259             if ( !pCollection )
260             {
261                 static cppu::OTypeCollection aCollection(
262                     CPPU_TYPE_REF( lang::XTypeProvider ),
263                     CPPU_TYPE_REF( lang::XServiceInfo ),
264                     CPPU_TYPE_REF( lang::XComponent ),
265                     CPPU_TYPE_REF( ucb::XContent ),
266                     CPPU_TYPE_REF( ucb::XCommandProcessor ),
267                     CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
268                     CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
269                     CPPU_TYPE_REF( beans::XPropertyContainer ),
270                     CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
271                     CPPU_TYPE_REF( container::XChild ),
272                     CPPU_TYPE_REF( ucb::XContentCreator ) ); // !!
273                 pCollection = &aCollection;
274                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
275                 pFolderTypes = pCollection;
276             }
277         }
278         else {
279             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
280         }
281     }
282     else
283     {
284         static cppu::OTypeCollection* pDocumentTypes = 0;
285 
286         pCollection = pDocumentTypes;
287         if ( !pCollection )
288         {
289             osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
290 
291             pCollection = pDocumentTypes;
292             if ( !pCollection )
293             {
294                 static cppu::OTypeCollection aCollection(
295                     CPPU_TYPE_REF( lang::XTypeProvider ),
296                     CPPU_TYPE_REF( lang::XServiceInfo ),
297                     CPPU_TYPE_REF( lang::XComponent ),
298                     CPPU_TYPE_REF( ucb::XContent ),
299                     CPPU_TYPE_REF( ucb::XCommandProcessor ),
300                     CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
301                     CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
302                     CPPU_TYPE_REF( beans::XPropertyContainer ),
303                     CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
304                     CPPU_TYPE_REF( container::XChild ) );
305                 pCollection = &aCollection;
306                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
307                 pDocumentTypes = pCollection;
308             }
309         }
310         else {
311             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
312         }
313     }
314 
315     return (*pCollection).getTypes();
316 }
317 
318 //=========================================================================
319 //
320 // XServiceInfo methods.
321 //
322 //=========================================================================
323 
324 // virtual
325 rtl::OUString SAL_CALL Content::getImplementationName()
326     throw( uno::RuntimeException )
327 {
328     return rtl::OUString::createFromAscii(
329                 "com.sun.star.comp.ucb.TransientDocumentsContent" );
330 }
331 
332 //=========================================================================
333 // virtual
334 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames()
335     throw( uno::RuntimeException )
336 {
337     osl::Guard< osl::Mutex > aGuard( m_aMutex );
338 
339     uno::Sequence< rtl::OUString > aSNS( 1 );
340 
341     if ( m_aProps.getType() == STREAM )
342         aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii(
343                                 TDOC_STREAM_CONTENT_SERVICE_NAME );
344     else if ( m_aProps.getType() == FOLDER )
345         aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii(
346                                 TDOC_FOLDER_CONTENT_SERVICE_NAME );
347     else if ( m_aProps.getType() == DOCUMENT )
348         aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii(
349                                 TDOC_DOCUMENT_CONTENT_SERVICE_NAME );
350     else
351         aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii(
352                                 TDOC_ROOT_CONTENT_SERVICE_NAME );
353 
354     return aSNS;
355 }
356 
357 //=========================================================================
358 //
359 // XContent methods.
360 //
361 //=========================================================================
362 
363 // virtual
364 rtl::OUString SAL_CALL Content::getContentType()
365     throw( uno::RuntimeException )
366 {
367     osl::Guard< osl::Mutex > aGuard( m_aMutex );
368     return m_aProps.getContentType();
369 }
370 
371 //=========================================================================
372 // virtual
373 uno::Reference< ucb::XContentIdentifier > SAL_CALL
374 Content::getIdentifier()
375     throw( uno::RuntimeException )
376 {
377     {
378         osl::Guard< osl::Mutex > aGuard( m_aMutex );
379 
380         // Transient?
381         if ( m_eState == TRANSIENT )
382         {
383             // Transient contents have no identifier.
384             return uno::Reference< ucb::XContentIdentifier >();
385         }
386     }
387     return ContentImplHelper::getIdentifier();
388 }
389 
390 //=========================================================================
391 //
392 // XCommandProcessor methods.
393 //
394 //=========================================================================
395 
396 // virtual
397 uno::Any SAL_CALL Content::execute(
398         const ucb::Command& aCommand,
399         sal_Int32 /*CommandId*/,
400         const uno::Reference< ucb::XCommandEnvironment >& Environment )
401     throw( uno::Exception,
402            ucb::CommandAbortedException,
403            uno::RuntimeException )
404 {
405     uno::Any aRet;
406 
407     if ( aCommand.Name.equalsAsciiL(
408             RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) )
409     {
410         //////////////////////////////////////////////////////////////////
411         // getPropertyValues
412         //////////////////////////////////////////////////////////////////
413 
414         uno::Sequence< beans::Property > Properties;
415         if ( !( aCommand.Argument >>= Properties ) )
416         {
417             ucbhelper::cancelCommandExecution(
418                 uno::makeAny( lang::IllegalArgumentException(
419                                     rtl::OUString::createFromAscii(
420                                         "Wrong argument type!" ),
421                                     static_cast< cppu::OWeakObject * >( this ),
422                                     -1 ) ),
423                 Environment );
424             // Unreachable
425         }
426 
427         aRet <<= getPropertyValues( Properties );
428     }
429     else if ( aCommand.Name.equalsAsciiL(
430                 RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) )
431     {
432         //////////////////////////////////////////////////////////////////
433         // setPropertyValues
434         //////////////////////////////////////////////////////////////////
435 
436         uno::Sequence< beans::PropertyValue > aProperties;
437         if ( !( aCommand.Argument >>= aProperties ) )
438         {
439             ucbhelper::cancelCommandExecution(
440                 uno::makeAny( lang::IllegalArgumentException(
441                                     rtl::OUString::createFromAscii(
442                                         "Wrong argument type!" ),
443                                     static_cast< cppu::OWeakObject * >( this ),
444                                     -1 ) ),
445                 Environment );
446             // Unreachable
447         }
448 
449         if ( !aProperties.getLength() )
450         {
451             ucbhelper::cancelCommandExecution(
452                 uno::makeAny( lang::IllegalArgumentException(
453                                     rtl::OUString::createFromAscii(
454                                         "No properties!" ),
455                                     static_cast< cppu::OWeakObject * >( this ),
456                                     -1 ) ),
457                 Environment );
458             // Unreachable
459         }
460 
461         aRet <<= setPropertyValues( aProperties, Environment );
462     }
463     else if ( aCommand.Name.equalsAsciiL(
464                 RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) )
465     {
466         //////////////////////////////////////////////////////////////////
467         // getPropertySetInfo
468         //////////////////////////////////////////////////////////////////
469 
470         aRet <<= getPropertySetInfo( Environment );
471     }
472     else if ( aCommand.Name.equalsAsciiL(
473                 RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) )
474     {
475         //////////////////////////////////////////////////////////////////
476         // getCommandInfo
477         //////////////////////////////////////////////////////////////////
478 
479         aRet <<= getCommandInfo( Environment );
480     }
481     else if ( aCommand.Name.equalsAsciiL(
482                 RTL_CONSTASCII_STRINGPARAM( "open" ) ) )
483     {
484         //////////////////////////////////////////////////////////////////
485         // open
486         //////////////////////////////////////////////////////////////////
487 
488         ucb::OpenCommandArgument2 aOpenCommand;
489         if ( !( aCommand.Argument >>= aOpenCommand ) )
490         {
491             ucbhelper::cancelCommandExecution(
492                 uno::makeAny( lang::IllegalArgumentException(
493                                     rtl::OUString::createFromAscii(
494                                         "Wrong argument type!" ),
495                                     static_cast< cppu::OWeakObject * >( this ),
496                                     -1 ) ),
497                 Environment );
498             // Unreachable
499         }
500 
501         aRet = open( aOpenCommand, Environment );
502     }
503     else if ( aCommand.Name.equalsAsciiL(
504                 RTL_CONSTASCII_STRINGPARAM( "insert" ) ) )
505     {
506         //////////////////////////////////////////////////////////////////
507         // insert ( Supported by folders and streams only )
508         //////////////////////////////////////////////////////////////////
509 
510         ContentType eType = m_aProps.getType();
511         if ( ( eType != FOLDER ) && ( eType != STREAM ) )
512         {
513             ucbhelper::cancelCommandExecution(
514                 uno::makeAny( ucb::UnsupportedCommandException(
515                                 rtl::OUString(
516                                     RTL_CONSTASCII_USTRINGPARAM(
517                                         "insert command only supported by "
518                                         "folders and streams!" ) ),
519                                 static_cast< cppu::OWeakObject * >( this ) ) ),
520                 Environment );
521             // Unreachable
522         }
523 
524 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
525         if ( eType == STREAM )
526         {
527             Uri aUri( m_xIdentifier->getContentIdentifier() );
528             Uri aParentUri( aUri.getParentUri() );
529             if ( aParentUri.isDocument() )
530             {
531                 ucbhelper::cancelCommandExecution(
532                     uno::makeAny( ucb::UnsupportedCommandException(
533                                     rtl::OUString(
534                                         RTL_CONSTASCII_USTRINGPARAM(
535                                             "insert command not supported by "
536                                             "streams that are direct children "
537                                             "of document root!" ) ),
538                                     static_cast< cppu::OWeakObject * >(
539                                         this ) ) ),
540                     Environment );
541                 // Unreachable
542             }
543         }
544 #endif
545         ucb::InsertCommandArgument aArg;
546         if ( !( aCommand.Argument >>= aArg ) )
547         {
548             ucbhelper::cancelCommandExecution(
549                 uno::makeAny( lang::IllegalArgumentException(
550                                     rtl::OUString::createFromAscii(
551                                         "Wrong argument type!" ),
552                                     static_cast< cppu::OWeakObject * >( this ),
553                                     -1 ) ),
554                 Environment );
555             // Unreachable
556         }
557 
558         sal_Int32 nNameClash = aArg.ReplaceExisting
559                              ? ucb::NameClash::OVERWRITE
560                              : ucb::NameClash::ERROR;
561         insert( aArg.Data, nNameClash, Environment );
562     }
563     else if ( aCommand.Name.equalsAsciiL(
564                 RTL_CONSTASCII_STRINGPARAM( "delete" ) ) )
565     {
566         //////////////////////////////////////////////////////////////////
567         // delete ( Supported by folders and streams only )
568         //////////////////////////////////////////////////////////////////
569 
570         {
571             osl::MutexGuard aGuard( m_aMutex );
572 
573             ContentType eType = m_aProps.getType();
574             if ( ( eType != FOLDER ) && ( eType != STREAM ) )
575             {
576                 ucbhelper::cancelCommandExecution(
577                     uno::makeAny( ucb::UnsupportedCommandException(
578                                     rtl::OUString(
579                                         RTL_CONSTASCII_USTRINGPARAM(
580                                             "delete command only supported by "
581                                             "folders and streams!" ) ),
582                                     static_cast< cppu::OWeakObject * >(
583                                         this ) ) ),
584                     Environment );
585                 // Unreachable
586             }
587         }
588 
589         sal_Bool bDeletePhysical = sal_False;
590         aCommand.Argument >>= bDeletePhysical;
591         destroy( bDeletePhysical, Environment );
592 
593         // Remove own and all children's persistent data.
594         if ( !removeData() )
595         {
596             uno::Any aProps
597                 = uno::makeAny(
598                          beans::PropertyValue(
599                              rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
600                                                "Uri")),
601                              -1,
602                              uno::makeAny(m_xIdentifier->
603                                               getContentIdentifier()),
604                              beans::PropertyState_DIRECT_VALUE));
605             ucbhelper::cancelCommandExecution(
606                 ucb::IOErrorCode_CANT_WRITE,
607                 uno::Sequence< uno::Any >(&aProps, 1),
608                 Environment,
609                 rtl::OUString::createFromAscii(
610                     "Cannot remove persistent data!" ),
611                 this );
612             // Unreachable
613         }
614 
615         // Remove own and all children's Additional Core Properties.
616         removeAdditionalPropertySet( sal_True );
617     }
618     else if ( aCommand.Name.equalsAsciiL(
619                 RTL_CONSTASCII_STRINGPARAM( "transfer" ) ) )
620     {
621         //////////////////////////////////////////////////////////////////
622         // transfer ( Supported by document and folders only )
623         //////////////////////////////////////////////////////////////////
624 
625         {
626             osl::MutexGuard aGuard( m_aMutex );
627 
628             ContentType eType = m_aProps.getType();
629             if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
630             {
631                 ucbhelper::cancelCommandExecution(
632                     uno::makeAny( ucb::UnsupportedCommandException(
633                                     rtl::OUString(
634                                         RTL_CONSTASCII_USTRINGPARAM(
635                                             "transfer command only supported "
636                                             "by folders and documents!" ) ),
637                                     static_cast< cppu::OWeakObject * >(
638                                         this ) ) ),
639                     Environment );
640                 // Unreachable
641             }
642         }
643 
644         ucb::TransferInfo aInfo;
645         if ( !( aCommand.Argument >>= aInfo ) )
646         {
647             OSL_ENSURE( sal_False, "Wrong argument type!" );
648             ucbhelper::cancelCommandExecution(
649                 uno::makeAny( lang::IllegalArgumentException(
650                                     rtl::OUString::createFromAscii(
651                                         "Wrong argument type!" ),
652                                     static_cast< cppu::OWeakObject * >( this ),
653                                     -1 ) ),
654                 Environment );
655             // Unreachable
656         }
657 
658         transfer( aInfo, Environment );
659     }
660     else if ( aCommand.Name.equalsAsciiL(
661                   RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) ) )
662     {
663         //////////////////////////////////////////////////////////////////
664         // createNewContent ( Supported by document and folders only )
665         //////////////////////////////////////////////////////////////////
666 
667         {
668             osl::MutexGuard aGuard( m_aMutex );
669 
670             ContentType eType = m_aProps.getType();
671             if ( ( eType != FOLDER ) && ( eType != DOCUMENT ) )
672             {
673                 ucbhelper::cancelCommandExecution(
674                     uno::makeAny( ucb::UnsupportedCommandException(
675                                     rtl::OUString(
676                                         RTL_CONSTASCII_USTRINGPARAM(
677                                             "createNewContent command only "
678                                             "supported by folders and "
679                                             "documents!" ) ),
680                                     static_cast< cppu::OWeakObject * >(
681                                         this ) ) ),
682                     Environment );
683                 // Unreachable
684             }
685         }
686 
687         ucb::ContentInfo aInfo;
688         if ( !( aCommand.Argument >>= aInfo ) )
689         {
690             OSL_ENSURE( sal_False, "Wrong argument type!" );
691             ucbhelper::cancelCommandExecution(
692                 uno::makeAny( lang::IllegalArgumentException(
693                                     rtl::OUString::createFromAscii(
694                                         "Wrong argument type!" ),
695                                     static_cast< cppu::OWeakObject * >( this ),
696                                     -1 ) ),
697                 Environment );
698             // Unreachable
699         }
700 
701         aRet <<= createNewContent( aInfo );
702     }
703     else
704     {
705         //////////////////////////////////////////////////////////////////
706         // Unsupported command
707         //////////////////////////////////////////////////////////////////
708 
709         ucbhelper::cancelCommandExecution(
710             uno::makeAny( ucb::UnsupportedCommandException(
711                                 rtl::OUString(),
712                                 static_cast< cppu::OWeakObject * >( this ) ) ),
713             Environment );
714         // Unreachable
715     }
716 
717     return aRet;
718 }
719 
720 //=========================================================================
721 // virtual
722 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
723     throw( uno::RuntimeException )
724 {
725 }
726 
727 //=========================================================================
728 //
729 // XContentCreator methods.
730 //
731 //=========================================================================
732 
733 // virtual
734 uno::Sequence< ucb::ContentInfo > SAL_CALL
735 Content::queryCreatableContentsInfo()
736     throw( uno::RuntimeException )
737 {
738     return m_aProps.getCreatableContentsInfo();
739 }
740 
741 //=========================================================================
742 // virtual
743 uno::Reference< ucb::XContent > SAL_CALL
744 Content::createNewContent( const ucb::ContentInfo& Info )
745     throw( uno::RuntimeException )
746 {
747     if ( m_aProps.isContentCreator() )
748     {
749         osl::Guard< osl::Mutex > aGuard( m_aMutex );
750 
751         if ( !Info.Type.getLength() )
752             return uno::Reference< ucb::XContent >();
753 
754         sal_Bool bCreateFolder =
755             Info.Type.equalsAsciiL(
756                 RTL_CONSTASCII_STRINGPARAM( TDOC_FOLDER_CONTENT_TYPE ) );
757 
758 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
759         // streams cannot be created as direct children of document root
760         if ( !bCreateFolder && ( m_aProps.getType() == DOCUMENT ) )
761         {
762             OSL_ENSURE( sal_False,
763                         "Content::createNewContent - streams cannot be "
764                         "created as direct children of document root!" );
765             return uno::Reference< ucb::XContent >();
766         }
767 #endif
768         if ( !bCreateFolder &&
769              !Info.Type.equalsAsciiL(
770                 RTL_CONSTASCII_STRINGPARAM( TDOC_STREAM_CONTENT_TYPE ) ) )
771         {
772             OSL_ENSURE( sal_False,
773                         "Content::createNewContent - unsupported type!" );
774             return uno::Reference< ucb::XContent >();
775         }
776 
777         rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
778 
779         OSL_ENSURE( aURL.getLength() > 0,
780                     "Content::createNewContent - empty identifier!" );
781 
782         if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
783             aURL += rtl::OUString::createFromAscii( "/" );
784 
785         if ( bCreateFolder )
786             aURL += rtl::OUString::createFromAscii( "New_Folder" );
787         else
788             aURL += rtl::OUString::createFromAscii( "New_Stream" );
789 
790         uno::Reference< ucb::XContentIdentifier > xId
791             = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL );
792 
793         return create( m_xSMgr, m_pProvider, xId, Info );
794     }
795     else
796     {
797         OSL_ENSURE( sal_False,
798                     "createNewContent called on non-contentcreator object!" );
799         return uno::Reference< ucb::XContent >();
800     }
801 }
802 
803 //=========================================================================
804 // virtual
805 rtl::OUString Content::getParentURL()
806 {
807     osl::Guard< osl::Mutex > aGuard( m_aMutex );
808     Uri aUri( m_xIdentifier->getContentIdentifier() );
809     return aUri.getParentUri();
810 }
811 
812 //=========================================================================
813 uno::Reference< ucb::XContentIdentifier >
814 Content::makeNewIdentifier( const rtl::OUString& rTitle )
815 {
816     osl::Guard< osl::Mutex > aGuard( m_aMutex );
817 
818     // Assemble new content identifier...
819     Uri aUri( m_xIdentifier->getContentIdentifier() );
820     rtl::OUStringBuffer aNewURL = aUri.getParentUri();
821     aNewURL.append( ::ucb_impl::urihelper::encodeSegment( rTitle ) );
822 
823     return
824         uno::Reference< ucb::XContentIdentifier >(
825             new ::ucbhelper::ContentIdentifier(
826                 m_xSMgr, aNewURL.makeStringAndClear() ) );
827 }
828 
829 //=========================================================================
830 void Content::queryChildren( ContentRefList& rChildren )
831 {
832     osl::Guard< osl::Mutex > aGuard( m_aMutex );
833 
834     // Only folders (root, documents, folders) have children.
835     if ( !m_aProps.getIsFolder() )
836         return;
837 
838     // Obtain a list with a snapshot of all currently instanciated contents
839     // from provider and extract the contents which are direct children
840     // of this content.
841 
842     ::ucbhelper::ContentRefList aAllContents;
843     m_xProvider->queryExistingContents( aAllContents );
844 
845     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
846     sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
847 
848     if ( nURLPos != ( aURL.getLength() - 1 ) )
849     {
850         // No trailing slash found. Append.
851         aURL += rtl::OUString::createFromAscii( "/" );
852     }
853 
854     sal_Int32 nLen = aURL.getLength();
855 
856     ::ucbhelper::ContentRefList::const_iterator it  = aAllContents.begin();
857     ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
858 
859     while ( it != end )
860     {
861         ::ucbhelper::ContentImplHelperRef xChild = (*it);
862         rtl::OUString aChildURL
863             = xChild->getIdentifier()->getContentIdentifier();
864 
865         // Is aURL a prefix of aChildURL?
866         if ( ( aChildURL.getLength() > nLen ) &&
867              ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
868         {
869             sal_Int32 nPos = nLen;
870             nPos = aChildURL.indexOf( '/', nPos );
871 
872             if ( ( nPos == -1 ) ||
873                  ( nPos == ( aChildURL.getLength() - 1 ) ) )
874             {
875                 // No further slashes / only a final slash. It's a child!
876                 rChildren.push_back(
877                     ContentRef(
878                         static_cast< Content * >( xChild.get() ) ) );
879             }
880         }
881         ++it;
882     }
883 }
884 
885 //=========================================================================
886 sal_Bool Content::exchangeIdentity(
887             const uno::Reference< ucb::XContentIdentifier >& xNewId )
888 {
889     if ( !xNewId.is() )
890         return sal_False;
891 
892     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
893 
894     uno::Reference< ucb::XContent > xThis = this;
895 
896     // Already persistent?
897     if ( m_eState != PERSISTENT )
898     {
899         OSL_ENSURE( sal_False,
900                     "Content::exchangeIdentity - Not persistent!" );
901         return sal_False;
902     }
903 
904     // Only folders and streams can be renamed -> exchange identity.
905     ContentType eType = m_aProps.getType();
906     if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
907     {
908         OSL_ENSURE( sal_False, "Content::exchangeIdentity - "
909                                "Not supported by root or document!" );
910         return sal_False;
911     }
912 
913     // Exchange own identitity.
914 
915     // Fail, if a content with given id already exists.
916     if ( !hasData( Uri( xNewId->getContentIdentifier() ) ) )
917     {
918         rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier();
919 
920         aGuard.clear();
921         if ( exchange( xNewId ) )
922         {
923             if ( eType == FOLDER )
924             {
925                 // Process instanciated children...
926 
927                 ContentRefList aChildren;
928                 queryChildren( aChildren );
929 
930                 ContentRefList::const_iterator it  = aChildren.begin();
931                 ContentRefList::const_iterator end = aChildren.end();
932 
933                 while ( it != end )
934                 {
935                     ContentRef xChild = (*it);
936 
937                     // Create new content identifier for the child...
938                     uno::Reference< ucb::XContentIdentifier > xOldChildId
939                                                     = xChild->getIdentifier();
940                     rtl::OUString aOldChildURL
941                         = xOldChildId->getContentIdentifier();
942                     rtl::OUString aNewChildURL
943                         = aOldChildURL.replaceAt(
944                                         0,
945                                         aOldURL.getLength(),
946                                         xNewId->getContentIdentifier() );
947                     uno::Reference< ucb::XContentIdentifier > xNewChildId
948                         = new ::ucbhelper::ContentIdentifier(
949                             m_xSMgr, aNewChildURL );
950 
951                     if ( !xChild->exchangeIdentity( xNewChildId ) )
952                         return sal_False;
953 
954                     ++it;
955                 }
956             }
957             return sal_True;
958         }
959     }
960 
961     OSL_ENSURE( sal_False,
962                 "Content::exchangeIdentity - "
963                 "Panic! Cannot exchange identity!" );
964     return sal_False;
965 }
966 
967 //=========================================================================
968 // static
969 uno::Reference< sdbc::XRow > Content::getPropertyValues(
970                 const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
971                 const uno::Sequence< beans::Property >& rProperties,
972                 ContentProvider* pProvider,
973                 const rtl::OUString& rContentId )
974 {
975     ContentProperties aData;
976     if ( loadData( pProvider, rContentId, aData ) )
977     {
978         return getPropertyValues(
979             rSMgr, rProperties, aData, pProvider, rContentId );
980     }
981     else
982     {
983         rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
984             = new ::ucbhelper::PropertyValueSet( rSMgr );
985 
986         sal_Int32 nCount = rProperties.getLength();
987         if ( nCount )
988         {
989             const beans::Property* pProps = rProperties.getConstArray();
990             for ( sal_Int32 n = 0; n < nCount; ++n )
991                 xRow->appendVoid( pProps[ n ] );
992         }
993 
994         return uno::Reference< sdbc::XRow >( xRow.get() );
995     }
996 }
997 
998 //=========================================================================
999 // static
1000 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1001                 const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
1002                 const uno::Sequence< beans::Property >& rProperties,
1003                 const ContentProperties& rData,
1004                 ContentProvider* pProvider,
1005                 const rtl::OUString& rContentId )
1006 {
1007     // Note: Empty sequence means "get values of all supported properties".
1008 
1009     rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
1010         = new ::ucbhelper::PropertyValueSet( rSMgr );
1011 
1012     sal_Int32 nCount = rProperties.getLength();
1013     if ( nCount )
1014     {
1015         uno::Reference< beans::XPropertySet > xAdditionalPropSet;
1016         sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1017 
1018         const beans::Property* pProps = rProperties.getConstArray();
1019         for ( sal_Int32 n = 0; n < nCount; ++n )
1020         {
1021             const beans::Property& rProp = pProps[ n ];
1022 
1023             // Process Core properties.
1024 
1025             if ( rProp.Name.equalsAsciiL(
1026                         RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
1027             {
1028                 xRow->appendString ( rProp, rData.getContentType() );
1029             }
1030             else if ( rProp.Name.equalsAsciiL(
1031                         RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1032             {
1033                 xRow->appendString ( rProp, rData.getTitle() );
1034             }
1035             else if ( rProp.Name.equalsAsciiL(
1036                         RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
1037             {
1038                 xRow->appendBoolean( rProp, rData.getIsDocument() );
1039             }
1040             else if ( rProp.Name.equalsAsciiL(
1041                         RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
1042             {
1043                 xRow->appendBoolean( rProp, rData.getIsFolder() );
1044             }
1045             else if ( rProp.Name.equalsAsciiL(
1046                         RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1047             {
1048                 xRow->appendObject(
1049                     rProp, uno::makeAny( rData.getCreatableContentsInfo() ) );
1050             }
1051             else if ( rProp.Name.equalsAsciiL(
1052                         RTL_CONSTASCII_STRINGPARAM( "Storage" ) ) )
1053             {
1054                 // Storage is only supported by folders.
1055                 ContentType eType = rData.getType();
1056                 if ( eType == FOLDER )
1057                     xRow->appendObject(
1058                         rProp,
1059                         uno::makeAny(
1060                             pProvider->queryStorageClone( rContentId ) ) );
1061                 else
1062                     xRow->appendVoid( rProp );
1063             }
1064             else if ( rProp.Name.equalsAsciiL(
1065                         RTL_CONSTASCII_STRINGPARAM( "DocumentModel" ) ) )
1066             {
1067                 // DocumentModel is only supported by documents.
1068                 ContentType eType = rData.getType();
1069                 if ( eType == DOCUMENT )
1070                     xRow->appendObject(
1071                         rProp,
1072                         uno::makeAny(
1073                             pProvider->queryDocumentModel( rContentId ) ) );
1074                 else
1075                     xRow->appendVoid( rProp );
1076             }
1077             else
1078             {
1079                 // Not a Core Property! Maybe it's an Additional Core Property?!
1080 
1081                 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1082                 {
1083                     xAdditionalPropSet
1084                         = uno::Reference< beans::XPropertySet >(
1085                             pProvider->getAdditionalPropertySet( rContentId,
1086                                                                  sal_False ),
1087                             uno::UNO_QUERY );
1088                     bTriedToGetAdditonalPropSet = sal_True;
1089                 }
1090 
1091                 if ( xAdditionalPropSet.is() )
1092                 {
1093                     if ( !xRow->appendPropertySetValue(
1094                                                 xAdditionalPropSet,
1095                                                 rProp ) )
1096                     {
1097                         // Append empty entry.
1098                         xRow->appendVoid( rProp );
1099                     }
1100                 }
1101                 else
1102                 {
1103                     // Append empty entry.
1104                     xRow->appendVoid( rProp );
1105                 }
1106             }
1107         }
1108     }
1109     else
1110     {
1111         // Append all Core Properties.
1112         xRow->appendString (
1113             beans::Property( rtl::OUString::createFromAscii( "ContentType" ),
1114                       -1,
1115                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1116                       beans::PropertyAttribute::BOUND
1117                         | beans::PropertyAttribute::READONLY ),
1118             rData.getContentType() );
1119 
1120         ContentType eType = rData.getType();
1121 
1122         xRow->appendString (
1123             beans::Property( rtl::OUString::createFromAscii( "Title" ),
1124                       -1,
1125                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
1126                       // Title is read-only for root and documents.
1127                       beans::PropertyAttribute::BOUND ||
1128                       ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1129                         ? beans::PropertyAttribute::READONLY
1130                         : 0 ),
1131             rData.getTitle() );
1132         xRow->appendBoolean(
1133             beans::Property( rtl::OUString::createFromAscii( "IsDocument" ),
1134                       -1,
1135                       getCppuBooleanType(),
1136                       beans::PropertyAttribute::BOUND
1137                         | beans::PropertyAttribute::READONLY ),
1138             rData.getIsDocument() );
1139         xRow->appendBoolean(
1140             beans::Property( rtl::OUString::createFromAscii( "IsFolder" ),
1141                       -1,
1142                       getCppuBooleanType(),
1143                       beans::PropertyAttribute::BOUND
1144                         | beans::PropertyAttribute::READONLY ),
1145             rData.getIsFolder() );
1146         xRow->appendObject(
1147             beans::Property(
1148                 rtl::OUString::createFromAscii( "CreatableContentsInfo" ),
1149                 -1,
1150                 getCppuType( static_cast<
1151                         const uno::Sequence< ucb::ContentInfo > * >( 0 ) ),
1152                 beans::PropertyAttribute::BOUND
1153                 | beans::PropertyAttribute::READONLY ),
1154             uno::makeAny( rData.getCreatableContentsInfo() ) );
1155 
1156         // Storage is only supported by folders.
1157         if ( eType == FOLDER )
1158             xRow->appendObject(
1159                 beans::Property( rtl::OUString::createFromAscii( "Storage" ),
1160                           -1,
1161                           getCppuType(
1162                             static_cast<
1163                                 const uno::Reference< embed::XStorage > * >( 0 ) ),
1164                           beans::PropertyAttribute::BOUND
1165                             | beans::PropertyAttribute::READONLY ),
1166                 uno::makeAny( pProvider->queryStorageClone( rContentId ) ) );
1167 
1168         // DocumentModel is only supported by documents.
1169         if ( eType == DOCUMENT )
1170             xRow->appendObject(
1171                 beans::Property( rtl::OUString::createFromAscii( "DocumentModel" ),
1172                           -1,
1173                           getCppuType(
1174                             static_cast<
1175                                 const uno::Reference< frame::XModel > * >( 0 ) ),
1176                           beans::PropertyAttribute::BOUND
1177                             | beans::PropertyAttribute::READONLY ),
1178                 uno::makeAny(
1179                     pProvider->queryDocumentModel( rContentId ) ) );
1180 
1181         // Append all Additional Core Properties.
1182 
1183         uno::Reference< beans::XPropertySet > xSet(
1184             pProvider->getAdditionalPropertySet( rContentId, sal_False ),
1185             uno::UNO_QUERY );
1186         xRow->appendPropertySet( xSet );
1187     }
1188 
1189     return uno::Reference< sdbc::XRow >( xRow.get() );
1190 }
1191 
1192 //=========================================================================
1193 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1194                         const uno::Sequence< beans::Property >& rProperties )
1195 {
1196     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1197     return getPropertyValues( m_xSMgr,
1198                               rProperties,
1199                               m_aProps,
1200                               m_pProvider,
1201                               m_xIdentifier->getContentIdentifier() );
1202 }
1203 
1204 //=========================================================================
1205 uno::Sequence< uno::Any > Content::setPropertyValues(
1206         const uno::Sequence< beans::PropertyValue >& rValues,
1207         const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1208     throw( uno::Exception )
1209 {
1210     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1211 
1212     uno::Sequence< uno::Any > aRet( rValues.getLength() );
1213     uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1214     sal_Int32 nChanged = 0;
1215 
1216     beans::PropertyChangeEvent aEvent;
1217     aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
1218     aEvent.Further        = sal_False;
1219     //    aEvent.PropertyName   =
1220     aEvent.PropertyHandle = -1;
1221     //    aEvent.OldValue       =
1222     //    aEvent.NewValue       =
1223 
1224     const beans::PropertyValue* pValues = rValues.getConstArray();
1225     sal_Int32 nCount = rValues.getLength();
1226 
1227     uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1228     sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1229 
1230     sal_Bool bExchange = sal_False;
1231     rtl::OUString aOldTitle;
1232     sal_Int32 nTitlePos = -1;
1233 
1234     for ( sal_Int32 n = 0; n < nCount; ++n )
1235     {
1236         const beans::PropertyValue& rValue = pValues[ n ];
1237 
1238         if ( rValue.Name.equalsAsciiL(
1239                     RTL_CONSTASCII_STRINGPARAM(  "ContentType" ) ) )
1240         {
1241             // Read-only property!
1242             aRet[ n ] <<= lang::IllegalAccessException(
1243                             rtl::OUString::createFromAscii(
1244                                 "Property is read-only!" ),
1245                             static_cast< cppu::OWeakObject * >( this ) );
1246         }
1247         else if ( rValue.Name.equalsAsciiL(
1248                     RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
1249         {
1250             // Read-only property!
1251             aRet[ n ] <<= lang::IllegalAccessException(
1252                             rtl::OUString::createFromAscii(
1253                                 "Property is read-only!" ),
1254                             static_cast< cppu::OWeakObject * >( this ) );
1255         }
1256         else if ( rValue.Name.equalsAsciiL(
1257                     RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
1258         {
1259             // Read-only property!
1260             aRet[ n ] <<= lang::IllegalAccessException(
1261                             rtl::OUString::createFromAscii(
1262                                 "Property is read-only!" ),
1263                             static_cast< cppu::OWeakObject * >( this ) );
1264         }
1265         else if ( rValue.Name.equalsAsciiL(
1266                     RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1267         {
1268             // Read-only property!
1269             aRet[ n ] <<= lang::IllegalAccessException(
1270                             rtl::OUString::createFromAscii(
1271                                 "Property is read-only!" ),
1272                             static_cast< cppu::OWeakObject * >( this ) );
1273         }
1274         else if ( rValue.Name.equalsAsciiL(
1275                     RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1276         {
1277             // Title is read-only for root and documents.
1278             ContentType eType = m_aProps.getType();
1279             if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
1280             {
1281                 aRet[ n ] <<= lang::IllegalAccessException(
1282                                 rtl::OUString::createFromAscii(
1283                                     "Property is read-only!" ),
1284                                 static_cast< cppu::OWeakObject * >( this ) );
1285             }
1286             else
1287             {
1288                 rtl::OUString aNewValue;
1289                 if ( rValue.Value >>= aNewValue )
1290                 {
1291                     // No empty titles!
1292                     if ( aNewValue.getLength() > 0 )
1293                     {
1294                         if ( aNewValue != m_aProps.getTitle() )
1295                         {
1296                             // modified title -> modified URL -> exchange !
1297                             if ( m_eState == PERSISTENT )
1298                                 bExchange = sal_True;
1299 
1300                             aOldTitle = m_aProps.getTitle();
1301                             m_aProps.setTitle( aNewValue );
1302 
1303                             // property change event will be sent later...
1304 
1305                             // remember position within sequence of values
1306                             // (for error handling).
1307                             nTitlePos = n;
1308                         }
1309                     }
1310                     else
1311                     {
1312                         aRet[ n ] <<= lang::IllegalArgumentException(
1313                                     rtl::OUString::createFromAscii(
1314                                         "Empty Title not allowed!" ),
1315                                     static_cast< cppu::OWeakObject * >( this ),
1316                                     -1 );
1317                     }
1318                 }
1319                 else
1320                 {
1321                     aRet[ n ] <<= beans::IllegalTypeException(
1322                                 rtl::OUString::createFromAscii(
1323                                     "Title Property value has wrong type!" ),
1324                                 static_cast< cppu::OWeakObject * >( this ) );
1325                 }
1326             }
1327         }
1328         else if ( rValue.Name.equalsAsciiL(
1329                     RTL_CONSTASCII_STRINGPARAM( "Storage" ) ) )
1330         {
1331             ContentType eType = m_aProps.getType();
1332             if ( eType == FOLDER )
1333             {
1334                 aRet[ n ] <<= lang::IllegalAccessException(
1335                                 rtl::OUString::createFromAscii(
1336                                     "Property is read-only!" ),
1337                                 static_cast< cppu::OWeakObject * >( this ) );
1338             }
1339             else
1340             {
1341                 // Storage is only supported by folders.
1342                 aRet[ n ] <<= beans::UnknownPropertyException(
1343                             rtl::OUString::createFromAscii(
1344                                 "Storage property only supported by folders" ),
1345                             static_cast< cppu::OWeakObject * >( this ) );
1346             }
1347         }
1348         else if ( rValue.Name.equalsAsciiL(
1349                     RTL_CONSTASCII_STRINGPARAM( "DocumentModel" ) ) )
1350         {
1351             ContentType eType = m_aProps.getType();
1352             if ( eType == DOCUMENT )
1353             {
1354                 aRet[ n ] <<= lang::IllegalAccessException(
1355                                 rtl::OUString::createFromAscii(
1356                                     "Property is read-only!" ),
1357                                 static_cast< cppu::OWeakObject * >( this ) );
1358             }
1359             else
1360             {
1361                 // Storage is only supported by folders.
1362                 aRet[ n ] <<= beans::UnknownPropertyException(
1363                             rtl::OUString::createFromAscii(
1364                                 "DocumentModel property only supported by "
1365                                 "documents" ),
1366                             static_cast< cppu::OWeakObject * >( this ) );
1367             }
1368         }
1369         else
1370         {
1371             // Not a Core Property! Maybe it's an Additional Core Property?!
1372 
1373             if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1374             {
1375                 xAdditionalPropSet = getAdditionalPropertySet( sal_False );
1376                 bTriedToGetAdditonalPropSet = sal_True;
1377             }
1378 
1379             if ( xAdditionalPropSet.is() )
1380             {
1381                 try
1382                 {
1383                     uno::Any aOldValue = xAdditionalPropSet->getPropertyValue(
1384                                                                 rValue.Name );
1385                     if ( aOldValue != rValue.Value )
1386                     {
1387                         xAdditionalPropSet->setPropertyValue(
1388                                                 rValue.Name, rValue.Value );
1389 
1390                         aEvent.PropertyName = rValue.Name;
1391                         aEvent.OldValue     = aOldValue;
1392                         aEvent.NewValue     = rValue.Value;
1393 
1394                         aChanges.getArray()[ nChanged ] = aEvent;
1395                         nChanged++;
1396                     }
1397                 }
1398                 catch ( beans::UnknownPropertyException const & e )
1399                 {
1400                     aRet[ n ] <<= e;
1401                 }
1402                 catch ( lang::WrappedTargetException const & e )
1403                 {
1404                     aRet[ n ] <<= e;
1405                 }
1406                 catch ( beans::PropertyVetoException const & e )
1407                 {
1408                     aRet[ n ] <<= e;
1409                 }
1410                 catch ( lang::IllegalArgumentException const & e )
1411                 {
1412                     aRet[ n ] <<= e;
1413                 }
1414             }
1415             else
1416             {
1417                 aRet[ n ] <<= uno::Exception(
1418                                 rtl::OUString::createFromAscii(
1419                                     "No property set for storing the value!" ),
1420                                 static_cast< cppu::OWeakObject * >( this ) );
1421             }
1422         }
1423     }
1424 
1425     if ( bExchange )
1426     {
1427         uno::Reference< ucb::XContentIdentifier > xOldId
1428             = m_xIdentifier;
1429         uno::Reference< ucb::XContentIdentifier > xNewId
1430             = makeNewIdentifier( m_aProps.getTitle() );
1431 
1432         aGuard.clear();
1433         if ( exchangeIdentity( xNewId ) )
1434         {
1435             // Adapt persistent data.
1436             renameData( xOldId, xNewId );
1437 
1438             // Adapt Additional Core Properties.
1439             renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1440                                          xNewId->getContentIdentifier(),
1441                                          sal_True );
1442         }
1443         else
1444         {
1445             // Roll-back.
1446             m_aProps.setTitle( aOldTitle );
1447             aOldTitle = rtl::OUString();
1448 
1449             // Set error .
1450             aRet[ nTitlePos ] <<= uno::Exception(
1451                     rtl::OUString::createFromAscii( "Exchange failed!" ),
1452                     static_cast< cppu::OWeakObject * >( this ) );
1453         }
1454     }
1455 
1456     if ( aOldTitle.getLength() )
1457     {
1458         aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" );
1459         aEvent.OldValue     = uno::makeAny( aOldTitle );
1460         aEvent.NewValue     = uno::makeAny( m_aProps.getTitle() );
1461 
1462         aChanges.getArray()[ nChanged ] = aEvent;
1463         nChanged++;
1464     }
1465 
1466     if ( nChanged > 0 )
1467     {
1468         // Save changes, if content was already made persistent.
1469         if ( !bExchange && ( m_eState == PERSISTENT ) )
1470         {
1471             if ( !storeData( uno::Reference< io::XInputStream >(), xEnv ) )
1472             {
1473                 uno::Any aProps
1474                     = uno::makeAny(
1475                              beans::PropertyValue(
1476                                  rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1477                                      "Uri")),
1478                                  -1,
1479                                  uno::makeAny(m_xIdentifier->
1480                                                   getContentIdentifier()),
1481                                  beans::PropertyState_DIRECT_VALUE));
1482                 ucbhelper::cancelCommandExecution(
1483                     ucb::IOErrorCode_CANT_WRITE,
1484                     uno::Sequence< uno::Any >(&aProps, 1),
1485                     xEnv,
1486                     rtl::OUString::createFromAscii(
1487                         "Cannot store persistent data!" ),
1488                     this );
1489                 // Unreachable
1490             }
1491         }
1492 
1493         aChanges.realloc( nChanged );
1494 
1495         aGuard.clear();
1496         notifyPropertiesChange( aChanges );
1497     }
1498 
1499     return aRet;
1500 }
1501 
1502 //=========================================================================
1503 uno::Any Content::open(
1504                 const ucb::OpenCommandArgument2& rArg,
1505                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1506     throw( uno::Exception )
1507 {
1508     if ( rArg.Mode == ucb::OpenMode::ALL ||
1509          rArg.Mode == ucb::OpenMode::FOLDERS ||
1510          rArg.Mode == ucb::OpenMode::DOCUMENTS )
1511     {
1512         //////////////////////////////////////////////////////////////////
1513         // open command for a folder content
1514         //////////////////////////////////////////////////////////////////
1515 
1516         uno::Reference< ucb::XDynamicResultSet > xSet
1517             = new DynamicResultSet( m_xSMgr, this, rArg );
1518         return uno::makeAny( xSet );
1519     }
1520     else
1521     {
1522         //////////////////////////////////////////////////////////////////
1523         // open command for a document content
1524         //////////////////////////////////////////////////////////////////
1525 
1526         if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1527              ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1528         {
1529             // Currently(?) unsupported.
1530             ucbhelper::cancelCommandExecution(
1531                 uno::makeAny( ucb::UnsupportedOpenModeException(
1532                                     rtl::OUString(),
1533                                     static_cast< cppu::OWeakObject * >( this ),
1534                                     sal_Int16( rArg.Mode ) ) ),
1535                 xEnv );
1536             // Unreachable
1537         }
1538 
1539         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1540 
1541         rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1542 
1543         uno::Reference< io::XActiveDataStreamer > xDataStreamer(
1544                                         rArg.Sink, uno::UNO_QUERY );
1545         if ( xDataStreamer.is() )
1546         {
1547             // May throw CommandFailedException, DocumentPasswordRequest!
1548             uno::Reference< io::XStream > xStream = getStream( xEnv );
1549             if ( !xStream.is() )
1550             {
1551                 // No interaction if we are not persistent!
1552                 uno::Any aProps
1553                     = uno::makeAny(
1554                              beans::PropertyValue(
1555                                  rtl::OUString(
1556                                      RTL_CONSTASCII_USTRINGPARAM("Uri")),
1557                                  -1,
1558                                  uno::makeAny(m_xIdentifier->
1559                                                   getContentIdentifier()),
1560                                  beans::PropertyState_DIRECT_VALUE));
1561                 ucbhelper::cancelCommandExecution(
1562                     ucb::IOErrorCode_CANT_READ,
1563                     uno::Sequence< uno::Any >(&aProps, 1),
1564                     m_eState == PERSISTENT
1565                         ? xEnv
1566                         : uno::Reference< ucb::XCommandEnvironment >(),
1567                     rtl::OUString::createFromAscii(
1568                         "Got no data stream!" ),
1569                     this );
1570                 // Unreachable
1571             }
1572 
1573             // Done.
1574             xDataStreamer->setStream( xStream );
1575         }
1576         else
1577         {
1578             uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1579             if ( xOut.is() )
1580             {
1581                 // PUSH: write data into xOut
1582 
1583                 // May throw CommandFailedException, DocumentPasswordRequest!
1584                 uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1585                 if ( !xIn.is() )
1586                 {
1587                     // No interaction if we are not persistent!
1588                     uno::Any aProps
1589                         = uno::makeAny(
1590                                  beans::PropertyValue(
1591                                      rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1592                                                        "Uri")),
1593                                      -1,
1594                                      uno::makeAny(m_xIdentifier->
1595                                                       getContentIdentifier()),
1596                                      beans::PropertyState_DIRECT_VALUE));
1597                     ucbhelper::cancelCommandExecution(
1598                         ucb::IOErrorCode_CANT_READ,
1599                         uno::Sequence< uno::Any >(&aProps, 1),
1600                         m_eState == PERSISTENT
1601                             ? xEnv
1602                             : uno::Reference< ucb::XCommandEnvironment >(),
1603                         rtl::OUString::createFromAscii( "Got no data stream!" ),
1604                         this );
1605                     // Unreachable
1606                 }
1607 
1608                 try
1609                 {
1610                     uno::Sequence< sal_Int8 > aBuffer;
1611                     sal_Int32  nRead = xIn->readSomeBytes( aBuffer, 65536 );
1612 
1613                     while ( nRead > 0 )
1614                     {
1615                         aBuffer.realloc( nRead );
1616                         xOut->writeBytes( aBuffer );
1617                         aBuffer.realloc( 0 );
1618                         nRead = xIn->readSomeBytes( aBuffer, 65536 );
1619                     }
1620 
1621                     xOut->closeOutput();
1622                 }
1623                 catch ( io::NotConnectedException const & )
1624                 {
1625                     // closeOutput, readSomeBytes, writeBytes
1626                 }
1627                 catch ( io::BufferSizeExceededException const & )
1628                 {
1629                     // closeOutput, readSomeBytes, writeBytes
1630                 }
1631                 catch ( io::IOException const & )
1632                 {
1633                     // closeOutput, readSomeBytes, writeBytes
1634                 }
1635             }
1636             else
1637             {
1638                 uno::Reference< io::XActiveDataSink > xDataSink(
1639                                                 rArg.Sink, uno::UNO_QUERY );
1640                 if ( xDataSink.is() )
1641                 {
1642                     // PULL: wait for client read
1643 
1644                     // May throw CommandFailedException, DocumentPasswordRequest!
1645                     uno::Reference< io::XInputStream > xIn = getInputStream( xEnv );
1646                     if ( !xIn.is() )
1647                     {
1648                         // No interaction if we are not persistent!
1649                         uno::Any aProps
1650                             = uno::makeAny(
1651                                      beans::PropertyValue(
1652                                          rtl::OUString(
1653                                              RTL_CONSTASCII_USTRINGPARAM("Uri")),
1654                                          -1,
1655                                          uno::makeAny(m_xIdentifier->
1656                                                           getContentIdentifier()),
1657                                          beans::PropertyState_DIRECT_VALUE));
1658                         ucbhelper::cancelCommandExecution(
1659                             ucb::IOErrorCode_CANT_READ,
1660                             uno::Sequence< uno::Any >(&aProps, 1),
1661                             m_eState == PERSISTENT
1662                                 ? xEnv
1663                                 : uno::Reference<
1664                                       ucb::XCommandEnvironment >(),
1665                             rtl::OUString::createFromAscii(
1666                                 "Got no data stream!" ),
1667                             this );
1668                         // Unreachable
1669                     }
1670 
1671                     // Done.
1672                     xDataSink->setInputStream( xIn );
1673                 }
1674                 else
1675                 {
1676                     ucbhelper::cancelCommandExecution(
1677                         uno::makeAny(
1678                             ucb::UnsupportedDataSinkException(
1679                                     rtl::OUString(),
1680                                     static_cast< cppu::OWeakObject * >( this ),
1681                                     rArg.Sink ) ),
1682                         xEnv );
1683                     // Unreachable
1684                 }
1685             }
1686         }
1687     }
1688 
1689     return uno::Any();
1690 }
1691 
1692 //=========================================================================
1693 void Content::insert( const uno::Reference< io::XInputStream >& xData,
1694                       sal_Int32 nNameClashResolve,
1695                       const uno::Reference<
1696                           ucb::XCommandEnvironment > & xEnv )
1697     throw( uno::Exception )
1698 {
1699     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1700 
1701     ContentType eType = m_aProps.getType();
1702 
1703     OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1704                 "insert command only supported by streams and folders!" );
1705 
1706     Uri aUri( m_xIdentifier->getContentIdentifier() );
1707 
1708 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
1709 #if OSL_DEBUG_LEVEL > 0
1710     if ( eType == STREAM )
1711     {
1712         Uri aParentUri( aUri.getParentUri() );
1713         OSL_ENSURE( !aParentUri.isDocument(),
1714                     "insert command not supported by streams that are direct "
1715                     "children of document root!" );
1716     }
1717 #endif
1718 #endif
1719 
1720     // Check, if all required properties were set.
1721     if ( eType == FOLDER )
1722     {
1723         // Required: Title
1724 
1725         if ( m_aProps.getTitle().getLength() == 0 )
1726             m_aProps.setTitle( aUri.getDecodedName() );
1727     }
1728     else // stream
1729     {
1730         // Required: data
1731 
1732         if ( !xData.is() )
1733         {
1734             ucbhelper::cancelCommandExecution(
1735                 uno::makeAny( ucb::MissingInputStreamException(
1736                                 rtl::OUString(),
1737                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1738                 xEnv );
1739             // Unreachable
1740         }
1741 
1742         // Required: Title
1743 
1744         if ( m_aProps.getTitle().getLength() == 0 )
1745             m_aProps.setTitle( aUri.getDecodedName() );
1746     }
1747 
1748     rtl::OUStringBuffer aNewURL = aUri.getParentUri();
1749     aNewURL.append( m_aProps.getTitle() );
1750     Uri aNewUri( aNewURL.makeStringAndClear() );
1751 
1752     // Handle possible name clash...
1753     switch ( nNameClashResolve )
1754     {
1755         // fail.
1756         case ucb::NameClash::ERROR:
1757             if ( hasData( aNewUri ) )
1758             {
1759                 ucbhelper::cancelCommandExecution(
1760                     uno::makeAny( ucb::NameClashException(
1761                                     rtl::OUString(),
1762                                     static_cast< cppu::OWeakObject * >( this ),
1763                                     task::InteractionClassification_ERROR,
1764                                     m_aProps.getTitle() ) ),
1765                     xEnv );
1766                 // Unreachable
1767             }
1768             break;
1769 
1770         // replace (possibly) existing object.
1771         case ucb::NameClash::OVERWRITE:
1772             break;
1773 
1774         // "invent" a new valid title.
1775         case ucb::NameClash::RENAME:
1776             if ( hasData( aNewUri ) )
1777             {
1778                 sal_Int32 nTry = 0;
1779 
1780                 do
1781                 {
1782                     rtl::OUStringBuffer aNew = aNewUri.getUri();
1783                     aNew.appendAscii( "_" );
1784                     aNew.append( rtl::OUString::valueOf( ++nTry ) );
1785                     aNewUri.setUri( aNew.makeStringAndClear() );
1786                 }
1787                 while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1788 
1789                 if ( nTry == 1000 )
1790                 {
1791                     ucbhelper::cancelCommandExecution(
1792                         uno::makeAny(
1793                             ucb::UnsupportedNameClashException(
1794                                 rtl::OUString::createFromAscii(
1795                                     "Unable to resolve name clash!" ),
1796                                 static_cast< cppu::OWeakObject * >( this ),
1797                                 nNameClashResolve ) ),
1798                         xEnv );
1799                     // Unreachable
1800                 }
1801                 else
1802                 {
1803                     rtl::OUStringBuffer aNewTitle = m_aProps.getTitle();
1804                     aNewTitle.appendAscii( "_" );
1805                     aNewTitle.append( rtl::OUString::valueOf( ++nTry ) );
1806                     m_aProps.setTitle( aNewTitle.makeStringAndClear() );
1807                 }
1808             }
1809             break;
1810 
1811         case ucb::NameClash::KEEP: // deprecated
1812         case ucb::NameClash::ASK:
1813         default:
1814             if ( hasData( aNewUri ) )
1815             {
1816                 ucbhelper::cancelCommandExecution(
1817                     uno::makeAny(
1818                         ucb::UnsupportedNameClashException(
1819                             rtl::OUString(),
1820                             static_cast< cppu::OWeakObject * >( this ),
1821                             nNameClashResolve ) ),
1822                     xEnv );
1823                 // Unreachable
1824             }
1825             break;
1826     }
1827 
1828     // Identifier changed?
1829     sal_Bool bNewId = ( aUri != aNewUri );
1830 
1831     if ( bNewId )
1832     {
1833         m_xIdentifier
1834             = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewUri.getUri() );
1835     }
1836 
1837     if ( !storeData( xData, xEnv ) )
1838     {
1839         uno::Any aProps
1840             = uno::makeAny(beans::PropertyValue(
1841                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1842                                                     "Uri")),
1843                                   -1,
1844                                   uno::makeAny(m_xIdentifier->
1845                                                    getContentIdentifier()),
1846                                   beans::PropertyState_DIRECT_VALUE));
1847         ucbhelper::cancelCommandExecution(
1848             ucb::IOErrorCode_CANT_WRITE,
1849             uno::Sequence< uno::Any >(&aProps, 1),
1850             xEnv,
1851             rtl::OUString::createFromAscii( "Cannot store persistent data!" ),
1852             this );
1853         // Unreachable
1854     }
1855 
1856     m_eState = PERSISTENT;
1857 
1858     if ( bNewId )
1859     {
1860         //loadData( m_pProvider, m_aUri, m_aProps );
1861 
1862         aGuard.clear();
1863         inserted();
1864     }
1865 }
1866 
1867 //=========================================================================
1868 void Content::destroy( sal_Bool bDeletePhysical,
1869                        const uno::Reference<
1870                            ucb::XCommandEnvironment > & xEnv )
1871     throw( uno::Exception )
1872 {
1873     // @@@ take care about bDeletePhysical -> trashcan support
1874 
1875     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1876 
1877     ContentType eType = m_aProps.getType();
1878 
1879     OSL_ENSURE( ( eType == FOLDER ) || ( eType == STREAM ),
1880                 "delete command only supported by streams and folders!" );
1881 
1882     uno::Reference< ucb::XContent > xThis = this;
1883 
1884     // Persistent?
1885     if ( m_eState != PERSISTENT )
1886     {
1887         ucbhelper::cancelCommandExecution(
1888             uno::makeAny( ucb::UnsupportedCommandException(
1889                                 rtl::OUString::createFromAscii(
1890                                     "Not persistent!" ),
1891                                 static_cast< cppu::OWeakObject * >( this ) ) ),
1892             xEnv );
1893         // Unreachable
1894     }
1895 
1896     m_eState = DEAD;
1897 
1898     aGuard.clear();
1899     deleted();
1900 
1901     if ( eType == FOLDER )
1902     {
1903         // Process instanciated children...
1904 
1905         ContentRefList aChildren;
1906         queryChildren( aChildren );
1907 
1908         ContentRefList::const_iterator it  = aChildren.begin();
1909         ContentRefList::const_iterator end = aChildren.end();
1910 
1911         while ( it != end )
1912         {
1913             (*it)->destroy( bDeletePhysical, xEnv );
1914             ++it;
1915         }
1916     }
1917 }
1918 
1919 //=========================================================================
1920 void Content::notifyDocumentClosed()
1921 {
1922     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1923 
1924     m_eState = DEAD;
1925 
1926     // @@@ anything else to reset or such?
1927 
1928     // callback follows!
1929     aGuard.clear();
1930 
1931     // Propagate destruction to content event listeners
1932     // Remove this from provider's content list.
1933     deleted();
1934 }
1935 
1936 //=========================================================================
1937 uno::Reference< ucb::XContent >
1938 Content::queryChildContent( const rtl::OUString & rRelativeChildUri )
1939 {
1940     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1941 
1942     const rtl::OUString aMyId = getIdentifier()->getContentIdentifier();
1943     rtl::OUStringBuffer aBuf( aMyId );
1944     if ( aMyId.getStr()[ aMyId.getLength() - 1 ] != sal_Unicode( '/' ) )
1945         aBuf.appendAscii( "/" );
1946     if ( rRelativeChildUri.getStr()[ 0 ] != sal_Unicode( '/' ) )
1947         aBuf.append( rRelativeChildUri );
1948     else
1949         aBuf.append( rRelativeChildUri.copy( 1 ) );
1950 
1951     uno::Reference< ucb::XContentIdentifier > xChildId
1952         = new ::ucbhelper::ContentIdentifier(
1953             m_xSMgr, aBuf.makeStringAndClear() );
1954 
1955     uno::Reference< ucb::XContent > xChild;
1956     try
1957     {
1958         xChild = m_pProvider->queryContent( xChildId );
1959     }
1960     catch ( ucb::IllegalIdentifierException const & )
1961     {
1962         // handled below.
1963     }
1964 
1965     OSL_ENSURE( xChild.is(),
1966                 "Content::queryChildContent - unable to create child content!" );
1967     return xChild;
1968 }
1969 
1970 //=========================================================================
1971 void Content::notifyChildRemoved( const rtl::OUString & rRelativeChildUri )
1972 {
1973     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1974 
1975     // Ugly! Need to create child content object, just to fill event properly.
1976     uno::Reference< ucb::XContent > xChild
1977         = queryChildContent( rRelativeChildUri );
1978 
1979     if ( xChild.is() )
1980     {
1981         // callback follows!
1982         aGuard.clear();
1983 
1984         // Notify "REMOVED" event.
1985         ucb::ContentEvent aEvt(
1986             static_cast< cppu::OWeakObject * >( this ),
1987             ucb::ContentAction::REMOVED,
1988             xChild,
1989             getIdentifier() );
1990         notifyContentEvent( aEvt );
1991     }
1992 }
1993 
1994 //=========================================================================
1995 void Content::notifyChildInserted( const rtl::OUString & rRelativeChildUri )
1996 {
1997     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1998 
1999     // Ugly! Need to create child content object, just to fill event properly.
2000     uno::Reference< ucb::XContent > xChild
2001         = queryChildContent( rRelativeChildUri );
2002 
2003     if ( xChild.is() )
2004     {
2005         // callback follows!
2006         aGuard.clear();
2007 
2008         // Notify "INSERTED" event.
2009         ucb::ContentEvent aEvt(
2010             static_cast< cppu::OWeakObject * >( this ),
2011             ucb::ContentAction::INSERTED,
2012             xChild,
2013             getIdentifier() );
2014         notifyContentEvent( aEvt );
2015     }
2016 }
2017 
2018 //=========================================================================
2019 void Content::transfer(
2020             const ucb::TransferInfo& rInfo,
2021             const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2022     throw( uno::Exception )
2023 {
2024     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
2025 
2026     // Persistent?
2027     if ( m_eState != PERSISTENT )
2028     {
2029         ucbhelper::cancelCommandExecution(
2030             uno::makeAny( ucb::UnsupportedCommandException(
2031                                 rtl::OUString::createFromAscii(
2032                                     "Not persistent!" ),
2033                                 static_cast< cppu::OWeakObject * >( this ) ) ),
2034             xEnv );
2035         // Unreachable
2036     }
2037 
2038     // Does source URI scheme match? Only vnd.sun.star.tdoc is supported.
2039 
2040     if ( ( rInfo.SourceURL.getLength() < TDOC_URL_SCHEME_LENGTH + 2 ) )
2041     {
2042         // Invaild length (to short).
2043         ucbhelper::cancelCommandExecution(
2044             uno::makeAny( ucb::InteractiveBadTransferURLException(
2045                             rtl::OUString(),
2046                             static_cast< cppu::OWeakObject * >( this ) ) ),
2047             xEnv );
2048         // Unreachable
2049     }
2050 
2051     rtl::OUString aScheme
2052         = rInfo.SourceURL.copy( 0, TDOC_URL_SCHEME_LENGTH + 2 )
2053             .toAsciiLowerCase();
2054     if ( !aScheme.equalsAsciiL(
2055             RTL_CONSTASCII_STRINGPARAM( TDOC_URL_SCHEME ":/" ) ) )
2056     {
2057         // Invalid scheme.
2058         ucbhelper::cancelCommandExecution(
2059             uno::makeAny( ucb::InteractiveBadTransferURLException(
2060                             rtl::OUString(),
2061                             static_cast< cppu::OWeakObject * >( this ) ) ),
2062             xEnv );
2063         // Unreachable
2064     }
2065 
2066     // Does source URI describe a tdoc folder or stream?
2067     Uri aSourceUri( rInfo.SourceURL );
2068     if ( !aSourceUri.isValid() )
2069     {
2070         ucbhelper::cancelCommandExecution(
2071             uno::makeAny( lang::IllegalArgumentException(
2072                                 rtl::OUString::createFromAscii(
2073                                     "Invalid source URI! Syntax!" ),
2074                                 static_cast< cppu::OWeakObject * >( this ),
2075                                 -1 ) ),
2076             xEnv );
2077         // Unreachable
2078     }
2079 
2080     if ( aSourceUri.isRoot() || aSourceUri.isDocument() )
2081     {
2082         ucbhelper::cancelCommandExecution(
2083             uno::makeAny( lang::IllegalArgumentException(
2084                                 rtl::OUString::createFromAscii(
2085                                     "Invalid source URI! "
2086                                     "Must describe a folder or stream!" ),
2087                                 static_cast< cppu::OWeakObject * >( this ),
2088                                 -1 ) ),
2089             xEnv );
2090         // Unreachable
2091     }
2092 
2093     // Is source not a parent of me / not me?
2094     rtl::OUString aId = m_xIdentifier->getContentIdentifier();
2095     sal_Int32 nPos = aId.lastIndexOf( '/' );
2096     if ( nPos != ( aId.getLength() - 1 ) )
2097     {
2098         // No trailing slash found. Append.
2099         aId += rtl::OUString::createFromAscii( "/" );
2100     }
2101 
2102     if ( rInfo.SourceURL.getLength() <= aId.getLength() )
2103     {
2104         if ( aId.compareTo(
2105                 rInfo.SourceURL, rInfo.SourceURL.getLength() ) == 0 )
2106         {
2107             uno::Any aProps
2108                 = uno::makeAny(beans::PropertyValue(
2109                                       rtl::OUString(
2110                                           RTL_CONSTASCII_USTRINGPARAM("Uri")),
2111                                       -1,
2112                                       uno::makeAny( rInfo.SourceURL ),
2113                                       beans::PropertyState_DIRECT_VALUE));
2114             ucbhelper::cancelCommandExecution(
2115                 ucb::IOErrorCode_RECURSIVE,
2116                 uno::Sequence< uno::Any >(&aProps, 1),
2117                 xEnv,
2118                 rtl::OUString::createFromAscii(
2119                     "Target is equal to or is a child of source!" ),
2120                 this );
2121             // Unreachable
2122         }
2123     }
2124 
2125 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
2126     if ( m_aProps.getType() == DOCUMENT )
2127     {
2128         bool bOK = false;
2129 
2130         uno::Reference< embed::XStorage > xStorage
2131             = m_pProvider->queryStorage(
2132                 aSourceUri.getParentUri(), READ_WRITE_NOCREATE );
2133         if ( xStorage.is() )
2134         {
2135             try
2136             {
2137                 if ( xStorage->isStreamElement( aSourceUri.getDecodedName() ) )
2138                 {
2139                     ucbhelper::cancelCommandExecution(
2140                         uno::makeAny( lang::IllegalArgumentException(
2141                                         rtl::OUString::createFromAscii(
2142                                             "Invalid source URI! "
2143                                             "Streams cannot be created as "
2144                                             "children of document root!" ),
2145                                         static_cast< cppu::OWeakObject * >(
2146                                             this ),
2147                                         -1 ) ),
2148                         xEnv );
2149                     // Unreachable
2150                 }
2151                 bOK = true;
2152             }
2153             catch ( container::NoSuchElementException const & )
2154             {
2155                 // handled below.
2156             }
2157             catch ( lang::IllegalArgumentException const & )
2158             {
2159                 // handled below.
2160             }
2161             catch ( embed::InvalidStorageException const & )
2162             {
2163                 // handled below.
2164             }
2165         }
2166 
2167         if ( !bOK )
2168         {
2169             ucbhelper::cancelCommandExecution(
2170                 uno::makeAny( lang::IllegalArgumentException(
2171                                     rtl::OUString::createFromAscii(
2172                                         "Invalid source URI! "
2173                                         "Unabale to determine source type!" ),
2174                                     static_cast< cppu::OWeakObject * >( this ),
2175                                     -1 ) ),
2176                 xEnv );
2177             // Unreachable
2178         }
2179     }
2180 #endif
2181 
2182     /////////////////////////////////////////////////////////////////////////
2183     // Copy data.
2184     /////////////////////////////////////////////////////////////////////////
2185 
2186     rtl::OUString aNewName( rInfo.NewTitle.getLength() > 0
2187                                 ? rInfo.NewTitle
2188                                 : aSourceUri.getDecodedName() );
2189 
2190     if ( !copyData( aSourceUri, aNewName ) )
2191     {
2192         uno::Any aProps
2193             = uno::makeAny(
2194                      beans::PropertyValue(
2195                          rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2196                                            "Uri")),
2197                          -1,
2198                          uno::makeAny( rInfo.SourceURL ),
2199                          beans::PropertyState_DIRECT_VALUE));
2200         ucbhelper::cancelCommandExecution(
2201             ucb::IOErrorCode_CANT_WRITE,
2202             uno::Sequence< uno::Any >(&aProps, 1),
2203             xEnv,
2204             rtl::OUString(
2205                 RTL_CONSTASCII_USTRINGPARAM( "Cannot copy data!" ) ),
2206             this );
2207         // Unreachable
2208     }
2209 
2210     /////////////////////////////////////////////////////////////////////////
2211     // Copy own and all children's Additional Core Properties.
2212     /////////////////////////////////////////////////////////////////////////
2213 
2214     rtl::OUString aTargetUri = m_xIdentifier->getContentIdentifier();
2215     if ( ( aTargetUri.lastIndexOf( '/' ) + 1 ) != aTargetUri.getLength() )
2216         aTargetUri += rtl::OUString::createFromAscii( "/" );
2217 
2218     if ( rInfo.NewTitle.getLength() > 0 )
2219         aTargetUri += ::ucb_impl::urihelper::encodeSegment( rInfo.NewTitle );
2220     else
2221         aTargetUri += aSourceUri.getName();
2222 
2223     if ( !copyAdditionalPropertySet(
2224             aSourceUri.getUri(), aTargetUri, sal_True ) )
2225     {
2226         uno::Any aProps
2227             = uno::makeAny(
2228                      beans::PropertyValue(
2229                          rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2230                                            "Uri")),
2231                          -1,
2232                          uno::makeAny( rInfo.SourceURL ),
2233                          beans::PropertyState_DIRECT_VALUE));
2234         ucbhelper::cancelCommandExecution(
2235             ucb::IOErrorCode_CANT_WRITE,
2236             uno::Sequence< uno::Any >(&aProps, 1),
2237             xEnv,
2238             rtl::OUString(
2239                 RTL_CONSTASCII_USTRINGPARAM(
2240                     "Cannot copy additional properties!" ) ),
2241             this );
2242         // Unreachable
2243     }
2244 
2245     /////////////////////////////////////////////////////////////////////////
2246     // Propagate new content.
2247     /////////////////////////////////////////////////////////////////////////
2248 
2249     rtl::Reference< Content > xTarget;
2250     try
2251     {
2252         uno::Reference< ucb::XContentIdentifier > xTargetId
2253             = new ::ucbhelper::ContentIdentifier( m_xSMgr, aTargetUri );
2254 
2255         // Note: The static cast is okay here, because its sure that
2256         //       m_xProvider is always the WebDAVContentProvider.
2257         xTarget = static_cast< Content * >(
2258             m_pProvider->queryContent( xTargetId ).get() );
2259 
2260     }
2261     catch ( ucb::IllegalIdentifierException const & )
2262     {
2263         // queryContent
2264     }
2265 
2266     if ( !xTarget.is() )
2267     {
2268         uno::Any aProps
2269             = uno::makeAny(beans::PropertyValue(
2270                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2271                                       "Uri")),
2272                                   -1,
2273                                   uno::makeAny( aTargetUri ),
2274                                   beans::PropertyState_DIRECT_VALUE));
2275         ucbhelper::cancelCommandExecution(
2276             ucb::IOErrorCode_CANT_READ,
2277             uno::Sequence< uno::Any >(&aProps, 1),
2278             xEnv,
2279             rtl::OUString::createFromAscii(
2280                 "Cannot instanciate target object!" ),
2281             this );
2282         // Unreachable
2283     }
2284 
2285     // Announce transfered content in its new folder.
2286     xTarget->inserted();
2287 
2288     /////////////////////////////////////////////////////////////////////////
2289     // Remove source, if requested
2290     /////////////////////////////////////////////////////////////////////////
2291 
2292     if ( rInfo.MoveData )
2293     {
2294         rtl::Reference< Content > xSource;
2295         try
2296         {
2297             uno::Reference< ucb::XContentIdentifier >
2298                 xSourceId = new ::ucbhelper::ContentIdentifier(
2299                     m_xSMgr, rInfo.SourceURL );
2300 
2301             // Note: The static cast is okay here, because its sure
2302             //       that m_xProvider is always the ContentProvider.
2303             xSource = static_cast< Content * >(
2304                 m_xProvider->queryContent( xSourceId ).get() );
2305         }
2306         catch ( ucb::IllegalIdentifierException const & )
2307         {
2308             // queryContent
2309         }
2310 
2311         if ( !xSource.is() )
2312         {
2313             uno::Any aProps
2314                 = uno::makeAny(beans::PropertyValue(
2315                                       rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2316                                           "Uri")),
2317                                       -1,
2318                                       uno::makeAny( rInfo.SourceURL ),
2319                                       beans::PropertyState_DIRECT_VALUE));
2320             ucbhelper::cancelCommandExecution(
2321                 ucb::IOErrorCode_CANT_READ,
2322                 uno::Sequence< uno::Any >(&aProps, 1),
2323                 xEnv,
2324                 rtl::OUString::createFromAscii(
2325                     "Cannot instanciate target object!" ),
2326                 this );
2327             // Unreachable
2328         }
2329 
2330         // Propagate destruction (recursively).
2331         xSource->destroy( sal_True, xEnv );
2332 
2333         // Remove all persistent data of source and its children.
2334         if ( !xSource->removeData() )
2335         {
2336             uno::Any aProps
2337                 = uno::makeAny(
2338                          beans::PropertyValue(
2339                              rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2340                                                "Uri")),
2341                              -1,
2342                              uno::makeAny( rInfo.SourceURL ),
2343                              beans::PropertyState_DIRECT_VALUE));
2344             ucbhelper::cancelCommandExecution(
2345                 ucb::IOErrorCode_CANT_WRITE,
2346                 uno::Sequence< uno::Any >(&aProps, 1),
2347                 xEnv,
2348                 rtl::OUString::createFromAscii(
2349                     "Cannot remove persistent data of source object!" ),
2350                 this );
2351             // Unreachable
2352         }
2353 
2354         // Remove own and all children's Additional Core Properties.
2355         if ( !xSource->removeAdditionalPropertySet( sal_True ) )
2356         {
2357             uno::Any aProps
2358                 = uno::makeAny(
2359                          beans::PropertyValue(
2360                              rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2361                                                "Uri")),
2362                              -1,
2363                              uno::makeAny( rInfo.SourceURL ),
2364                              beans::PropertyState_DIRECT_VALUE));
2365             ucbhelper::cancelCommandExecution(
2366                 ucb::IOErrorCode_CANT_WRITE,
2367                 uno::Sequence< uno::Any >(&aProps, 1),
2368                 xEnv,
2369                 rtl::OUString::createFromAscii(
2370                     "Cannot remove additional properties of source object!" ),
2371                 this );
2372             // Unreachable
2373         }
2374 
2375     } // rInfo.MoveData
2376 }
2377 
2378 //=========================================================================
2379 //static
2380 bool Content::hasData( ContentProvider* pProvider, const Uri & rUri )
2381 {
2382     if ( rUri.isRoot() )
2383     {
2384         return true; // root has no storage
2385     }
2386     else if ( rUri.isDocument() )
2387     {
2388         uno::Reference< embed::XStorage > xStorage
2389             = pProvider->queryStorage( rUri.getUri(), READ );
2390         return xStorage.is();
2391     }
2392     else
2393     {
2394         // folder or stream
2395 
2396         // Ask parent storage. In case that rUri describes a stream,
2397         // ContentProvider::queryStorage( rUri ) would return null.
2398 
2399         uno::Reference< embed::XStorage > xStorage
2400             = pProvider->queryStorage( rUri.getParentUri(), READ );
2401 
2402         if ( !xStorage.is() )
2403             return false;
2404 
2405         uno::Reference< container::XNameAccess > xParentNA(
2406             xStorage, uno::UNO_QUERY );
2407 
2408         OSL_ENSURE( xParentNA.is(), "Got no css.container.XNameAccess!" );
2409 
2410         return xParentNA->hasByName( rUri.getDecodedName() );
2411     }
2412 }
2413 
2414 //=========================================================================
2415 //static
2416 bool Content::loadData( ContentProvider* pProvider,
2417                         const Uri & rUri,
2418                         ContentProperties& rProps )
2419 {
2420     if ( rUri.isRoot() ) // root has no storage, but can always be created
2421     {
2422         rProps
2423             = ContentProperties(
2424                 ROOT, pProvider->queryStorageTitle( rUri.getUri() ) );
2425     }
2426     else if ( rUri.isDocument() ) // document must have storage
2427     {
2428         uno::Reference< embed::XStorage > xStorage
2429             = pProvider->queryStorage( rUri.getUri(), READ );
2430 
2431         if ( !xStorage.is() )
2432             return false;
2433 
2434         rProps
2435             = ContentProperties(
2436                 DOCUMENT, pProvider->queryStorageTitle( rUri.getUri() ) );
2437     }
2438     else // stream or folder; stream has no storage; folder has storage
2439     {
2440         uno::Reference< embed::XStorage > xStorage
2441             = pProvider->queryStorage( rUri.getParentUri(), READ );
2442 
2443         if ( !xStorage.is() )
2444             return false;
2445 
2446         // Check whether exists at all, is stream or folder
2447         try
2448         {
2449             // return: true  -> folder
2450             // return: false -> stream
2451             // NoSuchElementException -> neither folder nor stream
2452             bool bIsFolder
2453                 = xStorage->isStorageElement( rUri.getDecodedName() );
2454 
2455             rProps
2456                 = ContentProperties(
2457                     bIsFolder ? FOLDER : STREAM,
2458                     pProvider->queryStorageTitle( rUri.getUri() ) );
2459         }
2460         catch ( container::NoSuchElementException const & )
2461         {
2462             // there is no element with such name
2463             //OSL_ENSURE( false, "Caught NoSuchElementException!" );
2464             return false;
2465         }
2466         catch ( lang::IllegalArgumentException const & )
2467         {
2468             // an illegal argument is provided
2469             OSL_ENSURE( false, "Caught IllegalArgumentException!" );
2470             return false;
2471         }
2472         catch ( embed::InvalidStorageException const & )
2473         {
2474             // this storage is in invalid state for any reason
2475             OSL_ENSURE( false, "Caught InvalidStorageException!" );
2476             return false;
2477         }
2478     }
2479     return true;
2480 }
2481 
2482 //=========================================================================
2483 bool Content::storeData( const uno::Reference< io::XInputStream >& xData,
2484                          const uno::Reference<
2485                             ucb::XCommandEnvironment >& xEnv )
2486     throw ( ucb::CommandFailedException,
2487             task::DocumentPasswordRequest )
2488 {
2489     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2490 
2491     ContentType eType = m_aProps.getType();
2492     if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2493     {
2494         OSL_ENSURE( false, "storeData not supported by root and documents!" );
2495         return false;
2496     }
2497 
2498     Uri aUri( m_xIdentifier->getContentIdentifier() );
2499 
2500     if ( eType == FOLDER )
2501     {
2502         uno::Reference< embed::XStorage > xStorage
2503             = m_pProvider->queryStorage( aUri.getUri(), READ_WRITE_CREATE );
2504 
2505         if ( !xStorage.is() )
2506             return false;
2507 
2508         uno::Reference< beans::XPropertySet > xPropSet(
2509             xStorage, uno::UNO_QUERY );
2510         OSL_ENSURE( xPropSet.is(),
2511                     "Content::storeData - Got no XPropertySet interface!" );
2512         if ( !xPropSet.is() )
2513             return false;
2514 
2515         try
2516         {
2517             // According to MBA, if no mediatype is set, folder and all
2518             // its contents will be lost on save of the document!!!
2519             xPropSet->setPropertyValue(
2520                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ),
2521                 uno::makeAny(
2522                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
2523                         // @@@ better mediatype
2524                         "application/binary" ) ) ) );
2525         }
2526         catch ( beans::UnknownPropertyException const & )
2527         {
2528             OSL_ENSURE( false, "Property MediaType not supported!" );
2529             return false;
2530         }
2531         catch ( beans::PropertyVetoException const & )
2532         {
2533             OSL_ENSURE( false, "Caught PropertyVetoException!" );
2534             return false;
2535         }
2536         catch ( lang::IllegalArgumentException const & )
2537         {
2538             OSL_ENSURE( false, "Caught IllegalArgumentException!" );
2539             return false;
2540         }
2541         catch ( lang::WrappedTargetException const & )
2542         {
2543             OSL_ENSURE( false, "Caught WrappedTargetException!" );
2544             return false;
2545         }
2546 
2547         if ( !commitStorage( xStorage ) )
2548             return false;
2549     }
2550     else if ( eType == STREAM )
2551     {
2552         // stream
2553 
2554         // Important: Parent storage and output stream must be kept alive until
2555         //            changes have been committed!
2556         uno::Reference< embed::XStorage > xStorage
2557             = m_pProvider->queryStorage(
2558                 aUri.getParentUri(), READ_WRITE_CREATE );
2559         uno::Reference< io::XOutputStream > xOut;
2560 
2561         if ( !xStorage.is() )
2562             return false;
2563 
2564         if ( xData.is() )
2565         {
2566             // May throw CommandFailedException, DocumentPasswordRequest!
2567             xOut = getTruncatedOutputStream( xEnv );
2568 
2569             OSL_ENSURE( xOut.is(), "No target data stream!" );
2570 
2571             try
2572             {
2573                 uno::Sequence< sal_Int8 > aBuffer;
2574                 sal_Int32 nRead = xData->readSomeBytes( aBuffer, 65536 );
2575 
2576                 while ( nRead > 0 )
2577                 {
2578                     aBuffer.realloc( nRead );
2579                     xOut->writeBytes( aBuffer );
2580                     aBuffer.realloc( 0 );
2581                     nRead = xData->readSomeBytes( aBuffer, 65536 );
2582                 }
2583 
2584                 closeOutputStream( xOut );
2585             }
2586             catch ( io::NotConnectedException const & )
2587             {
2588                 // readSomeBytes, writeBytes
2589                 OSL_ENSURE( false, "Caught NotConnectedException!" );
2590                 closeOutputStream( xOut );
2591                 return false;
2592             }
2593             catch ( io::BufferSizeExceededException const & )
2594             {
2595                 // readSomeBytes, writeBytes
2596                 OSL_ENSURE( false, "Caught BufferSizeExceededException!" );
2597                 closeOutputStream( xOut );
2598                 return false;
2599             }
2600             catch ( io::IOException const & )
2601             {
2602                 // readSomeBytes, writeBytes
2603                 OSL_ENSURE( false, "Caught IOException!" );
2604                 closeOutputStream( xOut );
2605                 return false;
2606             }
2607             catch ( ... )
2608             {
2609                 closeOutputStream( xOut );
2610                 throw;
2611             }
2612         }
2613 
2614         // Commit changes.
2615         if ( !commitStorage( xStorage ) )
2616             return false;
2617     }
2618     else
2619     {
2620         OSL_ENSURE( false, "Unknown content type!" );
2621         return false;
2622     }
2623     return true;
2624 }
2625 
2626 //=========================================================================
2627 bool Content::renameData(
2628             const uno::Reference< ucb::XContentIdentifier >& xOldId,
2629             const uno::Reference< ucb::XContentIdentifier >& xNewId )
2630 {
2631     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2632 
2633     ContentType eType = m_aProps.getType();
2634     if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2635     {
2636         OSL_ENSURE( false, "renameData not supported by root and documents!" );
2637         return false;
2638     }
2639 
2640     Uri aOldUri( xOldId->getContentIdentifier() );
2641     uno::Reference< embed::XStorage > xStorage
2642         = m_pProvider->queryStorage(
2643             aOldUri.getParentUri(), READ_WRITE_NOCREATE );
2644 
2645     if ( !xStorage.is() )
2646         return false;
2647 
2648     try
2649     {
2650         Uri aNewUri( xNewId->getContentIdentifier() );
2651         xStorage->renameElement(
2652             aOldUri.getDecodedName(), aNewUri.getDecodedName() );
2653     }
2654     catch ( embed::InvalidStorageException const & )
2655     {
2656         // this storage is in invalid state for eny reason
2657         OSL_ENSURE( false, "Caught InvalidStorageException!" );
2658         return false;
2659     }
2660     catch ( lang::IllegalArgumentException const & )
2661     {
2662         // an illegal argument is provided
2663         OSL_ENSURE( false, "Caught IllegalArgumentException!" );
2664         return false;
2665     }
2666     catch ( container::NoSuchElementException const & )
2667     {
2668         // there is no element with old name in this storage
2669         OSL_ENSURE( false, "Caught NoSuchElementException!" );
2670         return false;
2671     }
2672     catch ( container::ElementExistException const & )
2673     {
2674         // an element with new name already exists in this storage
2675         OSL_ENSURE( false, "Caught ElementExistException!" );
2676         return false;
2677     }
2678     catch ( io::IOException const & )
2679     {
2680         // in case of io errors during renaming
2681         OSL_ENSURE( false, "Caught IOException!" );
2682         return false;
2683     }
2684     catch ( embed::StorageWrappedTargetException const & )
2685     {
2686         // wraps other exceptions
2687         OSL_ENSURE( false, "Caught StorageWrappedTargetException!" );
2688         return false;
2689     }
2690 
2691     return commitStorage( xStorage );
2692 }
2693 
2694 //=========================================================================
2695 bool Content::removeData()
2696 {
2697     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2698 
2699     ContentType eType = m_aProps.getType();
2700     if ( ( eType == ROOT ) || ( eType == DOCUMENT ) )
2701     {
2702         OSL_ENSURE( false, "removeData not supported by root and documents!" );
2703         return false;
2704     }
2705 
2706     Uri aUri( m_xIdentifier->getContentIdentifier() );
2707     uno::Reference< embed::XStorage > xStorage
2708         = m_pProvider->queryStorage(
2709             aUri.getParentUri(), READ_WRITE_NOCREATE );
2710 
2711     if ( !xStorage.is() )
2712         return false;
2713 
2714     try
2715     {
2716         xStorage->removeElement( aUri.getDecodedName() );
2717     }
2718     catch ( embed::InvalidStorageException const & )
2719     {
2720         // this storage is in invalid state for eny reason
2721         OSL_ENSURE( false, "Caught InvalidStorageException!" );
2722         return false;
2723     }
2724     catch ( lang::IllegalArgumentException const & )
2725     {
2726         // an illegal argument is provided
2727         OSL_ENSURE( false, "Caught IllegalArgumentException!" );
2728         return false;
2729     }
2730     catch ( container::NoSuchElementException const & )
2731     {
2732         // there is no element with this name in this storage
2733         OSL_ENSURE( false, "Caught NoSuchElementException!" );
2734         return false;
2735     }
2736     catch ( io::IOException const & )
2737     {
2738         // in case of io errors during renaming
2739         OSL_ENSURE( false, "Caught IOException!" );
2740         return false;
2741     }
2742     catch ( embed::StorageWrappedTargetException const & )
2743     {
2744         // wraps other exceptions
2745         OSL_ENSURE( false, "Caught StorageWrappedTargetException!" );
2746         return false;
2747     }
2748 
2749     return commitStorage( xStorage );
2750 }
2751 
2752 //=========================================================================
2753 bool Content::copyData( const Uri & rSourceUri, const rtl::OUString & rNewName )
2754 {
2755     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2756 
2757     ContentType eType = m_aProps.getType();
2758     if ( ( eType == ROOT ) || ( eType == STREAM ) )
2759     {
2760         OSL_ENSURE( false, "copyData not supported by root and streams!" );
2761         return false;
2762     }
2763 
2764     Uri aDestUri( m_xIdentifier->getContentIdentifier() );
2765     uno::Reference< embed::XStorage > xDestStorage
2766         = m_pProvider->queryStorage( aDestUri.getUri(), READ_WRITE_NOCREATE );
2767 
2768     if ( !xDestStorage.is() )
2769         return false;
2770 
2771     uno::Reference< embed::XStorage > xSourceStorage
2772         = m_pProvider->queryStorage( rSourceUri.getParentUri(), READ );
2773 
2774     if ( !xSourceStorage.is() )
2775         return false;
2776 
2777     try
2778     {
2779         xSourceStorage->copyElementTo( rSourceUri.getDecodedName(),
2780                                        xDestStorage,
2781                                        rNewName );
2782     }
2783     catch ( embed::InvalidStorageException const & )
2784     {
2785         // this storage is in invalid state for eny reason
2786         OSL_ENSURE( false, "Caught InvalidStorageException!" );
2787         return false;
2788     }
2789     catch ( lang::IllegalArgumentException const & )
2790     {
2791         // an illegal argument is provided
2792         OSL_ENSURE( false, "Caught IllegalArgumentException!" );
2793         return false;
2794     }
2795     catch ( container::NoSuchElementException const & )
2796     {
2797         // there is no element with this name in this storage
2798         OSL_ENSURE( false, "Caught NoSuchElementException!" );
2799         return false;
2800     }
2801     catch ( container::ElementExistException const & )
2802     {
2803         // there is no element with this name in this storage
2804         OSL_ENSURE( false, "Caught ElementExistException!" );
2805         return false;
2806     }
2807     catch ( io::IOException const & )
2808     {
2809         // in case of io errors during renaming
2810         OSL_ENSURE( false, "Caught IOException!" );
2811         return false;
2812     }
2813     catch ( embed::StorageWrappedTargetException const & )
2814     {
2815         // wraps other exceptions
2816         OSL_ENSURE( false, "Caught StorageWrappedTargetException!" );
2817         return false;
2818     }
2819 
2820     return commitStorage( xDestStorage );
2821 }
2822 
2823 //=========================================================================
2824 // static
2825 bool Content::commitStorage( const uno::Reference< embed::XStorage > & xStorage )
2826 {
2827     // Commit changes
2828     uno::Reference< embed::XTransactedObject > xTO( xStorage, uno::UNO_QUERY );
2829 
2830     OSL_ENSURE( xTO.is(),
2831                 "Required interface css.embed.XTransactedObject missing!" );
2832     try
2833     {
2834         xTO->commit();
2835     }
2836     catch ( io::IOException const & )
2837     {
2838         OSL_ENSURE( false, "Caught IOException!" );
2839         return false;
2840     }
2841     catch ( lang::WrappedTargetException const & )
2842     {
2843         OSL_ENSURE( false, "Caught WrappedTargetException!" );
2844         return false;
2845     }
2846 
2847     return true;
2848 }
2849 
2850 //=========================================================================
2851 // static
2852 bool Content::closeOutputStream(
2853     const uno::Reference< io::XOutputStream > & xOut )
2854 {
2855     if ( xOut.is() )
2856     {
2857         try
2858         {
2859             xOut->closeOutput();
2860             return true;
2861         }
2862         catch ( io::NotConnectedException const & )
2863         {
2864             OSL_ENSURE( false, "Caught NotConnectedException!" );
2865         }
2866         catch ( io::BufferSizeExceededException const & )
2867         {
2868             OSL_ENSURE( false, "Caught BufferSizeExceededException!" );
2869         }
2870         catch ( io::IOException const & )
2871         {
2872             OSL_ENSURE( false, "Caught IOException!" );
2873         }
2874     }
2875     return false;
2876 }
2877 
2878 //=========================================================================
2879 static rtl::OUString obtainPassword(
2880         const rtl::OUString & rName,
2881         task::PasswordRequestMode eMode,
2882         const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2883     throw ( ucb::CommandFailedException,
2884             task::DocumentPasswordRequest )
2885 {
2886     rtl::Reference< DocumentPasswordRequest > xRequest
2887         = new DocumentPasswordRequest( eMode, rName );
2888 
2889     if ( xEnv.is() )
2890     {
2891         uno::Reference< task::XInteractionHandler > xIH
2892             = xEnv->getInteractionHandler();
2893         if ( xIH.is() )
2894         {
2895             xIH->handle( xRequest.get() );
2896 
2897             rtl::Reference< ucbhelper::InteractionContinuation > xSelection
2898                 = xRequest->getSelection();
2899 
2900             if ( xSelection.is() )
2901             {
2902                 // Handler handled the request.
2903                 uno::Reference< task::XInteractionAbort > xAbort(
2904                     xSelection.get(), uno::UNO_QUERY );
2905                 if ( xAbort.is() )
2906                 {
2907                     throw ucb::CommandFailedException(
2908                         rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
2909                             "Abort requested by Interaction Handler." ) ),
2910                         uno::Reference< uno::XInterface >(),
2911                         xRequest->getRequest() );
2912                 }
2913 
2914                 uno::Reference< task::XInteractionPassword > xPassword(
2915                     xSelection.get(), uno::UNO_QUERY );
2916                 if ( xPassword.is() )
2917                 {
2918                     return xPassword->getPassword();
2919                 }
2920 
2921                 // Unknown selection. Should never happen.
2922                 throw ucb::CommandFailedException(
2923                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
2924                         "Interaction Handler selected unknown continuation!" ) ),
2925                     uno::Reference< uno::XInterface >(),
2926                     xRequest->getRequest() );
2927             }
2928         }
2929     }
2930 
2931     // No IH or IH did not handle exception.
2932     task::DocumentPasswordRequest aRequest;
2933     xRequest->getRequest() >>= aRequest;
2934     throw aRequest;
2935 }
2936 
2937 //=========================================================================
2938 uno::Reference< io::XInputStream > Content::getInputStream(
2939         const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2940     throw ( ucb::CommandFailedException,
2941             task::DocumentPasswordRequest )
2942 {
2943     rtl::OUString aUri;
2944     rtl::OUString aPassword;
2945     bool bPasswordRequested = false;
2946 
2947     {
2948         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2949 
2950         OSL_ENSURE( m_aProps.getType() == STREAM,
2951                     "Content::getInputStream - content is no stream!" );
2952 
2953         aUri = Uri( m_xIdentifier->getContentIdentifier() ).getUri();
2954     }
2955 
2956     for ( ;; )
2957     {
2958         try
2959         {
2960             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2961             return uno::Reference< io::XInputStream >(
2962                 m_pProvider->queryInputStream( aUri, aPassword ) );
2963         }
2964         catch ( packages::WrongPasswordException const & )
2965         {
2966             // Obtain (new) password.
2967             aPassword
2968                 = obtainPassword( aUri, /* @@@ find better title */
2969                                   bPasswordRequested
2970                                    ? task::PasswordRequestMode_PASSWORD_REENTER
2971                                    : task::PasswordRequestMode_PASSWORD_ENTER,
2972                                    xEnv );
2973             bPasswordRequested = true;
2974         }
2975     }
2976 }
2977 
2978 //=========================================================================
2979 static uno::Reference< io::XOutputStream > lcl_getTruncatedOutputStream(
2980                 const rtl::OUString & rUri,
2981                 ContentProvider * pProvider,
2982                 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2983     throw ( ucb::CommandFailedException,
2984             task::DocumentPasswordRequest )
2985 {
2986     rtl::OUString aPassword;
2987     bool bPasswordRequested = false;
2988     for ( ;; )
2989     {
2990         try
2991         {
2992             return uno::Reference< io::XOutputStream >(
2993                 pProvider->queryOutputStream(
2994                     rUri, aPassword, true /* truncate */ ) );
2995         }
2996         catch ( packages::WrongPasswordException const & )
2997         {
2998             // Obtain (new) password.
2999             aPassword
3000                 = obtainPassword( rUri, /* @@@ find better title */
3001                                   bPasswordRequested
3002                                    ? task::PasswordRequestMode_PASSWORD_REENTER
3003                                    : task::PasswordRequestMode_PASSWORD_ENTER,
3004                                    xEnv );
3005             bPasswordRequested = true;
3006         }
3007     }
3008 }
3009 
3010 //=========================================================================
3011 uno::Reference< io::XOutputStream > Content::getTruncatedOutputStream(
3012         const uno::Reference< ucb::XCommandEnvironment > & xEnv )
3013     throw ( ucb::CommandFailedException,
3014             task::DocumentPasswordRequest )
3015 {
3016     OSL_ENSURE( m_aProps.getType() == STREAM,
3017                 "Content::getTruncatedOutputStream - content is no stream!" );
3018 
3019     return lcl_getTruncatedOutputStream(
3020             Uri( m_xIdentifier->getContentIdentifier() ).getUri(),
3021             m_pProvider,
3022             xEnv );
3023 }
3024 
3025 //=========================================================================
3026 uno::Reference< io::XStream > Content::getStream(
3027         const uno::Reference< ucb::XCommandEnvironment > & xEnv )
3028     throw ( ucb::CommandFailedException,
3029             task::DocumentPasswordRequest )
3030 {
3031     osl::Guard< osl::Mutex > aGuard( m_aMutex );
3032 
3033     OSL_ENSURE( m_aProps.getType() == STREAM,
3034                 "Content::getStream - content is no stream!" );
3035 
3036     rtl::OUString aUri( Uri( m_xIdentifier->getContentIdentifier() ).getUri() );
3037     rtl::OUString aPassword;
3038     bool bPasswordRequested = false;
3039     for ( ;; )
3040     {
3041         try
3042         {
3043             return uno::Reference< io::XStream >(
3044                 m_pProvider->queryStream(
3045                     aUri, aPassword, false /* no truncate */ ) );
3046         }
3047         catch ( packages::WrongPasswordException const & )
3048         {
3049             // Obtain (new) password.
3050             aPassword
3051                 = obtainPassword( aUri, /* @@@ find better title */
3052                                   bPasswordRequested
3053                                    ? task::PasswordRequestMode_PASSWORD_REENTER
3054                                    : task::PasswordRequestMode_PASSWORD_ENTER,
3055                                    xEnv );
3056             bPasswordRequested = true;
3057         }
3058     }
3059 }
3060 
3061 //=========================================================================
3062 //=========================================================================
3063 //
3064 // ContentProperties Implementation.
3065 //
3066 //=========================================================================
3067 //=========================================================================
3068 
3069 uno::Sequence< ucb::ContentInfo >
3070 ContentProperties::getCreatableContentsInfo() const
3071 {
3072     if ( isContentCreator() )
3073     {
3074         uno::Sequence< beans::Property > aProps( 1 );
3075         aProps.getArray()[ 0 ] = beans::Property(
3076                     rtl::OUString::createFromAscii( "Title" ),
3077                     -1,
3078                     getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
3079                     beans::PropertyAttribute::BOUND );
3080 
3081 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
3082         if ( getType() == DOCUMENT )
3083         {
3084             // streams cannot be created as direct children of document root
3085             uno::Sequence< ucb::ContentInfo > aSeq( 1 );
3086 
3087             // Folder.
3088             aSeq.getArray()[ 0 ].Type
3089                 = rtl::OUString::createFromAscii( TDOC_FOLDER_CONTENT_TYPE );
3090             aSeq.getArray()[ 0 ].Attributes
3091                 = ucb::ContentInfoAttribute::KIND_FOLDER;
3092             aSeq.getArray()[ 0 ].Properties = aProps;
3093 
3094             return aSeq;
3095         }
3096         else
3097         {
3098 #endif
3099             uno::Sequence< ucb::ContentInfo > aSeq( 2 );
3100 
3101             // Folder.
3102             aSeq.getArray()[ 0 ].Type
3103                 = rtl::OUString::createFromAscii( TDOC_FOLDER_CONTENT_TYPE );
3104             aSeq.getArray()[ 0 ].Attributes
3105                 = ucb::ContentInfoAttribute::KIND_FOLDER;
3106             aSeq.getArray()[ 0 ].Properties = aProps;
3107 
3108             // Stream.
3109             aSeq.getArray()[ 1 ].Type
3110                 = rtl::OUString::createFromAscii( TDOC_STREAM_CONTENT_TYPE );
3111             aSeq.getArray()[ 1 ].Attributes
3112                 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
3113                   | ucb::ContentInfoAttribute::KIND_DOCUMENT;
3114             aSeq.getArray()[ 1 ].Properties = aProps;
3115 
3116             return aSeq;
3117 #ifdef NO_STREAM_CREATION_WITHIN_DOCUMENT_ROOT
3118         }
3119 #endif
3120     }
3121     else
3122     {
3123         OSL_ENSURE( sal_False,
3124                     "getCreatableContentsInfo called on non-contentcreator "
3125                     "object!" );
3126 
3127         return uno::Sequence< ucb::ContentInfo >( 0 );
3128     }
3129 }
3130 
3131 //=========================================================================
3132 bool ContentProperties::isContentCreator() const
3133 {
3134     return ( getType() == FOLDER ) || ( getType() == DOCUMENT );
3135 }
3136