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