1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <rtl/uri.hxx>
21 #include <rtl/ustrbuf.hxx>
22 
23 #include <osl/diagnose.h>
24 #include <com/sun/star/lang/NoSupportException.hpp>
25 #include <com/sun/star/sdbc/SQLException.hpp>
26 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
27 #include <com/sun/star/ucb/OpenMode.hpp>
28 #include <com/sun/star/beans/IllegalTypeException.hpp>
29 #include <com/sun/star/io/XActiveDataStreamer.hpp>
30 #include <com/sun/star/io/XOutputStream.hpp>
31 #include <com/sun/star/io/XActiveDataSink.hpp>
32 #include <com/sun/star/ucb/NameClash.hpp>
33 #include <comphelper/fileurl.hxx>
34 #include <cppuhelper/interfacecontainer.hxx>
35 #include <cppuhelper/supportsservice.hxx>
36 #include "filglob.hxx"
37 #include "filid.hxx"
38 #include "filrow.hxx"
39 #include "bc.hxx"
40 #include "prov.hxx"
41 #include "filerror.hxx"
42 #include "filinsreq.hxx"
43 
44 using namespace fileaccess;
45 using namespace com::sun::star;
46 using namespace com::sun::star::uno;
47 using namespace com::sun::star::ucb;
48 
49 #if OSL_DEBUG_LEVEL > 0
50 #define THROW_WHERE SAL_WHERE
51 #else
52 #define THROW_WHERE ""
53 #endif
54 
55 typedef cppu::OMultiTypeInterfaceContainerHelperVar<OUString>
56     PropertyListeners_impl;
57 
58 class fileaccess::PropertyListeners
59     : public PropertyListeners_impl
60 {
61 public:
PropertyListeners(::osl::Mutex & aMutex)62     explicit PropertyListeners( ::osl::Mutex& aMutex )
63         : PropertyListeners_impl( aMutex )
64     {
65     }
66 };
67 
68 
69 /****************************************************************************************/
70 /*                                                                                      */
71 /*                    BaseContent                                                       */
72 /*                                                                                      */
73 /****************************************************************************************/
74 
75 
76 // Private Constructor for just inserted Contents
77 
BaseContent(TaskManager * pMyShell,const OUString & parentName,bool bFolder)78 BaseContent::BaseContent( TaskManager* pMyShell,
79                           const OUString& parentName,
80                           bool bFolder )
81     : m_pMyShell( pMyShell ),
82       m_aUncPath( parentName ),
83       m_bFolder( bFolder ),
84       m_nState( JustInserted )
85 {
86     m_pMyShell->m_pProvider->acquire();
87     // No registering, since we have no name
88 }
89 
90 
91 // Constructor for full featured Contents
92 
BaseContent(TaskManager * pMyShell,const Reference<XContentIdentifier> & xContentIdentifier,const OUString & aUncPath)93 BaseContent::BaseContent( TaskManager* pMyShell,
94                           const Reference< XContentIdentifier >& xContentIdentifier,
95                           const OUString& aUncPath )
96     : m_pMyShell( pMyShell ),
97       m_xContentIdentifier( xContentIdentifier ),
98       m_aUncPath( aUncPath ),
99       m_bFolder( false ),
100       m_nState( FullFeatured )
101 {
102     m_pMyShell->m_pProvider->acquire();
103     m_pMyShell->registerNotifier( m_aUncPath,this );
104     m_pMyShell->insertDefaultProperties( m_aUncPath );
105 }
106 
107 
~BaseContent()108 BaseContent::~BaseContent( )
109 {
110     if( ( m_nState & FullFeatured ) || ( m_nState & Deleted ) )
111     {
112         m_pMyShell->deregisterNotifier( m_aUncPath,this );
113     }
114     m_pMyShell->m_pProvider->release();
115 }
116 
117 
118 // XComponent
119 
120 
121 void SAL_CALL
addEventListener(const Reference<lang::XEventListener> & Listener)122 BaseContent::addEventListener( const Reference< lang::XEventListener >& Listener )
123 {
124     osl::MutexGuard aGuard( m_aMutex );
125 
126     if ( ! m_pDisposeEventListeners )
127         m_pDisposeEventListeners.reset(
128             new comphelper::OInterfaceContainerHelper2( m_aEventListenerMutex ) );
129 
130     m_pDisposeEventListeners->addInterface( Listener );
131 }
132 
133 
134 void SAL_CALL
removeEventListener(const Reference<lang::XEventListener> & Listener)135 BaseContent::removeEventListener( const Reference< lang::XEventListener >& Listener )
136 {
137     osl::MutexGuard aGuard( m_aMutex );
138 
139     if ( m_pDisposeEventListeners )
140         m_pDisposeEventListeners->removeInterface( Listener );
141 }
142 
143 
144 void SAL_CALL
dispose()145 BaseContent::dispose()
146 {
147     lang::EventObject aEvt;
148     std::unique_ptr<comphelper::OInterfaceContainerHelper2> pDisposeEventListeners;
149     std::unique_ptr<comphelper::OInterfaceContainerHelper2> pContentEventListeners;
150     std::unique_ptr<comphelper::OInterfaceContainerHelper2> pPropertySetInfoChangeListeners;
151     std::unique_ptr<PropertyListeners> pPropertyListener;
152 
153     {
154         osl::MutexGuard aGuard( m_aMutex );
155         aEvt.Source = static_cast< XContent* >( this );
156 
157         pDisposeEventListeners = std::move(m_pDisposeEventListeners);
158         pContentEventListeners = std::move(m_pContentEventListeners);
159         pPropertySetInfoChangeListeners = std::move(m_pPropertySetInfoChangeListeners);
160         pPropertyListener = std::move(m_pPropertyListener);
161     }
162 
163     if ( pDisposeEventListeners && pDisposeEventListeners->getLength() )
164         pDisposeEventListeners->disposeAndClear( aEvt );
165 
166     if ( pContentEventListeners && pContentEventListeners->getLength() )
167         pContentEventListeners->disposeAndClear( aEvt );
168 
169     if( pPropertyListener )
170         pPropertyListener->disposeAndClear( aEvt );
171 
172     if( pPropertySetInfoChangeListeners )
173         pPropertySetInfoChangeListeners->disposeAndClear( aEvt );
174 }
175 
176 //  XServiceInfo
177 OUString SAL_CALL
getImplementationName()178 BaseContent::getImplementationName()
179 {
180     return "com.sun.star.comp.ucb.FileContent";
181 }
182 
183 sal_Bool SAL_CALL
supportsService(const OUString & ServiceName)184 BaseContent::supportsService( const OUString& ServiceName )
185 {
186     return cppu::supportsService( this, ServiceName );
187 }
188 
189 Sequence< OUString > SAL_CALL
getSupportedServiceNames()190 BaseContent::getSupportedServiceNames()
191 {
192     Sequence<OUString> ret { "com.sun.star.ucb.FileContent" };
193     return ret;
194 }
195 
196 //  XCommandProcessor
197 
198 
199 sal_Int32 SAL_CALL
createCommandIdentifier()200 BaseContent::createCommandIdentifier()
201 {
202     return m_pMyShell->getCommandId();
203 }
204 
205 
206 void SAL_CALL
abort(sal_Int32)207 BaseContent::abort( sal_Int32 /*CommandId*/ )
208 {
209 }
210 
211 
212 Any SAL_CALL
execute(const Command & aCommand,sal_Int32 CommandId,const Reference<XCommandEnvironment> & Environment)213 BaseContent::execute( const Command& aCommand,
214                       sal_Int32 CommandId,
215                       const Reference< XCommandEnvironment >& Environment )
216 {
217     if( ! CommandId )
218         // A Command with commandid zero cannot be aborted
219         CommandId = createCommandIdentifier();
220 
221     m_pMyShell->startTask( CommandId,
222                            Environment );
223 
224     Any aAny;
225 
226     if (aCommand.Name == "getPropertySetInfo")  // No exceptions
227     {
228         aAny <<= getPropertySetInfo();
229     }
230     else if (aCommand.Name == "getCommandInfo")  // no exceptions
231     {
232         aAny <<= getCommandInfo();
233     }
234     else if ( aCommand.Name == "setPropertyValues" )
235     {
236         Sequence< beans::PropertyValue > sPropertyValues;
237 
238         if( ! ( aCommand.Argument >>= sPropertyValues ) )
239             m_pMyShell->installError( CommandId,
240                                       TASKHANDLING_WRONG_SETPROPERTYVALUES_ARGUMENT );
241         else
242             aAny <<= setPropertyValues( CommandId,sPropertyValues );  // calls endTask by itself
243     }
244     else if ( aCommand.Name == "getPropertyValues" )
245     {
246         Sequence< beans::Property > ListOfRequestedProperties;
247 
248         if( ! ( aCommand.Argument >>= ListOfRequestedProperties ) )
249             m_pMyShell->installError( CommandId,
250                                       TASKHANDLING_WRONG_GETPROPERTYVALUES_ARGUMENT );
251         else
252             aAny <<= getPropertyValues( CommandId,
253                                         ListOfRequestedProperties );
254     }
255     else if ( aCommand.Name == "open" )
256     {
257         OpenCommandArgument2 aOpenArgument;
258         if( ! ( aCommand.Argument >>= aOpenArgument ) )
259             m_pMyShell->installError( CommandId,
260                                       TASKHANDLING_WRONG_OPEN_ARGUMENT );
261         else
262         {
263             Reference< XDynamicResultSet > result = open( CommandId,aOpenArgument );
264             if( result.is() )
265                 aAny <<= result;
266         }
267     }
268     else if ( aCommand.Name == "delete" )
269     {
270         if( ! aCommand.Argument.has< bool >() )
271             m_pMyShell->installError( CommandId,
272                                       TASKHANDLING_WRONG_DELETE_ARGUMENT );
273         else
274             deleteContent( CommandId );
275     }
276     else if ( aCommand.Name == "transfer" )
277     {
278         TransferInfo aTransferInfo;
279         if( ! ( aCommand.Argument >>= aTransferInfo ) )
280             m_pMyShell->installError( CommandId,
281                                       TASKHANDLING_WRONG_TRANSFER_ARGUMENT );
282         else
283             transfer( CommandId, aTransferInfo );
284     }
285     else if ( aCommand.Name == "insert" )
286     {
287         InsertCommandArgument aInsertArgument;
288         if( ! ( aCommand.Argument >>= aInsertArgument ) )
289             m_pMyShell->installError( CommandId,
290                                       TASKHANDLING_WRONG_INSERT_ARGUMENT );
291         else
292             insert( CommandId,aInsertArgument );
293     }
294     else if ( aCommand.Name == "getCasePreservingURL" )
295     {
296         Sequence< beans::Property > seq(1);
297         seq[0] = beans::Property(
298             "CasePreservingURL",
299             -1,
300             cppu::UnoType<sal_Bool>::get(),
301             0 );
302         Reference< sdbc::XRow > xRow = getPropertyValues( CommandId,seq );
303         OUString CasePreservingURL = xRow->getString(1);
304         if(!xRow->wasNull())
305             aAny <<= CasePreservingURL;
306     }
307     else if ( aCommand.Name == "createNewContent" )
308     {
309         ucb::ContentInfo aArg;
310         if ( !( aCommand.Argument >>= aArg ) )
311             m_pMyShell->installError( CommandId,
312                                       TASKHANDLING_WRONG_CREATENEWCONTENT_ARGUMENT );
313         else
314             aAny <<= createNewContent( aArg );
315     }
316     else
317         m_pMyShell->installError( CommandId,
318                                   TASKHANDLER_UNSUPPORTED_COMMAND );
319 
320 
321     // This is the only function allowed to throw an exception
322     endTask( CommandId );
323 
324     return aAny;
325 }
326 
327 
328 void SAL_CALL
addPropertiesChangeListener(const Sequence<OUString> & PropertyNames,const Reference<beans::XPropertiesChangeListener> & Listener)329 BaseContent::addPropertiesChangeListener(
330     const Sequence< OUString >& PropertyNames,
331     const Reference< beans::XPropertiesChangeListener >& Listener )
332 {
333     if( ! Listener.is() )
334         return;
335 
336     osl::MutexGuard aGuard( m_aMutex );
337 
338     if( ! m_pPropertyListener )
339         m_pPropertyListener.reset( new PropertyListeners( m_aEventListenerMutex ) );
340 
341 
342     if( !PropertyNames.hasElements() )
343         m_pPropertyListener->addInterface( OUString(),Listener );
344     else
345     {
346         Reference< beans::XPropertySetInfo > xProp = m_pMyShell->info_p( m_aUncPath );
347         for( const auto& rName : PropertyNames )
348             if( xProp->hasPropertyByName( rName ) )
349                 m_pPropertyListener->addInterface( rName,Listener );
350     }
351 }
352 
353 
354 void SAL_CALL
removePropertiesChangeListener(const Sequence<OUString> & PropertyNames,const Reference<beans::XPropertiesChangeListener> & Listener)355 BaseContent::removePropertiesChangeListener( const Sequence< OUString >& PropertyNames,
356                                              const Reference< beans::XPropertiesChangeListener >& Listener )
357 {
358     if( ! Listener.is() )
359         return;
360 
361     osl::MutexGuard aGuard( m_aMutex );
362 
363     if( ! m_pPropertyListener )
364         return;
365 
366     for( const auto& rName : PropertyNames )
367         m_pPropertyListener->removeInterface( rName,Listener );
368 
369     m_pPropertyListener->removeInterface( OUString(), Listener );
370 }
371 
372 
373 // XContent
374 
375 
376 Reference< ucb::XContentIdentifier > SAL_CALL
getIdentifier()377 BaseContent::getIdentifier()
378 {
379     return m_xContentIdentifier;
380 }
381 
382 
383 OUString SAL_CALL
getContentType()384 BaseContent::getContentType()
385 {
386     if( !( m_nState & Deleted ) )
387     {
388         if( m_nState & JustInserted )
389         {
390             if ( m_bFolder )
391                 return TaskManager::FolderContentType;
392             else
393                 return TaskManager::FileContentType;
394         }
395         else
396         {
397             try
398             {
399                 // Who am I ?
400                 Sequence< beans::Property > seq(1);
401                 seq[0] = beans::Property( "IsDocument",
402                                           -1,
403                                           cppu::UnoType<sal_Bool>::get(),
404                                           0 );
405                 Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq );
406                 bool IsDocument = xRow->getBoolean( 1 );
407 
408                 if ( !xRow->wasNull() )
409                 {
410                     if ( IsDocument )
411                         return TaskManager::FileContentType;
412                     else
413                         return TaskManager::FolderContentType;
414                 }
415                 else
416                 {
417                     OSL_FAIL( "BaseContent::getContentType - Property value was null!" );
418                 }
419             }
420             catch (const sdbc::SQLException&)
421             {
422                 OSL_FAIL( "BaseContent::getContentType - Caught SQLException!" );
423             }
424         }
425     }
426 
427     return OUString();
428 }
429 
430 
431 void SAL_CALL
addContentEventListener(const Reference<XContentEventListener> & Listener)432 BaseContent::addContentEventListener(
433     const Reference< XContentEventListener >& Listener )
434 {
435     osl::MutexGuard aGuard( m_aMutex );
436 
437     if ( ! m_pContentEventListeners )
438         m_pContentEventListeners.reset(
439             new comphelper::OInterfaceContainerHelper2( m_aEventListenerMutex ) );
440 
441 
442     m_pContentEventListeners->addInterface( Listener );
443 }
444 
445 
446 void SAL_CALL
removeContentEventListener(const Reference<XContentEventListener> & Listener)447 BaseContent::removeContentEventListener(
448     const Reference< XContentEventListener >& Listener )
449 {
450     osl::MutexGuard aGuard( m_aMutex );
451 
452     if ( m_pContentEventListeners )
453         m_pContentEventListeners->removeInterface( Listener );
454 }
455 
456 
457 // XPropertyContainer
458 
459 
460 void SAL_CALL
addProperty(const OUString & Name,sal_Int16 Attributes,const Any & DefaultValue)461 BaseContent::addProperty(
462     const OUString& Name,
463     sal_Int16 Attributes,
464     const Any& DefaultValue )
465 {
466     if( ( m_nState & JustInserted ) || ( m_nState & Deleted ) || Name.isEmpty() )
467     {
468         throw lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
469     }
470 
471     m_pMyShell->associate( m_aUncPath,Name,DefaultValue,Attributes );
472 }
473 
474 
475 void SAL_CALL
removeProperty(const OUString & Name)476 BaseContent::removeProperty( const OUString& Name )
477 {
478 
479     if( m_nState & Deleted )
480         throw beans::UnknownPropertyException( Name );
481 
482     m_pMyShell->deassociate( m_aUncPath, Name );
483 }
484 
485 
486 // XContentCreator
487 
488 
489 Sequence< ContentInfo > SAL_CALL
queryCreatableContentsInfo()490 BaseContent::queryCreatableContentsInfo()
491 {
492     return TaskManager::queryCreatableContentsInfo();
493 }
494 
495 
496 Reference< XContent > SAL_CALL
createNewContent(const ContentInfo & Info)497 BaseContent::createNewContent( const ContentInfo& Info )
498 {
499     // Check type.
500     if ( Info.Type.isEmpty() )
501         return Reference< XContent >();
502 
503     bool bFolder = Info.Type == TaskManager::FolderContentType;
504     if ( !bFolder )
505     {
506         if ( Info.Type != TaskManager::FileContentType )
507         {
508             // Neither folder nor file to create!
509             return Reference< XContent >();
510         }
511     }
512 
513     // Who am I ?
514     bool IsDocument = false;
515 
516     try
517     {
518         Sequence< beans::Property > seq(1);
519         seq[0] = beans::Property( "IsDocument",
520                                   -1,
521                                   cppu::UnoType<sal_Bool>::get(),
522                                   0 );
523         Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq );
524         IsDocument = xRow->getBoolean( 1 );
525 
526         if ( xRow->wasNull() )
527         {
528             IsDocument = false;
529 //              OSL_FAIL( //                          "BaseContent::createNewContent - Property value was null!" );
530 //              return Reference< XContent >();
531         }
532     }
533     catch (const sdbc::SQLException&)
534     {
535         OSL_FAIL( "BaseContent::createNewContent - Caught SQLException!" );
536         return Reference< XContent >();
537     }
538 
539     OUString dstUncPath;
540 
541     if( IsDocument )
542     {
543         // KSO: Why is a document a XContentCreator? This is quite unusual.
544         dstUncPath = getParentName( m_aUncPath );
545     }
546     else
547         dstUncPath = m_aUncPath;
548 
549     BaseContent* p = new BaseContent( m_pMyShell, dstUncPath, bFolder );
550     return Reference< XContent >( p );
551 }
552 
553 
554 // XPropertySetInfoChangeNotifier
555 
556 
557 void SAL_CALL
addPropertySetInfoChangeListener(const Reference<beans::XPropertySetInfoChangeListener> & Listener)558 BaseContent::addPropertySetInfoChangeListener(
559     const Reference< beans::XPropertySetInfoChangeListener >& Listener )
560 {
561     osl::MutexGuard aGuard( m_aMutex );
562     if( ! m_pPropertySetInfoChangeListeners )
563         m_pPropertySetInfoChangeListeners.reset( new comphelper::OInterfaceContainerHelper2( m_aEventListenerMutex ) );
564 
565     m_pPropertySetInfoChangeListeners->addInterface( Listener );
566 }
567 
568 
569 void SAL_CALL
removePropertySetInfoChangeListener(const Reference<beans::XPropertySetInfoChangeListener> & Listener)570 BaseContent::removePropertySetInfoChangeListener(
571     const Reference< beans::XPropertySetInfoChangeListener >& Listener )
572 {
573     osl::MutexGuard aGuard( m_aMutex );
574 
575     if( m_pPropertySetInfoChangeListeners )
576         m_pPropertySetInfoChangeListeners->removeInterface( Listener );
577 }
578 
579 
580 // XChild
581 
582 
583 Reference< XInterface > SAL_CALL
getParent()584 BaseContent::getParent()
585 {
586     OUString ParentUnq = getParentName( m_aUncPath );
587     OUString ParentUrl;
588 
589 
590     bool err = fileaccess::TaskManager::getUrlFromUnq( ParentUnq, ParentUrl );
591     if( err )
592         return Reference< XInterface >( nullptr );
593 
594     FileContentIdentifier* p = new FileContentIdentifier( ParentUnq );
595     Reference< XContentIdentifier > Identifier( p );
596 
597     try
598     {
599         return Reference<XInterface>( m_pMyShell->m_pProvider->queryContent( Identifier ), UNO_QUERY );
600     }
601     catch (const IllegalIdentifierException&)
602     {
603         return Reference< XInterface >();
604     }
605 }
606 
607 
608 void SAL_CALL
setParent(const Reference<XInterface> &)609 BaseContent::setParent(
610     const Reference< XInterface >& )
611 {
612     throw lang::NoSupportException( THROW_WHERE );
613 }
614 
615 
616 // Private Methods
617 
618 
619 Reference< XCommandInfo >
getCommandInfo()620 BaseContent::getCommandInfo()
621 {
622     if( m_nState & Deleted )
623         return Reference< XCommandInfo >();
624 
625     return m_pMyShell->info_c();
626 }
627 
628 
629 Reference< beans::XPropertySetInfo >
getPropertySetInfo()630 BaseContent::getPropertySetInfo()
631 {
632     if( m_nState & Deleted )
633         return Reference< beans::XPropertySetInfo >();
634 
635     return m_pMyShell->info_p( m_aUncPath );
636 }
637 
638 Reference< sdbc::XRow >
getPropertyValues(sal_Int32 nMyCommandIdentifier,const Sequence<beans::Property> & PropertySet)639 BaseContent::getPropertyValues(
640     sal_Int32 nMyCommandIdentifier,
641     const Sequence< beans::Property >& PropertySet )
642 {
643     sal_Int32 nProps = PropertySet.getLength();
644     if ( !nProps )
645         return Reference< sdbc::XRow >();
646 
647     if( m_nState & Deleted )
648     {
649         Sequence< Any > aValues( nProps );
650         return Reference< sdbc::XRow >( new XRow_impl( m_pMyShell, aValues ) );
651     }
652 
653     if( m_nState & JustInserted )
654     {
655         Sequence< Any > aValues( nProps );
656         Any* pValues = aValues.getArray();
657 
658         const beans::Property* pProps = PropertySet.getConstArray();
659 
660         for ( sal_Int32 n = 0; n < nProps; ++n )
661         {
662             const beans::Property& rProp = pProps[ n ];
663             Any& rValue = pValues[ n ];
664 
665             if ( rProp.Name == "ContentType" )
666             {
667                 rValue <<= OUString(m_bFolder ? TaskManager::FolderContentType
668                     : TaskManager::FileContentType);
669             }
670             else if ( rProp.Name == "IsFolder" )
671             {
672                 rValue <<= m_bFolder;
673             }
674             else if ( rProp.Name == "IsDocument" )
675             {
676                 rValue <<= !m_bFolder;
677             }
678         }
679 
680         return Reference< sdbc::XRow >(
681             new XRow_impl( m_pMyShell, aValues ) );
682     }
683 
684     return m_pMyShell->getv( nMyCommandIdentifier,
685                              m_aUncPath,
686                              PropertySet );
687 }
688 
689 
690 Sequence< Any >
setPropertyValues(sal_Int32 nMyCommandIdentifier,const Sequence<beans::PropertyValue> & Values)691 BaseContent::setPropertyValues(
692     sal_Int32 nMyCommandIdentifier,
693     const Sequence< beans::PropertyValue >& Values )
694 {
695     if( m_nState & Deleted )
696     {   //  To do
697         return Sequence< Any >( Values.getLength() );
698     }
699 
700     const OUString Title("Title");
701 
702     // Special handling for files which have to be inserted
703     if( m_nState & JustInserted )
704     {
705         for( const auto& rValue : Values )
706         {
707             if( rValue.Name == Title )
708             {
709                 OUString NewTitle;
710                 if( rValue.Value >>= NewTitle )
711                 {
712                     if ( m_nState & NameForInsertionSet )
713                     {
714                         // User wants to set another Title before "insert".
715                         // m_aUncPath contains previous own URI.
716 
717                         sal_Int32 nLastSlash = m_aUncPath.lastIndexOf( '/' );
718                         bool bTrailingSlash = false;
719                         if ( nLastSlash == m_aUncPath.getLength() - 1 )
720                         {
721                             bTrailingSlash = true;
722                             nLastSlash
723                                 = m_aUncPath.lastIndexOf( '/', nLastSlash );
724                         }
725 
726                         OSL_ENSURE( nLastSlash != -1,
727                                     "BaseContent::setPropertyValues: "
728                                     "Invalid URL!" );
729 
730                         OUStringBuffer aBuf(
731                             m_aUncPath.copy( 0, nLastSlash + 1 ) );
732 
733                         if ( !NewTitle.isEmpty() )
734                         {
735                             aBuf.append( NewTitle );
736                             if ( bTrailingSlash )
737                                 aBuf.append( '/' );
738                         }
739                         else
740                         {
741                             m_nState &= ~NameForInsertionSet;
742                         }
743 
744                         m_aUncPath = aBuf.makeStringAndClear();
745                     }
746                     else
747                     {
748                         if ( !NewTitle.isEmpty() )
749                         {
750                             // Initial Title before "insert".
751                             // m_aUncPath contains parent's URI.
752 
753                             if( !m_aUncPath.endsWith( "/" ) )
754                                 m_aUncPath += "/";
755 
756                             m_aUncPath += rtl::Uri::encode( NewTitle,
757                                                             rtl_UriCharClassPchar,
758                                                             rtl_UriEncodeIgnoreEscapes,
759                                                             RTL_TEXTENCODING_UTF8 );
760                             m_nState |= NameForInsertionSet;
761                         }
762                     }
763                 }
764             }
765         }
766 
767         return Sequence< Any >( Values.getLength() );
768     }
769     else
770     {
771         Sequence< Any > ret = m_pMyShell->setv( m_aUncPath,  // Does not handle Title
772                                                 Values );
773 
774         // Special handling Title: Setting Title is equivalent to a renaming of the underlying file
775         for( sal_Int32 i = 0; i < Values.getLength(); ++i )
776         {
777             if( Values[i].Name != Title )
778                 continue;                  // handled by setv
779 
780             OUString NewTitle;
781             if( !( Values[i].Value >>= NewTitle ) )
782             {
783                 ret[i] <<= beans::IllegalTypeException( THROW_WHERE );
784                 break;
785             }
786             else if( NewTitle.isEmpty() )
787             {
788                 ret[i] <<= lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
789                 break;
790             }
791 
792 
793             OUString aDstName = getParentName( m_aUncPath );
794             if( !aDstName.endsWith("/") )
795                 aDstName += "/";
796 
797             aDstName += rtl::Uri::encode( NewTitle,
798                                           rtl_UriCharClassPchar,
799                                           rtl_UriEncodeIgnoreEscapes,
800                                           RTL_TEXTENCODING_UTF8 );
801 
802             m_pMyShell->move( nMyCommandIdentifier,     // move notifies the children also;
803                               m_aUncPath,
804                               aDstName,
805                               NameClash::KEEP );
806 
807             try
808             {
809                 endTask( nMyCommandIdentifier );
810             }
811             catch(const Exception& e)
812             {
813                 ret[i] <<= e;
814             }
815 
816             // NameChanges come back through a ContentEvent
817             break; // only handling Title
818         } // end for
819 
820         return ret;
821     }
822 }
823 
824 
825 Reference< XDynamicResultSet >
open(sal_Int32 nMyCommandIdentifier,const OpenCommandArgument2 & aCommandArgument)826 BaseContent::open(
827     sal_Int32 nMyCommandIdentifier,
828     const OpenCommandArgument2& aCommandArgument )
829 {
830     Reference< XDynamicResultSet > retValue;
831 
832     if( m_nState & Deleted )
833     {
834         m_pMyShell->installError( nMyCommandIdentifier,
835                                   TASKHANDLING_DELETED_STATE_IN_OPEN_COMMAND );
836     }
837     else if( m_nState & JustInserted )
838     {
839         m_pMyShell->installError( nMyCommandIdentifier,
840                                   TASKHANDLING_INSERTED_STATE_IN_OPEN_COMMAND );
841     }
842     else
843     {
844         if( aCommandArgument.Mode == OpenMode::DOCUMENT ||
845             aCommandArgument.Mode == OpenMode::DOCUMENT_SHARE_DENY_NONE )
846 
847         {
848             Reference< io::XOutputStream > outputStream( aCommandArgument.Sink,UNO_QUERY );
849             if( outputStream.is() )
850             {
851                 m_pMyShell->page( nMyCommandIdentifier,
852                                   m_aUncPath,
853                                   outputStream );
854             }
855 
856             bool bLock = ( aCommandArgument.Mode != OpenMode::DOCUMENT_SHARE_DENY_NONE );
857 
858             Reference< io::XActiveDataSink > activeDataSink( aCommandArgument.Sink,UNO_QUERY );
859             if( activeDataSink.is() )
860             {
861                 activeDataSink->setInputStream( m_pMyShell->open( nMyCommandIdentifier,
862                                                                   m_aUncPath,
863                                                                   bLock ) );
864             }
865 
866             Reference< io::XActiveDataStreamer > activeDataStreamer( aCommandArgument.Sink,UNO_QUERY );
867             if( activeDataStreamer.is() )
868             {
869                 activeDataStreamer->setStream( m_pMyShell->open_rw( nMyCommandIdentifier,
870                                                                     m_aUncPath,
871                                                                     bLock ) );
872             }
873         }
874         else if ( aCommandArgument.Mode == OpenMode::ALL        ||
875                   aCommandArgument.Mode == OpenMode::FOLDERS    ||
876                   aCommandArgument.Mode == OpenMode::DOCUMENTS )
877         {
878             retValue = m_pMyShell->ls( nMyCommandIdentifier,
879                                        m_aUncPath,
880                                        aCommandArgument.Mode,
881                                        aCommandArgument.Properties,
882                                        aCommandArgument.SortingInfo );
883         }
884 //          else if(  aCommandArgument.Mode ==
885 //                    OpenMode::DOCUMENT_SHARE_DENY_NONE  ||
886 //                    aCommandArgument.Mode ==
887 //                    OpenMode::DOCUMENT_SHARE_DENY_WRITE )
888 //              m_pMyShell->installError( nMyCommandIdentifier,
889 //                                        TASKHANDLING_UNSUPPORTED_OPEN_MODE,
890 //                                        aCommandArgument.Mode);
891         else
892             m_pMyShell->installError( nMyCommandIdentifier,
893                                       TASKHANDLING_UNSUPPORTED_OPEN_MODE,
894                                       aCommandArgument.Mode);
895     }
896 
897     return retValue;
898 }
899 
900 
901 void
deleteContent(sal_Int32 nMyCommandIdentifier)902 BaseContent::deleteContent( sal_Int32 nMyCommandIdentifier )
903 {
904     if( m_nState & Deleted )
905         return;
906 
907     if( m_pMyShell->remove( nMyCommandIdentifier,m_aUncPath ) )
908     {
909         osl::MutexGuard aGuard( m_aMutex );
910         m_nState |= Deleted;
911     }
912 }
913 
914 
915 void
transfer(sal_Int32 nMyCommandIdentifier,const TransferInfo & aTransferInfo)916 BaseContent::transfer( sal_Int32 nMyCommandIdentifier,
917                        const TransferInfo& aTransferInfo )
918 {
919     if( m_nState & Deleted )
920         return;
921 
922     if( !comphelper::isFileUrl(aTransferInfo.SourceURL) )
923     {
924         m_pMyShell->installError( nMyCommandIdentifier,
925                                   TASKHANDLING_TRANSFER_INVALIDSCHEME );
926         return;
927     }
928 
929     OUString srcUnc;
930     if( fileaccess::TaskManager::getUnqFromUrl( aTransferInfo.SourceURL,srcUnc ) )
931     {
932         m_pMyShell->installError( nMyCommandIdentifier,
933                                   TASKHANDLING_TRANSFER_INVALIDURL );
934         return;
935     }
936 
937     OUString srcUncPath = srcUnc;
938 
939     // Determine the new title !
940     OUString NewTitle;
941     if( !aTransferInfo.NewTitle.isEmpty() )
942         NewTitle = rtl::Uri::encode( aTransferInfo.NewTitle,
943                                      rtl_UriCharClassPchar,
944                                      rtl_UriEncodeIgnoreEscapes,
945                                      RTL_TEXTENCODING_UTF8 );
946     else
947         NewTitle = srcUncPath.copy( 1 + srcUncPath.lastIndexOf( '/' ) );
948 
949     // Is destination a document or a folder ?
950     Sequence< beans::Property > seq(1);
951     seq[0] = beans::Property( "IsDocument",
952                               -1,
953                               cppu::UnoType<sal_Bool>::get(),
954                               0 );
955     Reference< sdbc::XRow > xRow = getPropertyValues( nMyCommandIdentifier,seq );
956     bool IsDocument = xRow->getBoolean( 1 );
957     if( xRow->wasNull() )
958     {   // Destination file type could not be determined
959         m_pMyShell->installError( nMyCommandIdentifier,
960                                   TASKHANDLING_TRANSFER_DESTFILETYPE );
961         return;
962     }
963 
964     OUString dstUncPath;
965     if( IsDocument )
966     {   // as sibling
967         sal_Int32 lastSlash = m_aUncPath.lastIndexOf( '/' );
968         dstUncPath = m_aUncPath.copy(0,lastSlash );
969     }
970     else
971         // as child
972         dstUncPath = m_aUncPath;
973 
974     dstUncPath += "/" + NewTitle;
975 
976     sal_Int32 NameClash = aTransferInfo.NameClash;
977 
978     if( aTransferInfo.MoveData )
979         m_pMyShell->move( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash );
980     else
981         m_pMyShell->copy( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash );
982 }
983 
984 
insert(sal_Int32 nMyCommandIdentifier,const InsertCommandArgument & aInsertArgument)985 void BaseContent::insert( sal_Int32 nMyCommandIdentifier,
986                                    const InsertCommandArgument& aInsertArgument )
987 {
988     if( m_nState & FullFeatured )
989     {
990         m_pMyShell->write( nMyCommandIdentifier,
991                            m_aUncPath,
992                            aInsertArgument.ReplaceExisting,
993                            aInsertArgument.Data );
994         return;
995     }
996 
997     if( ! ( m_nState & JustInserted ) )
998     {
999         m_pMyShell->installError( nMyCommandIdentifier,
1000                                   TASKHANDLING_NOFRESHINSERT_IN_INSERT_COMMAND );
1001         return;
1002     }
1003 
1004     // Inserts the content, which has the flag m_bIsFresh
1005 
1006     if( ! (m_nState & NameForInsertionSet) )
1007     {
1008         m_pMyShell->installError( nMyCommandIdentifier,
1009                                   TASKHANDLING_NONAMESET_INSERT_COMMAND );
1010         return;
1011     }
1012 
1013     // Inserting a document or a file?
1014     bool bDocument = false;
1015 
1016     Sequence< beans::Property > seq(1);
1017     seq[0] = beans::Property( "IsDocument",
1018                               -1,
1019                               cppu::UnoType<sal_Bool>::get(),
1020                               0 );
1021 
1022     Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq );
1023 
1024     bool contentTypeSet = true;  // is set to false, if contentType not set
1025     try
1026     {
1027         bDocument = xRow->getBoolean( 1 );
1028         if( xRow->wasNull() )
1029             contentTypeSet = false;
1030 
1031     }
1032     catch (const sdbc::SQLException&)
1033     {
1034         OSL_FAIL( "BaseContent::insert - Caught SQLException!" );
1035         contentTypeSet = false;
1036     }
1037 
1038     if( ! contentTypeSet )
1039     {
1040         m_pMyShell->installError( nMyCommandIdentifier,
1041                                   TASKHANDLING_NOCONTENTTYPE_INSERT_COMMAND );
1042         return;
1043     }
1044 
1045 
1046     bool success = false;
1047     if( bDocument )
1048         success = m_pMyShell->mkfil( nMyCommandIdentifier,
1049                                      m_aUncPath,
1050                                      aInsertArgument.ReplaceExisting,
1051                                      aInsertArgument.Data );
1052     else
1053     {
1054         while( ! success )
1055         {
1056             success = m_pMyShell->mkdir( nMyCommandIdentifier,
1057                                          m_aUncPath,
1058                                          aInsertArgument.ReplaceExisting );
1059             if( success )
1060                 break;
1061 
1062             XInteractionRequestImpl aRequestImpl(
1063                     rtl::Uri::decode(
1064                         getTitle(m_aUncPath),
1065                         rtl_UriDecodeWithCharset,
1066                         RTL_TEXTENCODING_UTF8),
1067                     static_cast<cppu::OWeakObject*>(this),
1068                     m_pMyShell,nMyCommandIdentifier);
1069             uno::Reference<task::XInteractionRequest> const& xReq(aRequestImpl.getRequest());
1070 
1071             m_pMyShell->handleTask( nMyCommandIdentifier, xReq );
1072             if (aRequestImpl.aborted() || aRequestImpl.newName().isEmpty())
1073                 // means aborting
1074                 break;
1075 
1076             // determine new uncpath
1077             m_pMyShell->clearError( nMyCommandIdentifier );
1078             m_aUncPath = getParentName( m_aUncPath );
1079             if( !m_aUncPath.endsWith( "/" ) )
1080                 m_aUncPath += "/";
1081 
1082             m_aUncPath += rtl::Uri::encode( aRequestImpl.newName(),
1083                                             rtl_UriCharClassPchar,
1084                                             rtl_UriEncodeIgnoreEscapes,
1085                                             RTL_TEXTENCODING_UTF8 );
1086         }
1087     }
1088 
1089     if ( ! success )
1090         return;
1091 
1092     m_xContentIdentifier.set( new FileContentIdentifier( m_aUncPath ) );
1093 
1094     m_pMyShell->registerNotifier( m_aUncPath,this );
1095     m_pMyShell->insertDefaultProperties( m_aUncPath );
1096 
1097     osl::MutexGuard aGuard( m_aMutex );
1098     m_nState = FullFeatured;
1099 }
1100 
1101 
endTask(sal_Int32 CommandId)1102 void BaseContent::endTask( sal_Int32 CommandId )
1103 {
1104     // This is the only function allowed to throw an exception
1105     m_pMyShell->endTask( CommandId,m_aUncPath,this );
1106 }
1107 
1108 
1109 std::unique_ptr<ContentEventNotifier>
cDEL()1110 BaseContent::cDEL()
1111 {
1112     osl::MutexGuard aGuard( m_aMutex );
1113 
1114     m_nState |= Deleted;
1115 
1116     std::unique_ptr<ContentEventNotifier> p;
1117     if( m_pContentEventListeners )
1118     {
1119         p.reset( new ContentEventNotifier( m_pMyShell,
1120                                       this,
1121                                       m_xContentIdentifier,
1122                                       m_pContentEventListeners->getElements() ) );
1123     }
1124 
1125     return p;
1126 }
1127 
1128 
1129 std::unique_ptr<ContentEventNotifier>
cEXC(const OUString & aNewName)1130 BaseContent::cEXC( const OUString& aNewName )
1131 {
1132     osl::MutexGuard aGuard( m_aMutex );
1133 
1134     Reference< XContentIdentifier > xOldRef = m_xContentIdentifier;
1135     m_aUncPath = aNewName;
1136     FileContentIdentifier* pp = new FileContentIdentifier( aNewName );
1137     m_xContentIdentifier.set( pp );
1138 
1139     std::unique_ptr<ContentEventNotifier> p;
1140     if( m_pContentEventListeners )
1141         p.reset( new ContentEventNotifier( m_pMyShell,
1142                                       this,
1143                                       m_xContentIdentifier,
1144                                       xOldRef,
1145                                       m_pContentEventListeners->getElements() ) );
1146 
1147     return p;
1148 }
1149 
1150 
1151 std::unique_ptr<ContentEventNotifier>
cCEL()1152 BaseContent::cCEL()
1153 {
1154     osl::MutexGuard aGuard( m_aMutex );
1155     std::unique_ptr<ContentEventNotifier> p;
1156     if( m_pContentEventListeners )
1157         p.reset( new ContentEventNotifier( m_pMyShell,
1158                                       this,
1159                                       m_xContentIdentifier,
1160                                       m_pContentEventListeners->getElements() ) );
1161 
1162     return p;
1163 }
1164 
1165 std::unique_ptr<PropertySetInfoChangeNotifier>
cPSL()1166 BaseContent::cPSL()
1167 {
1168     osl::MutexGuard aGuard( m_aMutex );
1169     std::unique_ptr<PropertySetInfoChangeNotifier> p;
1170     if( m_pPropertySetInfoChangeListeners  )
1171         p.reset( new PropertySetInfoChangeNotifier( this,
1172                                                m_pPropertySetInfoChangeListeners->getElements() ) );
1173 
1174     return p;
1175 }
1176 
1177 
1178 std::unique_ptr<PropertyChangeNotifier>
cPCL()1179 BaseContent::cPCL()
1180 {
1181     osl::MutexGuard aGuard( m_aMutex );
1182 
1183     if (!m_pPropertyListener)
1184         return nullptr;
1185 
1186     const Sequence< OUString > seqNames = m_pPropertyListener->getContainedTypes();
1187 
1188     std::unique_ptr<PropertyChangeNotifier> p;
1189 
1190     if( seqNames.hasElements() )
1191     {
1192         std::unique_ptr<ListenerMap> listener(new ListenerMap);
1193         for( const auto& rName : seqNames )
1194         {
1195             cppu::OInterfaceContainerHelper* pContainer = m_pPropertyListener->getContainer(rName);
1196             if (!pContainer)
1197                 continue;
1198             (*listener)[rName] = pContainer->getElements();
1199         }
1200 
1201         p.reset( new PropertyChangeNotifier( this, std::move(listener) ) );
1202     }
1203 
1204     return p;
1205 }
1206 
1207 
1208 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1209