bump product version to 5.0.4.1
[LibreOffice.git] / ucb / source / core / ucbcmds.cxx
blobe0974e1d46d44a22556983fd89188174a136b2dd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <osl/diagnose.h>
21 #include <comphelper/processfactory.hxx>
22 #include <cppuhelper/implbase1.hxx>
23 #include <cppuhelper/exc_hlp.hxx>
24 #include <rtl/ustring.h>
25 #include <rtl/ustring.hxx>
26 #include <com/sun/star/uno/XInterface.hpp>
27 #include <com/sun/star/beans/PropertyState.hpp>
28 #include <com/sun/star/beans/PropertyValue.hpp>
29 #include <com/sun/star/container/XChild.hpp>
30 #include <com/sun/star/beans/XPropertySetInfo.hpp>
31 #include <com/sun/star/io/Pipe.hpp>
32 #include <com/sun/star/io/XActiveDataSink.hpp>
33 #include <com/sun/star/io/XOutputStream.hpp>
34 #include <com/sun/star/io/XSeekable.hpp>
35 #include <com/sun/star/sdbc/XRow.hpp>
36 #include <com/sun/star/task/XInteractionHandler.hpp>
37 #include <com/sun/star/ucb/CommandEnvironment.hpp>
38 #include <com/sun/star/ucb/CommandFailedException.hpp>
39 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
40 #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
41 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
42 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
43 #include <com/sun/star/ucb/NameClash.hpp>
44 #include <com/sun/star/ucb/NameClashException.hpp>
45 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
46 #include <com/sun/star/ucb/OpenMode.hpp>
47 #include <com/sun/star/ucb/TransferInfo2.hpp>
48 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
49 #include <com/sun/star/ucb/XCommandInfo.hpp>
50 #include <com/sun/star/ucb/XContentAccess.hpp>
51 #include <com/sun/star/ucb/XContentCreator.hpp>
52 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
53 #include <com/sun/star/ucb/XInteractionSupplyName.hpp>
54 #include <com/sun/star/uno/Any.hxx>
55 #include <com/sun/star/uno/Sequence.hxx>
56 #include <ucbhelper/cancelcommandexecution.hxx>
57 #include <ucbhelper/simplenameclashresolverequest.hxx>
58 #include "ucbcmds.hxx"
59 #include "ucb.hxx"
61 using namespace com::sun::star;
63 namespace
68 // struct TransferCommandContext.
72 struct TransferCommandContext
74 uno::Reference< uno::XComponentContext > m_xContext;
75 uno::Reference< ucb::XCommandProcessor > xProcessor;
76 uno::Reference< ucb::XCommandEnvironment > xEnv;
77 uno::Reference< ucb::XCommandEnvironment > xOrigEnv;
78 ucb::GlobalTransferCommandArgument2 aArg;
80 TransferCommandContext(
81 const uno::Reference< uno::XComponentContext > & xContext,
82 const uno::Reference< ucb::XCommandProcessor > & rxProcessor,
83 const uno::Reference< ucb::XCommandEnvironment > & rxEnv,
84 const uno::Reference< ucb::XCommandEnvironment > & rxOrigEnv,
85 const ucb::GlobalTransferCommandArgument2 & rArg )
86 : m_xContext( xContext ), xProcessor( rxProcessor ), xEnv( rxEnv ),
87 xOrigEnv( rxOrigEnv ), aArg( rArg ) {}
92 // class InteractionHandlerProxy.
96 class InteractionHandlerProxy :
97 public cppu::WeakImplHelper1< task::XInteractionHandler >
99 uno::Reference< task::XInteractionHandler > m_xOrig;
101 public:
102 InteractionHandlerProxy(
103 const uno::Reference< task::XInteractionHandler > & xOrig )
104 : m_xOrig( xOrig ) {}
106 // XInteractionHandler methods.
107 virtual void SAL_CALL handle(
108 const uno::Reference< task::XInteractionRequest >& Request )
109 throw ( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
113 // virtual
114 void SAL_CALL InteractionHandlerProxy::handle(
115 const uno::Reference< task::XInteractionRequest >& Request )
116 throw ( uno::RuntimeException, std::exception )
118 if ( !m_xOrig.is() )
119 return;
121 // Filter unwanted requests by just not handling them.
122 uno::Any aRequest = Request->getRequest();
124 // "transfer"
125 ucb::InteractiveBadTransferURLException aBadTransferURLEx;
126 if ( aRequest >>= aBadTransferURLEx )
128 return;
130 else
132 // "transfer"
133 ucb::UnsupportedNameClashException aUnsupportedNameClashEx;
134 if ( aRequest >>= aUnsupportedNameClashEx )
136 if ( aUnsupportedNameClashEx.NameClash
137 != ucb::NameClash::ERROR )
138 return;
140 else
142 // "insert"
143 ucb::NameClashException aNameClashEx;
144 if ( aRequest >>= aNameClashEx )
146 return;
148 else
150 // "transfer"
151 ucb::UnsupportedCommandException aUnsupportedCommandEx;
152 if ( aRequest >>= aUnsupportedCommandEx )
154 return;
160 // not filtered; let the original handler do the work.
161 m_xOrig->handle( Request );
166 // class ActiveDataSink.
170 class ActiveDataSink : public cppu::WeakImplHelper1< io::XActiveDataSink >
172 uno::Reference< io::XInputStream > m_xStream;
174 public:
175 // XActiveDataSink methods.
176 virtual void SAL_CALL setInputStream(
177 const uno::Reference< io::XInputStream >& aStream )
178 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
179 virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream()
180 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
184 // virtual
185 void SAL_CALL ActiveDataSink::setInputStream(
186 const uno::Reference< io::XInputStream >& aStream )
187 throw( uno::RuntimeException, std::exception )
189 m_xStream = aStream;
193 // virtual
194 uno::Reference< io::XInputStream > SAL_CALL ActiveDataSink::getInputStream()
195 throw( uno::RuntimeException, std::exception )
197 return m_xStream;
202 // class CommandProcessorInfo.
206 class CommandProcessorInfo :
207 public cppu::WeakImplHelper1< ucb::XCommandInfo >
209 uno::Sequence< ucb::CommandInfo > * m_pInfo;
211 public:
212 CommandProcessorInfo();
213 virtual ~CommandProcessorInfo();
215 // XCommandInfo methods
216 virtual uno::Sequence< ucb::CommandInfo > SAL_CALL getCommands()
217 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
218 virtual ucb::CommandInfo SAL_CALL
219 getCommandInfoByName( const OUString& Name )
220 throw( ucb::UnsupportedCommandException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
221 virtual ucb::CommandInfo SAL_CALL
222 getCommandInfoByHandle( sal_Int32 Handle )
223 throw( ucb::UnsupportedCommandException, uno::RuntimeException, std::exception ) SAL_OVERRIDE;
224 virtual sal_Bool SAL_CALL hasCommandByName( const OUString& Name )
225 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
226 virtual sal_Bool SAL_CALL hasCommandByHandle( sal_Int32 Handle )
227 throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
231 CommandProcessorInfo::CommandProcessorInfo()
233 m_pInfo = new uno::Sequence< ucb::CommandInfo >( 2 );
235 (*m_pInfo)[ 0 ]
236 = ucb::CommandInfo(
237 OUString( GETCOMMANDINFO_NAME ), // Name
238 GETCOMMANDINFO_HANDLE, // Handle
239 cppu::UnoType<void>::get() ); // ArgType
240 (*m_pInfo)[ 1 ]
241 = ucb::CommandInfo(
242 OUString( GLOBALTRANSFER_NAME ), // Name
243 GLOBALTRANSFER_HANDLE, // Handle
244 cppu::UnoType<ucb::GlobalTransferCommandArgument>::get() ); // ArgType
245 (*m_pInfo)[ 2 ]
246 = ucb::CommandInfo(
247 OUString( CHECKIN_NAME ), // Name
248 CHECKIN_HANDLE, // Handle
249 cppu::UnoType<ucb::CheckinArgument>::get() ); // ArgType
253 // virtual
254 CommandProcessorInfo::~CommandProcessorInfo()
256 delete m_pInfo;
260 // virtual
261 uno::Sequence< ucb::CommandInfo > SAL_CALL
262 CommandProcessorInfo::getCommands()
263 throw( uno::RuntimeException, std::exception )
265 return uno::Sequence< ucb::CommandInfo >( *m_pInfo );
269 // virtual
270 ucb::CommandInfo SAL_CALL
271 CommandProcessorInfo::getCommandInfoByName( const OUString& Name )
272 throw( ucb::UnsupportedCommandException, uno::RuntimeException, std::exception )
274 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
276 if ( (*m_pInfo)[ n ].Name == Name )
277 return ucb::CommandInfo( (*m_pInfo)[ n ] );
280 throw ucb::UnsupportedCommandException();
284 // virtual
285 ucb::CommandInfo SAL_CALL
286 CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle )
287 throw( ucb::UnsupportedCommandException, uno::RuntimeException, std::exception )
289 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
291 if ( (*m_pInfo)[ n ].Handle == Handle )
292 return ucb::CommandInfo( (*m_pInfo)[ n ] );
295 throw ucb::UnsupportedCommandException();
299 // virtual
300 sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByName(
301 const OUString& Name )
302 throw( uno::RuntimeException, std::exception )
304 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
306 if ( (*m_pInfo)[ n ].Name == Name )
307 return sal_True;
310 return sal_False;
314 // virtual
315 sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle )
316 throw( uno::RuntimeException, std::exception )
318 for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
320 if ( (*m_pInfo)[ n ].Handle == Handle )
321 return sal_True;
324 return sal_False;
331 OUString createDesiredName(
332 const OUString & rSourceURL, const OUString & rNewTitle )
334 OUString aName( rNewTitle );
335 if ( aName.isEmpty() )
337 // calculate name using source URL
339 // @@@ It's not guaranteed that slashes contained in the URL are
340 // actually path separators. This depends on the fact whether the
341 // URL is hierarchical. Only then the slashes are path separators.
342 // Therefore this algorithm is not guaranteed to work! But, ATM
343 // I don't know a better solution. It would have been better to
344 // have a member for the clashing name in
345 // UnsupportedNameClashException...
347 sal_Int32 nLastSlash = rSourceURL.lastIndexOf( '/' );
348 bool bTrailingSlash = false;
349 if ( nLastSlash == rSourceURL.getLength() - 1 )
351 nLastSlash = rSourceURL.lastIndexOf( '/', nLastSlash );
352 bTrailingSlash = true;
355 if ( nLastSlash != -1 )
357 if ( bTrailingSlash )
358 aName = rSourceURL.copy(
359 nLastSlash + 1,
360 rSourceURL.getLength() - nLastSlash - 2 );
361 else
362 aName = rSourceURL.copy( nLastSlash + 1 );
364 else
366 aName = rSourceURL;
369 // query, fragment present?
370 sal_Int32 nPos = aName.indexOf( '?' );
371 if ( nPos == -1 )
372 nPos = aName.indexOf( '#' );
374 if ( nPos != -1 )
375 aName = aName.copy( 0, nPos );
377 return OUString( aName );
380 OUString createDesiredName(
381 const ucb::GlobalTransferCommandArgument & rArg )
383 return createDesiredName( rArg.SourceURL, rArg.NewTitle );
386 OUString createDesiredName(
387 const ucb::TransferInfo & rArg )
389 return createDesiredName( rArg.SourceURL, rArg.NewTitle );
393 enum NameClashContinuation { NOT_HANDLED, ABORT, OVERWRITE, NEW_NAME, UNKNOWN };
395 NameClashContinuation interactiveNameClashResolve(
396 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
397 const OUString & rTargetURL,
398 const OUString & rClashingName,
399 /* [out] */ uno::Any & rException,
400 /* [out] */ OUString & rNewName )
402 rtl::Reference< ucbhelper::SimpleNameClashResolveRequest > xRequest(
403 new ucbhelper::SimpleNameClashResolveRequest(
404 rTargetURL, // target folder URL
405 rClashingName, // clashing name
406 OUString(), // no proposal for new name
407 true /* bSupportsOverwriteData */ ) );
409 rException = xRequest->getRequest();
410 if ( xEnv.is() )
412 uno::Reference< task::XInteractionHandler > xIH
413 = xEnv->getInteractionHandler();
414 if ( xIH.is() )
417 xIH->handle( xRequest.get() );
419 rtl::Reference< ucbhelper::InteractionContinuation >
420 xSelection( xRequest->getSelection() );
422 if ( xSelection.is() )
424 // Handler handled the request.
425 uno::Reference< task::XInteractionAbort > xAbort(
426 xSelection.get(), uno::UNO_QUERY );
427 if ( xAbort.is() )
429 // Abort.
430 return ABORT;
432 else
434 uno::Reference<
435 ucb::XInteractionReplaceExistingData >
436 xReplace(
437 xSelection.get(), uno::UNO_QUERY );
438 if ( xReplace.is() )
440 // Try again: Replace existing data.
441 return OVERWRITE;
443 else
445 uno::Reference<
446 ucb::XInteractionSupplyName >
447 xSupplyName(
448 xSelection.get(), uno::UNO_QUERY );
449 if ( xSupplyName.is() )
451 // Try again: Use new name.
452 rNewName = xRequest->getNewName();
453 return NEW_NAME;
455 else
457 OSL_FAIL( "Unknown interaction continuation!" );
458 return UNKNOWN;
465 return NOT_HANDLED;
469 bool setTitle(
470 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessor,
471 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
472 const OUString & rNewTitle )
473 throw( uno::RuntimeException )
477 uno::Sequence< beans::PropertyValue > aPropValues( 1 );
478 aPropValues[ 0 ].Name = "Title";
479 aPropValues[ 0 ].Handle = -1;
480 aPropValues[ 0 ].Value = uno::makeAny( rNewTitle );
482 ucb::Command aSetPropsCommand(
483 OUString( "setPropertyValues" ),
485 uno::makeAny( aPropValues ) );
487 uno::Any aResult
488 = xCommandProcessor->execute( aSetPropsCommand, 0, xEnv );
490 uno::Sequence< uno::Any > aErrors;
491 aResult >>= aErrors;
493 OSL_ENSURE( aErrors.getLength() == 1,
494 "getPropertyValues return value invalid!" );
496 if ( aErrors[ 0 ].hasValue() )
498 // error occurred.
499 OSL_FAIL( "error setting Title property!" );
500 return false;
503 catch ( uno::RuntimeException const & )
505 throw;
507 catch ( uno::Exception const & )
509 return false;
512 return true;
516 uno::Reference< ucb::XContent > createNew(
517 const TransferCommandContext & rContext,
518 const uno::Reference< ucb::XContent > & xTarget,
519 bool bSourceIsFolder,
520 bool bSourceIsDocument,
521 bool bSourceIsLink )
522 throw( uno::Exception )
526 // (1) Obtain creatable types from target.
530 // First, try it using "CreatabeleContentsInfo" property and
531 // "createNewContent" command -> the "new" way.
533 uno::Reference< ucb::XCommandProcessor > xCommandProcessorT(
534 xTarget, uno::UNO_QUERY );
535 if ( !xCommandProcessorT.is() )
537 uno::Any aProps
538 = uno::makeAny(beans::PropertyValue(
539 OUString( "Folder"),
541 uno::makeAny(rContext.aArg.TargetURL),
542 beans::PropertyState_DIRECT_VALUE));
543 ucbhelper::cancelCommandExecution(
544 ucb::IOErrorCode_CANT_CREATE,
545 uno::Sequence< uno::Any >(&aProps, 1),
546 rContext.xOrigEnv,
547 OUString("Target is no XCommandProcessor!"),
548 rContext.xProcessor );
549 // Unreachable
552 uno::Sequence< beans::Property > aPropsToObtain( 1 );
553 aPropsToObtain[ 0 ].Name = "CreatableContentsInfo";
554 aPropsToObtain[ 0 ].Handle = -1;
556 ucb::Command aGetPropsCommand(
557 OUString("getPropertyValues"),
559 uno::makeAny( aPropsToObtain ) );
561 uno::Reference< sdbc::XRow > xRow;
562 xCommandProcessorT->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
564 uno::Sequence< ucb::ContentInfo > aTypesInfo;
565 bool bGotTypesInfo = false;
567 if ( xRow.is() )
569 uno::Any aValue = xRow->getObject(
570 1, uno::Reference< container::XNameAccess >() );
571 if ( aValue.hasValue() && ( aValue >>= aTypesInfo ) )
573 bGotTypesInfo = true;
577 uno::Reference< ucb::XContentCreator > xCreator;
579 if ( !bGotTypesInfo )
581 // Second, try it using XContentCreator interface -> the "old" way (not
582 // providing the chance to supply an XCommandEnvironment.
584 xCreator.set( xTarget, uno::UNO_QUERY );
586 if ( !xCreator.is() )
588 uno::Any aProps
589 = uno::makeAny(beans::PropertyValue(
590 OUString( "Folder"),
592 uno::makeAny(rContext.aArg.TargetURL),
593 beans::PropertyState_DIRECT_VALUE));
594 ucbhelper::cancelCommandExecution(
595 ucb::IOErrorCode_CANT_CREATE,
596 uno::Sequence< uno::Any >(&aProps, 1),
597 rContext.xOrigEnv,
598 OUString("Target is no XContentCreator!"),
599 rContext.xProcessor );
600 // Unreachable
603 aTypesInfo = xCreator->queryCreatableContentsInfo();
606 sal_Int32 nCount = aTypesInfo.getLength();
607 if ( !nCount )
609 uno::Any aProps
610 = uno::makeAny(beans::PropertyValue(
611 OUString("Folder"),
613 uno::makeAny(rContext.aArg.TargetURL),
614 beans::PropertyState_DIRECT_VALUE));
615 ucbhelper::cancelCommandExecution(
616 ucb::IOErrorCode_CANT_CREATE,
617 uno::Sequence< uno::Any >(&aProps, 1),
618 rContext.xOrigEnv,
619 OUString("No types creatable!"),
620 rContext.xProcessor );
621 // Unreachable
626 // (2) Try to find a matching target type for the source object.
630 uno::Reference< ucb::XContent > xNew;
631 for ( sal_Int32 n = 0; n < nCount; ++n )
633 sal_Int32 nAttribs = aTypesInfo[ n ].Attributes;
634 bool bMatch = false;
636 if ( rContext.aArg.Operation == ucb::TransferCommandOperation_LINK )
638 // Create link
640 if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
642 // Match!
643 bMatch = true;
646 else if ( ( rContext.aArg.Operation
647 == ucb::TransferCommandOperation_COPY ) ||
648 ( rContext.aArg.Operation
649 == ucb::TransferCommandOperation_MOVE ) )
651 // Copy / Move
653 // Is source a link? Create link in target folder then.
654 if ( bSourceIsLink )
656 if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
658 // Match!
659 bMatch = true;
662 else
664 // (not a and not b) or (a and b)
665 // not( a or b) or (a and b)
667 if ( ( !!bSourceIsFolder ==
668 !!( nAttribs
669 & ucb::ContentInfoAttribute::KIND_FOLDER ) )
671 ( !!bSourceIsDocument ==
672 !!( nAttribs
673 & ucb::ContentInfoAttribute::KIND_DOCUMENT ) )
676 // Match!
677 bMatch = true;
681 else
683 ucbhelper::cancelCommandExecution(
684 uno::makeAny( lang::IllegalArgumentException(
685 OUString( "Unknown transfer operation!" ),
686 rContext.xProcessor,
687 -1 ) ),
688 rContext.xOrigEnv );
689 // Unreachable
692 if ( bMatch )
696 // (3) Create a new, empty object of matched type.
700 if ( !xCreator.is() )
702 // First, try it using "CreatabeleContentsInfo" property and
703 // "createNewContent" command -> the "new" way.
704 ucb::Command aCreateNewCommand(
705 OUString("createNewContent"),
707 uno::makeAny( aTypesInfo[ n ] ) );
709 xCommandProcessorT->execute( aCreateNewCommand, 0, rContext.xEnv )
710 >>= xNew;
712 else
714 // Second, try it using XContentCreator interface -> the "old"
715 // way (not providing the chance to supply an XCommandEnvironment.
717 xNew = xCreator->createNewContent( aTypesInfo[ n ] );
720 if ( !xNew.is() )
722 uno::Any aProps
723 = uno::makeAny(
724 beans::PropertyValue(
725 OUString( "Folder"),
727 uno::makeAny(rContext.aArg.TargetURL),
728 beans::PropertyState_DIRECT_VALUE));
729 ucbhelper::cancelCommandExecution(
730 ucb::IOErrorCode_CANT_CREATE,
731 uno::Sequence< uno::Any >(&aProps, 1),
732 rContext.xOrigEnv,
733 OUString( "createNewContent failed!" ),
734 rContext.xProcessor );
735 // Unreachable
737 break; // escape from 'for' loop
739 } // for
741 return xNew;
745 void transferProperties(
746 const TransferCommandContext & rContext,
747 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS,
748 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorN )
749 throw( uno::Exception )
751 ucb::Command aGetPropertySetInfoCommand(
752 OUString("getPropertySetInfo"),
754 uno::Any() );
756 uno::Reference< beans::XPropertySetInfo > xInfo;
757 xCommandProcessorS->execute( aGetPropertySetInfoCommand, 0, rContext.xEnv )
758 >>= xInfo;
760 if ( !xInfo.is() )
762 uno::Any aProps
763 = uno::makeAny(beans::PropertyValue(
764 OUString( "Uri"),
766 uno::makeAny(rContext.aArg.SourceURL),
767 beans::PropertyState_DIRECT_VALUE));
768 ucbhelper::cancelCommandExecution(
769 ucb::IOErrorCode_CANT_READ,
770 uno::Sequence< uno::Any >(&aProps, 1),
771 rContext.xOrigEnv,
772 OUString( "Unable to get propertyset info from source object!" ),
773 rContext.xProcessor );
774 // Unreachable
777 uno::Sequence< beans::Property > aAllProps = xInfo->getProperties();
779 ucb::Command aGetPropsCommand1(
780 OUString("getPropertyValues"),
782 uno::makeAny( aAllProps ) );
784 uno::Reference< sdbc::XRow > xRow1;
785 xCommandProcessorS->execute(
786 aGetPropsCommand1, 0, rContext.xEnv ) >>= xRow1;
788 if ( !xRow1.is() )
790 uno::Any aProps
791 = uno::makeAny(beans::PropertyValue(
792 OUString( "Uri"),
794 uno::makeAny(rContext.aArg.SourceURL),
795 beans::PropertyState_DIRECT_VALUE));
796 ucbhelper::cancelCommandExecution(
797 ucb::IOErrorCode_CANT_READ,
798 uno::Sequence< uno::Any >(&aProps, 1),
799 rContext.xOrigEnv,
800 OUString( "Unable to get properties from source object!" ),
801 rContext.xProcessor );
802 // Unreachable
805 // Assemble data structure for setPropertyValues command.
807 // Note: Make room for additional Title and TargetURL too. -> + 2
808 uno::Sequence< beans::PropertyValue > aPropValues(
809 aAllProps.getLength() + 2 );
811 bool bHasTitle = rContext.aArg.NewTitle.isEmpty();
812 bool bHasTargetURL = ( rContext.aArg.Operation
813 != ucb::TransferCommandOperation_LINK );
815 sal_Int32 nWritePos = 0;
816 for ( sal_Int32 m = 0; m < aAllProps.getLength(); ++m )
818 const beans::Property & rCurrProp = aAllProps[ m ];
819 beans::PropertyValue & rCurrValue = aPropValues[ nWritePos ];
821 uno::Any aValue;
823 if ( rCurrProp.Name == "Title" )
825 // Supply new title, if given.
826 if ( !bHasTitle )
828 bHasTitle = true;
829 aValue <<= rContext.aArg.NewTitle;
832 else if ( rCurrProp.Name == "TargetURL" )
834 // Supply source URL as link target for the new link to create.
835 if ( !bHasTargetURL )
837 bHasTargetURL = true;
838 aValue <<= rContext.aArg.SourceURL;
842 if ( !aValue.hasValue() )
846 aValue = xRow1->getObject(
847 m + 1, uno::Reference< container::XNameAccess >() );
849 catch ( sdbc::SQLException const & )
851 // Argh! But try to bring things to an end. Perhaps the
852 // mad property is not really important...
856 if ( aValue.hasValue() )
858 rCurrValue.Name = rCurrProp.Name;
859 rCurrValue.Handle = rCurrProp.Handle;
860 rCurrValue.Value = aValue;
861 // rCurrValue.State =
863 nWritePos++;
867 // Title needed, but not set yet?
868 if ( !bHasTitle && !rContext.aArg.NewTitle.isEmpty() )
870 aPropValues[ nWritePos ].Name = "Title";
871 aPropValues[ nWritePos ].Handle = -1;
872 aPropValues[ nWritePos ].Value <<= rContext.aArg.NewTitle;
874 nWritePos++;
877 // TargetURL needed, but not set yet?
878 if ( !bHasTargetURL && ( rContext.aArg.Operation
879 == ucb::TransferCommandOperation_LINK ) )
881 aPropValues[ nWritePos ].Name = "TargetURL";
882 aPropValues[ nWritePos ].Handle = -1;
883 aPropValues[ nWritePos ].Value <<= rContext.aArg.SourceURL;
885 nWritePos++;
888 aPropValues.realloc( nWritePos );
890 // Set properties at new object.
892 ucb::Command aSetPropsCommand(
893 OUString("setPropertyValues"),
895 uno::makeAny( aPropValues ) );
897 xCommandProcessorN->execute( aSetPropsCommand, 0, rContext.xEnv );
899 // @@@ What to do with source props that are not supported by the
900 // new object? addProperty ???
904 uno::Reference< io::XInputStream > getInputStream(
905 const TransferCommandContext & rContext,
906 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
907 throw( uno::Exception )
909 uno::Reference< io::XInputStream > xInputStream;
913 // (1) Try to get data as XInputStream via XActiveDataSink.
919 uno::Reference< io::XActiveDataSink > xSink = new ActiveDataSink;
921 ucb::OpenCommandArgument2 aArg;
922 aArg.Mode = ucb::OpenMode::DOCUMENT;
923 aArg.Priority = 0; // unused
924 aArg.Sink = xSink;
925 aArg.Properties = uno::Sequence< beans::Property >( 0 ); // unused
927 ucb::Command aOpenCommand(
928 OUString("open"),
930 uno::makeAny( aArg ) );
932 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
933 xInputStream = xSink->getInputStream();
935 catch ( uno::RuntimeException const & )
937 throw;
939 catch ( uno::Exception const & )
941 // will be handled below.
944 if ( !xInputStream.is() )
948 // (2) Try to get data via XOutputStream.
954 uno::Reference< io::XOutputStream > xOutputStream( io::Pipe::create(rContext.m_xContext), uno::UNO_QUERY_THROW );
956 ucb::OpenCommandArgument2 aArg;
957 aArg.Mode = ucb::OpenMode::DOCUMENT;
958 aArg.Priority = 0; // unused
959 aArg.Sink = xOutputStream;
960 aArg.Properties = uno::Sequence< beans::Property >( 0 );
962 ucb::Command aOpenCommand(
963 OUString("open"),
965 uno::makeAny( aArg ) );
967 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
969 xInputStream = uno::Reference< io::XInputStream >(
970 xOutputStream, uno::UNO_QUERY );
972 catch ( uno::RuntimeException const & )
974 throw;
976 catch ( uno::Exception const & )
978 OSL_FAIL( "unable to get input stream from document!" );
982 return xInputStream;
986 uno::Reference< sdbc::XResultSet > getResultSet(
987 const TransferCommandContext & rContext,
988 const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
989 throw( uno::Exception )
991 uno::Reference< sdbc::XResultSet > xResultSet;
993 uno::Sequence< beans::Property > aProps( 3 );
995 aProps[ 0 ].Name = "IsFolder";
996 aProps[ 0 ].Handle = -1; /* unknown */
997 aProps[ 1 ].Name = "IsDocument";
998 aProps[ 1 ].Handle = -1; /* unknown */
999 aProps[ 2 ].Name = "TargetURL";
1000 aProps[ 2 ].Handle = -1; /* unknown */
1002 ucb::OpenCommandArgument2 aArg;
1003 aArg.Mode = ucb::OpenMode::ALL;
1004 aArg.Priority = 0; // unused
1005 aArg.Sink = 0;
1006 aArg.Properties = aProps;
1008 ucb::Command aOpenCommand( OUString("open"),
1010 uno::makeAny( aArg ) );
1013 uno::Reference< ucb::XDynamicResultSet > xSet;
1014 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv ) >>= xSet;
1016 if ( xSet.is() )
1017 xResultSet = xSet->getStaticResultSet();
1019 catch ( uno::RuntimeException const & )
1021 throw;
1023 catch ( uno::Exception const & )
1025 OSL_FAIL( "unable to get result set from folder!" );
1028 return xResultSet;
1032 void handleNameClashRename(
1033 const TransferCommandContext & rContext,
1034 const uno::Reference< ucb::XContent > & xNew,
1035 const uno::Reference<
1036 ucb::XCommandProcessor > & xCommandProcessorN,
1037 const uno::Reference<
1038 ucb::XCommandProcessor > & xCommandProcessorS,
1039 /* [inout] */ uno::Reference< io::XInputStream > & xInputStream )
1040 throw( uno::Exception )
1042 sal_Int32 nTry = 0;
1044 // Obtain old title.
1045 uno::Sequence< beans::Property > aProps( 1 );
1046 aProps[ 0 ].Name = "Title";
1047 aProps[ 0 ].Handle = -1;
1049 ucb::Command aGetPropsCommand(
1050 OUString("getPropertyValues"),
1052 uno::makeAny( aProps ) );
1054 uno::Reference< sdbc::XRow > xRow;
1055 xCommandProcessorN->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
1057 if ( !xRow.is() )
1059 uno::Any aProps2
1060 = uno::makeAny(
1061 beans::PropertyValue(
1062 OUString( "Uri" ),
1064 uno::makeAny(
1065 xNew->getIdentifier()->getContentIdentifier() ),
1066 beans::PropertyState_DIRECT_VALUE ) );
1067 ucbhelper::cancelCommandExecution(
1068 ucb::IOErrorCode_CANT_READ,
1069 uno::Sequence< uno::Any >( &aProps2, 1 ),
1070 rContext.xOrigEnv,
1071 OUString( "Unable to get properties from new object!" ),
1072 rContext.xProcessor );
1073 // Unreachable
1076 OUString aOldTitle = xRow->getString( 1 );
1077 if ( aOldTitle.isEmpty() )
1079 ucbhelper::cancelCommandExecution(
1080 uno::makeAny( beans::UnknownPropertyException(
1081 OUString( "Unable to get property 'Title' from new object!" ),
1082 rContext.xProcessor ) ),
1083 rContext.xOrigEnv );
1084 // Unreachable
1087 // Some pseudo-intelligence for not destroying file extensions.
1088 OUString aOldTitlePre;
1089 OUString aOldTitlePost;
1090 sal_Int32 nPos = aOldTitle.lastIndexOf( '.' );
1091 if ( nPos != -1 )
1093 aOldTitlePre = aOldTitle.copy( 0, nPos );
1094 aOldTitlePost = aOldTitle.copy( nPos );
1096 else
1097 aOldTitlePre = aOldTitle;
1099 if ( nPos > 0 )
1100 aOldTitlePre += "_";
1102 bool bContinue = true;
1105 nTry++;
1107 OUString aNewTitle = aOldTitlePre;
1108 aNewTitle += OUString::number( nTry );
1109 aNewTitle += aOldTitlePost;
1111 // Set new title
1112 setTitle( xCommandProcessorN, rContext.xEnv, aNewTitle );
1114 // Retry inserting the content.
1117 // Previous try may have read from stream. Seek to begin (if
1118 // optional interface XSeekable is supported) or get a new stream.
1119 if ( xInputStream.is() )
1121 uno::Reference< io::XSeekable > xSeekable(
1122 xInputStream, uno::UNO_QUERY );
1123 if ( xSeekable.is() )
1127 xSeekable->seek( 0 );
1129 catch ( lang::IllegalArgumentException const & )
1131 xInputStream.clear();
1133 catch ( io::IOException const & )
1135 xInputStream.clear();
1138 else
1139 xInputStream.clear();
1141 if ( !xInputStream.is() )
1143 xInputStream
1144 = getInputStream( rContext, xCommandProcessorS );
1145 if ( !xInputStream.is() )
1147 uno::Any aProps2
1148 = uno::makeAny(
1149 beans::PropertyValue(
1150 OUString( "Uri" ),
1152 uno::makeAny(
1153 xNew->getIdentifier()->
1154 getContentIdentifier() ),
1155 beans::PropertyState_DIRECT_VALUE ) );
1156 ucbhelper::cancelCommandExecution(
1157 ucb::IOErrorCode_CANT_READ,
1158 uno::Sequence< uno::Any >( &aProps2, 1 ),
1159 rContext.xOrigEnv,
1160 OUString( "Got no data stream from source!" ),
1161 rContext.xProcessor );
1162 // Unreachable
1167 ucb::InsertCommandArgument2 aArg;
1168 aArg.Data = xInputStream;
1169 aArg.ReplaceExisting = sal_False;
1171 ucb::Command aInsertCommand(
1172 OUString("insert"),
1174 uno::makeAny( aArg ) );
1176 xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
1178 // Success!
1179 bContinue = false;
1181 catch ( uno::RuntimeException const & )
1183 throw;
1185 catch ( uno::Exception const & )
1189 while ( bContinue && ( nTry < 50 ) );
1191 if ( nTry == 50 )
1193 ucbhelper::cancelCommandExecution(
1194 uno::makeAny(
1195 ucb::UnsupportedNameClashException(
1196 OUString( "Unable to resolve name clash!" ),
1197 rContext.xProcessor,
1198 ucb::NameClash::RENAME ) ),
1199 rContext.xOrigEnv );
1200 // Unreachable
1205 void globalTransfer_(
1206 const TransferCommandContext & rContext,
1207 const uno::Reference< ucb::XContent > & xSource,
1208 const uno::Reference< ucb::XContent > & xTarget,
1209 const uno::Reference< sdbc::XRow > & xSourceProps )
1210 throw( uno::Exception )
1212 // IsFolder: property is required.
1213 bool bSourceIsFolder = xSourceProps->getBoolean( 1 );
1214 if ( !bSourceIsFolder && xSourceProps->wasNull() )
1216 ucbhelper::cancelCommandExecution(
1217 uno::makeAny( beans::UnknownPropertyException(
1218 OUString( "Unable to get property 'IsFolder' "
1219 "from source object!" ),
1220 rContext.xProcessor ) ),
1221 rContext.xOrigEnv );
1222 // Unreachable
1225 // IsDocument: property is required.
1226 bool bSourceIsDocument = xSourceProps->getBoolean( 2 );
1227 if ( !bSourceIsDocument && xSourceProps->wasNull() )
1229 ucbhelper::cancelCommandExecution(
1230 uno::makeAny( beans::UnknownPropertyException(
1231 OUString( "Unable to get property 'IsDocument' "
1232 "from source object!" ),
1233 rContext.xProcessor ) ),
1234 rContext.xOrigEnv );
1235 // Unreachable
1238 // TargetURL: property is optional.
1239 bool bSourceIsLink = !xSourceProps->getString( 3 ).isEmpty();
1243 // (1) Try to find a matching target type for the source object and
1244 // create a new, empty object of that type.
1248 uno::Reference< ucb::XContent > xNew = createNew( rContext,
1249 xTarget,
1250 bSourceIsFolder,
1251 bSourceIsDocument,
1252 bSourceIsLink );
1253 if ( !xNew.is() )
1255 uno::Any aProps
1256 = uno::makeAny(beans::PropertyValue(
1257 OUString( "Folder"),
1259 uno::makeAny(rContext.aArg.TargetURL),
1260 beans::PropertyState_DIRECT_VALUE));
1261 ucbhelper::cancelCommandExecution(
1262 ucb::IOErrorCode_CANT_CREATE,
1263 uno::Sequence< uno::Any >(&aProps, 1),
1264 rContext.xOrigEnv,
1265 OUString( "No matching content type at target!" ),
1266 rContext.xProcessor );
1267 // Unreachable
1272 // (2) Transfer property values from source to new object.
1276 uno::Reference< ucb::XCommandProcessor > xCommandProcessorN(
1277 xNew, uno::UNO_QUERY );
1278 if ( !xCommandProcessorN.is() )
1280 uno::Any aProps
1281 = uno::makeAny(beans::PropertyValue(
1282 OUString( "Uri"),
1284 uno::makeAny(
1285 xNew->getIdentifier()->
1286 getContentIdentifier()),
1287 beans::PropertyState_DIRECT_VALUE));
1288 ucbhelper::cancelCommandExecution(
1289 ucb::IOErrorCode_CANT_WRITE,
1290 uno::Sequence< uno::Any >(&aProps, 1),
1291 rContext.xOrigEnv,
1292 OUString( "New content is not a XCommandProcessor!" ),
1293 rContext.xProcessor );
1294 // Unreachable
1297 // Obtain all properties from source.
1299 uno::Reference< ucb::XCommandProcessor > xCommandProcessorS(
1300 xSource, uno::UNO_QUERY );
1301 if ( !xCommandProcessorS.is() )
1303 uno::Any aProps
1304 = uno::makeAny(beans::PropertyValue(
1305 OUString( "Uri"),
1307 uno::makeAny(rContext.aArg.SourceURL),
1308 beans::PropertyState_DIRECT_VALUE));
1309 ucbhelper::cancelCommandExecution(
1310 ucb::IOErrorCode_CANT_READ,
1311 uno::Sequence< uno::Any >(&aProps, 1),
1312 rContext.xOrigEnv,
1313 OUString( "Source content is not a XCommandProcessor!" ),
1314 rContext.xProcessor );
1315 // Unreachable
1318 transferProperties( rContext, xCommandProcessorS, xCommandProcessorN );
1322 // (3) Try to obtain a data stream from source.
1326 uno::Reference< io::XInputStream > xInputStream;
1328 if ( bSourceIsDocument && ( rContext.aArg.Operation
1329 != ucb::TransferCommandOperation_LINK ) )
1330 xInputStream = getInputStream( rContext, xCommandProcessorS );
1334 // (4) Try to obtain a resultset (children) from source.
1338 uno::Reference< sdbc::XResultSet > xResultSet;
1340 if ( bSourceIsFolder && ( rContext.aArg.Operation
1341 != ucb::TransferCommandOperation_LINK ) )
1342 xResultSet = getResultSet( rContext, xCommandProcessorS );
1346 // (5) Insert (store) new content.
1350 ucb::InsertCommandArgument2 aArg;
1351 aArg.Data = xInputStream;
1352 aArg.MimeType = rContext.aArg.MimeType;
1353 aArg.DocumentId = rContext.aArg.DocumentId;
1355 switch ( rContext.aArg.NameClash )
1357 case ucb::NameClash::OVERWRITE:
1358 aArg.ReplaceExisting = sal_True;
1359 break;
1361 case ucb::NameClash::ERROR:
1362 case ucb::NameClash::RENAME:
1363 case ucb::NameClash::KEEP: // deprecated
1364 case ucb::NameClash::ASK:
1365 aArg.ReplaceExisting = sal_False;
1366 break;
1368 default:
1369 aArg.ReplaceExisting = sal_False;
1370 OSL_FAIL( "Unknown nameclash directive!" );
1371 break;
1374 OUString aDesiredName = createDesiredName( rContext.aArg );
1376 bool bRetry;
1379 bRetry = false;
1383 ucb::Command aInsertCommand(
1384 OUString("insert"),
1386 uno::makeAny( aArg ) );
1388 xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
1390 catch ( ucb::UnsupportedNameClashException const & exc )
1392 OSL_ENSURE( !aArg.ReplaceExisting,
1393 "BUG: UnsupportedNameClashException not allowed here!" );
1395 if (exc.NameClash != ucb::NameClash::ERROR) {
1396 OSL_FAIL( "BUG: NameClash::ERROR expected!" );
1399 // No chance to solve name clashes, because I'm not able to detect
1400 // whether there is one.
1401 throw ucb::UnsupportedNameClashException(
1402 OUString(
1403 "Unable to resolve name clashes, no chance to detect "
1404 "that there is one!" ),
1405 rContext.xProcessor,
1406 rContext.aArg.NameClash );
1408 catch ( ucb::NameClashException const & )
1410 // The 'insert' command throws a NameClashException if the parameter
1411 // ReplaceExisting of the command's argument was set to false and
1412 // there exists a resource with a clashing name in the target folder
1413 // of the operation.
1415 // 'insert' command has no direct support for name clashes other
1416 // than ERROR ( ReplaceExisting == false ) and OVERWRITE
1417 // ( ReplaceExisting == true ). So we have to implement the
1418 // other name clash handling directives on top of the content.
1420 // @@@ 'insert' command should be extended that it accepts a
1421 // name clash handling directive, exactly like 'transfer' command.
1423 switch ( rContext.aArg.NameClash )
1425 case ucb::NameClash::OVERWRITE:
1427 ucbhelper::cancelCommandExecution(
1428 uno::makeAny(
1429 ucb::UnsupportedNameClashException(
1430 OUString(
1431 "BUG: insert + replace == true MUST NOT "
1432 "throw NameClashException." ),
1433 rContext.xProcessor,
1434 rContext.aArg.NameClash ) ),
1435 rContext.xOrigEnv );
1436 // Unreachable
1439 case ucb::NameClash::ERROR:
1440 throw;
1442 case ucb::NameClash::RENAME:
1444 // "invent" a new valid title.
1445 handleNameClashRename( rContext,
1446 xNew,
1447 xCommandProcessorN,
1448 xCommandProcessorS,
1449 xInputStream );
1450 break;
1453 case ucb::NameClash::ASK:
1455 uno::Any aExc;
1456 OUString aNewTitle;
1457 NameClashContinuation eCont
1458 = interactiveNameClashResolve(
1459 rContext.xOrigEnv, // always use original environment!
1460 rContext.aArg.TargetURL, // target folder URL
1461 aDesiredName,
1462 aExc,
1463 aNewTitle );
1465 switch ( eCont )
1467 case NOT_HANDLED:
1468 // Not handled.
1469 cppu::throwException( aExc );
1470 // break;
1472 case UNKNOWN:
1473 // Handled, but not clear, how...
1474 // fall through intended.
1476 case ABORT:
1477 throw ucb::CommandFailedException(
1478 OUString(
1479 "abort requested via interaction "
1480 "handler" ),
1481 uno::Reference< uno::XInterface >(),
1482 aExc );
1483 // break;
1485 case OVERWRITE:
1486 OSL_ENSURE( aArg.ReplaceExisting == sal_False,
1487 "Hu? ReplaceExisting already true?"
1489 aArg.ReplaceExisting = sal_True;
1490 bRetry = true;
1491 break;
1493 case NEW_NAME:
1495 // set new name -> set "Title" property...
1496 if ( setTitle( xCommandProcessorN,
1497 rContext.xEnv,
1498 aNewTitle ) )
1500 // remember suggested title...
1501 aDesiredName = aNewTitle;
1503 // ... and try again.
1504 bRetry = true;
1506 else
1508 // error setting title. Abort.
1509 throw ucb::CommandFailedException(
1510 OUString( "error setting Title property!" ),
1511 uno::Reference< uno::XInterface >(),
1512 aExc );
1514 break;
1518 OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
1520 break;
1522 case ucb::NameClash::KEEP: // deprecated
1523 default:
1525 ucbhelper::cancelCommandExecution(
1526 uno::makeAny(
1527 ucb::UnsupportedNameClashException(
1528 OUString(
1529 "default action, don't know how to "
1530 "handle name clash" ),
1531 rContext.xProcessor,
1532 rContext.aArg.NameClash ) ),
1533 rContext.xOrigEnv );
1534 // Unreachable
1539 while ( bRetry );
1543 // (6) Process children of source.
1547 if ( xResultSet.is() )
1551 // Iterate over children...
1553 uno::Reference< sdbc::XRow > xChildRow(
1554 xResultSet, uno::UNO_QUERY );
1556 if ( !xChildRow.is() )
1558 uno::Any aProps
1559 = uno::makeAny(
1560 beans::PropertyValue(
1561 OUString( "Uri"),
1563 uno::makeAny(rContext.aArg.SourceURL),
1564 beans::PropertyState_DIRECT_VALUE));
1565 ucbhelper::cancelCommandExecution(
1566 ucb::IOErrorCode_CANT_READ,
1567 uno::Sequence< uno::Any >(&aProps, 1),
1568 rContext.xOrigEnv,
1569 OUString( "Unable to get properties from children of source!" ),
1570 rContext.xProcessor );
1571 // Unreachable
1574 uno::Reference< ucb::XContentAccess > xChildAccess(
1575 xResultSet, uno::UNO_QUERY );
1577 if ( !xChildAccess.is() )
1579 uno::Any aProps
1580 = uno::makeAny(
1581 beans::PropertyValue(
1582 OUString( "Uri"),
1584 uno::makeAny(rContext.aArg.SourceURL),
1585 beans::PropertyState_DIRECT_VALUE));
1586 ucbhelper::cancelCommandExecution(
1587 ucb::IOErrorCode_CANT_READ,
1588 uno::Sequence< uno::Any >(&aProps, 1),
1589 rContext.xOrigEnv,
1590 OUString( "Unable to get children of source!" ),
1591 rContext.xProcessor );
1592 // Unreachable
1595 if ( xResultSet->first() )
1597 ucb::GlobalTransferCommandArgument2 aTransArg(
1598 rContext.aArg.Operation,
1599 OUString(), // SourceURL; filled later
1600 xNew->getIdentifier()
1601 ->getContentIdentifier(), // TargetURL
1602 OUString(), // NewTitle;
1603 rContext.aArg.NameClash,
1604 rContext.aArg.MimeType,
1605 rContext.aArg.DocumentId);
1607 TransferCommandContext aSubCtx(
1608 rContext.m_xContext,
1609 rContext.xProcessor,
1610 rContext.xEnv,
1611 rContext.xOrigEnv,
1612 aTransArg );
1615 uno::Reference< ucb::XContent > xChild
1616 = xChildAccess->queryContent();
1617 if ( xChild.is() )
1619 // Recursion!
1621 aSubCtx.aArg.SourceURL
1622 = xChild->getIdentifier()->getContentIdentifier();
1624 globalTransfer_( aSubCtx,
1625 xChild,
1626 xNew,
1627 xChildRow );
1630 while ( xResultSet->next() );
1633 catch ( sdbc::SQLException const & )
1638 try {
1639 uno::Reference< ucb::XCommandProcessor > xcp(
1640 xTarget, uno::UNO_QUERY );
1642 uno::Any aAny;
1643 uno::Reference< ucb::XCommandInfo > xci;
1644 if(xcp.is())
1645 aAny =
1646 xcp->execute(
1647 ucb::Command(
1648 OUString("getCommandInfo"),
1650 uno::Any()),
1652 rContext.xEnv );
1654 const OUString cmdName("flush");
1655 if((aAny >>= xci) && xci->hasCommandByName(cmdName))
1656 xcp->execute(
1657 ucb::Command(
1658 cmdName,
1660 uno::Any()) ,
1662 rContext.xEnv );
1664 catch( uno::Exception const & )
1669 } /* namescpace */
1673 // UniversalContentBroker implementation ( XCommandProcessor commands ).
1677 uno::Reference< ucb::XCommandInfo >
1678 UniversalContentBroker::getCommandInfo()
1680 return uno::Reference< ucb::XCommandInfo >( new CommandProcessorInfo() );
1684 void UniversalContentBroker::globalTransfer(
1685 const ucb::GlobalTransferCommandArgument2 & rArg,
1686 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1687 throw( uno::Exception )
1689 // Use own command environment with own interaction handler intercepting
1690 // some interaction requests that shall not be handled by the user-supplied
1691 // interaction handler.
1692 uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
1693 if (xEnv.is())
1695 xLocalEnv.set( ucb::CommandEnvironment::create(
1696 m_xContext,
1697 new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
1698 xEnv->getProgressHandler() ) );
1703 // (1) Try to transfer the content using 'transfer' command.
1707 uno::Reference< ucb::XContent > xTarget;
1708 uno::Reference< ucb::XContentIdentifier > xId
1709 = createContentIdentifier( rArg.TargetURL );
1710 if ( xId.is() )
1714 xTarget = queryContent( xId );
1716 catch ( ucb::IllegalIdentifierException const & )
1721 if ( !xTarget.is() )
1723 uno::Any aProps
1724 = uno::makeAny(beans::PropertyValue(
1725 OUString( "Uri"),
1727 uno::makeAny(rArg.TargetURL),
1728 beans::PropertyState_DIRECT_VALUE));
1729 ucbhelper::cancelCommandExecution(
1730 ucb::IOErrorCode_CANT_READ,
1731 uno::Sequence< uno::Any >(&aProps, 1),
1732 xEnv,
1733 OUString( "Can't instanciate target object!" ),
1734 this );
1735 // Unreachable
1738 if ( ( rArg.Operation == ucb::TransferCommandOperation_COPY ) ||
1739 ( rArg.Operation == ucb::TransferCommandOperation_MOVE ) )
1741 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
1742 xTarget, uno::UNO_QUERY );
1743 if ( !xCommandProcessor.is() )
1745 uno::Any aProps
1746 = uno::makeAny(
1747 beans::PropertyValue(
1748 OUString( "Uri"),
1750 uno::makeAny(rArg.TargetURL),
1751 beans::PropertyState_DIRECT_VALUE));
1752 ucbhelper::cancelCommandExecution(
1753 ucb::IOErrorCode_CANT_READ,
1754 uno::Sequence< uno::Any >(&aProps, 1),
1755 xEnv,
1756 OUString( "Target content is not a XCommandProcessor!" ),
1757 this );
1758 // Unreachable
1761 ucb::TransferInfo2 aTransferArg(
1762 ( rArg.Operation
1763 == ucb::TransferCommandOperation_MOVE ), // MoveData
1764 rArg.SourceURL,
1765 rArg.NewTitle,
1766 rArg.NameClash,
1767 rArg.MimeType );
1769 bool bRetry;
1772 bRetry = false;
1776 ucb::Command aCommand(
1777 OUString( "transfer" ), // Name
1778 -1, // Handle
1779 uno::makeAny( aTransferArg ) ); // Argument
1781 xCommandProcessor->execute( aCommand, 0, xLocalEnv );
1783 // Command succeeded. We're done.
1784 return;
1786 catch ( ucb::InteractiveBadTransferURLException const & )
1788 // Source URL is not supported by target. Try to transfer
1789 // the content "manually".
1791 catch ( ucb::UnsupportedCommandException const & )
1793 // 'transfer' command is not supported by commandprocessor.
1794 // Try to transfer manually.
1796 catch ( ucb::UnsupportedNameClashException const & exc )
1798 OSL_ENSURE( aTransferArg.NameClash == exc.NameClash,
1799 "nameclash mismatch!" );
1800 if ( exc.NameClash == ucb::NameClash::ASK )
1802 // Try to detect a name clash by invoking "transfer" with
1803 // NameClash::ERROR.
1806 ucb::TransferInfo2 aTransferArg1(
1807 aTransferArg.MoveData,
1808 aTransferArg.SourceURL,
1809 aTransferArg.NewTitle,
1810 ucb::NameClash::ERROR,
1811 aTransferArg.MimeType );
1813 ucb::Command aCommand1(
1814 OUString("transfer"),
1816 uno::makeAny( aTransferArg1 ) );
1818 xCommandProcessor->execute( aCommand1, 0, xLocalEnv );
1820 // Command succeeded. We're done.
1821 return;
1823 catch ( ucb::UnsupportedNameClashException const & )
1825 // No chance to solve name clashes, because I'm not
1826 // able to detect whether there is one.
1827 throw exc; // Not just 'throw;'!
1829 catch ( ucb::NameClashException const & )
1831 // There's a clash. Use interaction handler to solve it.
1833 uno::Any aExc;
1834 OUString aNewTitle;
1835 NameClashContinuation eCont
1836 = interactiveNameClashResolve(
1837 xEnv, // always use original environment!
1838 rArg.TargetURL, // target folder URL
1839 createDesiredName(
1840 aTransferArg ), // clashing name
1841 aExc,
1842 aNewTitle );
1844 switch ( eCont )
1846 case NOT_HANDLED:
1847 // Not handled.
1848 cppu::throwException( aExc );
1849 // break;
1851 case UNKNOWN:
1852 // Handled, but not clear, how...
1853 // fall through intended.
1855 case ABORT:
1856 throw ucb::CommandFailedException(
1857 OUString(
1858 "abort requested via interaction "
1859 "handler" ),
1860 uno::Reference< uno::XInterface >(),
1861 aExc );
1862 // break;
1864 case OVERWRITE:
1865 aTransferArg.NameClash
1866 = ucb::NameClash::OVERWRITE;
1867 bRetry = true;
1868 break;
1870 case NEW_NAME:
1871 aTransferArg.NewTitle = aNewTitle;
1872 bRetry = true;
1873 break;
1876 OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
1879 else
1881 throw;
1885 while ( bRetry );
1890 // (2) Try to transfer the content "manually".
1894 uno::Reference< ucb::XContent > xSource;
1897 uno::Reference< ucb::XContentIdentifier > xId2
1898 = createContentIdentifier( rArg.SourceURL );
1899 if ( xId2.is() )
1900 xSource = queryContent( xId2 );
1902 catch ( ucb::IllegalIdentifierException const & )
1904 // Error handling via "if ( !xSource.is() )" below.
1907 if ( !xSource.is() )
1909 uno::Any aProps
1910 = uno::makeAny(beans::PropertyValue(
1911 OUString( "Uri"),
1913 uno::makeAny(rArg.SourceURL),
1914 beans::PropertyState_DIRECT_VALUE));
1915 ucbhelper::cancelCommandExecution(
1916 ucb::IOErrorCode_CANT_READ,
1917 uno::Sequence< uno::Any >(&aProps, 1),
1918 xEnv,
1919 OUString( "Can't instanciate source object!" ),
1920 this );
1921 // Unreachable
1924 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
1925 xSource, uno::UNO_QUERY );
1926 if ( !xCommandProcessor.is() )
1928 uno::Any aProps
1929 = uno::makeAny(beans::PropertyValue(
1930 OUString( "Uri"),
1932 uno::makeAny(rArg.SourceURL),
1933 beans::PropertyState_DIRECT_VALUE));
1934 ucbhelper::cancelCommandExecution(
1935 ucb::IOErrorCode_CANT_READ,
1936 uno::Sequence< uno::Any >(&aProps, 1),
1937 xEnv,
1938 OUString( "Source content is not a XCommandProcessor!" ),
1939 this );
1940 // Unreachable
1943 // Obtain interesting property values from source...
1945 uno::Sequence< beans::Property > aProps( 4 );
1947 aProps[ 0 ].Name = "IsFolder";
1948 aProps[ 0 ].Handle = -1; /* unknown */
1949 aProps[ 1 ].Name = "IsDocument";
1950 aProps[ 1 ].Handle = -1; /* unknown */
1951 aProps[ 2 ].Name = "TargetURL";
1952 aProps[ 2 ].Handle = -1; /* unknown */
1953 aProps[ 3 ].Name = "BaseURI";
1954 aProps[ 3 ].Handle = -1; /* unknown */
1956 ucb::Command aGetPropsCommand(
1957 OUString("getPropertyValues"),
1959 uno::makeAny( aProps ) );
1961 uno::Reference< sdbc::XRow > xRow;
1962 xCommandProcessor->execute( aGetPropsCommand, 0, xLocalEnv ) >>= xRow;
1964 if ( !xRow.is() )
1966 uno::Any aProps2
1967 = uno::makeAny(beans::PropertyValue(
1968 OUString( "Uri"),
1970 uno::makeAny(rArg.SourceURL),
1971 beans::PropertyState_DIRECT_VALUE));
1972 ucbhelper::cancelCommandExecution(
1973 ucb::IOErrorCode_CANT_READ,
1974 uno::Sequence< uno::Any >(&aProps2, 1),
1975 xEnv,
1976 OUString( "Unable to get properties from source object!" ),
1977 this );
1978 // Unreachable
1981 TransferCommandContext aTransferCtx(
1982 m_xContext, this, xLocalEnv, xEnv, rArg );
1984 if ( rArg.NewTitle.isEmpty() )
1986 // BaseURI: property is optional.
1987 OUString aBaseURI( xRow->getString( 4 ) );
1988 if ( !aBaseURI.isEmpty() )
1990 aTransferCtx.aArg.NewTitle
1991 = createDesiredName( aBaseURI, OUString() );
1995 // Do it!
1996 globalTransfer_( aTransferCtx, xSource, xTarget, xRow );
2000 // (3) Delete source, if operation is MOVE.
2004 if ( rArg.Operation == ucb::TransferCommandOperation_MOVE )
2008 ucb::Command aCommand(
2009 OUString("delete"), // Name
2010 -1, // Handle
2011 uno::makeAny( true ) ); // Argument
2013 xCommandProcessor->execute( aCommand, 0, xLocalEnv );
2015 catch ( uno::Exception const & )
2017 OSL_FAIL( "Cannot delete source object!" );
2018 throw;
2023 uno::Any UniversalContentBroker::checkIn( const ucb::CheckinArgument& rArg,
2024 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) throw ( uno::Exception )
2026 uno::Any aRet;
2027 // Use own command environment with own interaction handler intercepting
2028 // some interaction requests that shall not be handled by the user-supplied
2029 // interaction handler.
2030 uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
2031 if (xEnv.is())
2033 xLocalEnv.set( ucb::CommandEnvironment::create(
2034 m_xContext,
2035 new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
2036 xEnv->getProgressHandler() ) );
2039 uno::Reference< ucb::XContent > xTarget;
2040 uno::Reference< ucb::XContentIdentifier > xId
2041 = createContentIdentifier( rArg.TargetURL );
2042 if ( xId.is() )
2046 xTarget = queryContent( xId );
2048 catch ( ucb::IllegalIdentifierException const & )
2053 if ( !xTarget.is() )
2055 uno::Any aProps
2056 = uno::makeAny(beans::PropertyValue(
2057 OUString( "Uri" ), -1,
2058 uno::makeAny( rArg.TargetURL ),
2059 beans::PropertyState_DIRECT_VALUE ) );
2060 ucbhelper::cancelCommandExecution(
2061 ucb::IOErrorCode_CANT_READ,
2062 uno::Sequence< uno::Any >( &aProps, 1 ),
2063 xEnv,
2064 OUString( "Can't instanciate target object!" ),
2065 this );
2066 // Unreachable
2069 uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
2070 xTarget, uno::UNO_QUERY );
2071 if ( !xCommandProcessor.is() )
2073 uno::Any aProps
2074 = uno::makeAny(
2075 beans::PropertyValue(
2076 OUString( "Uri" ), -1,
2077 uno::makeAny( rArg.TargetURL ),
2078 beans::PropertyState_DIRECT_VALUE ) );
2079 ucbhelper::cancelCommandExecution(
2080 ucb::IOErrorCode_CANT_READ,
2081 uno::Sequence< uno::Any >( &aProps, 1 ),
2082 xEnv,
2083 OUString( "Target content is not a XCommandProcessor!" ),
2084 this );
2085 // Unreachable
2090 ucb::Command aCommand(
2091 OUString( "checkin" ), -1,
2092 uno::makeAny( rArg ) );
2094 aRet = xCommandProcessor->execute( aCommand, 0, xLocalEnv );
2096 catch ( ucb::UnsupportedCommandException const & )
2098 // 'checkin' command is not supported by commandprocessor:
2099 // ignore.
2101 return aRet;
2104 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */