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