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