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