1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <osl/diagnose.h>
22 #include <comphelper/propertysequence.hxx>
23 #include <cppuhelper/implbase.hxx>
24 #include <cppuhelper/exc_hlp.hxx>
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/beans/XPropertySetInfo.hpp>
30 #include <com/sun/star/io/IOException.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/lang/IllegalArgumentException.hpp>
36 #include <com/sun/star/sdbc/SQLException.hpp>
37 #include <com/sun/star/sdbc/XRow.hpp>
38 #include <com/sun/star/task/XInteractionHandler.hpp>
39 #include <com/sun/star/ucb/CommandEnvironment.hpp>
40 #include <com/sun/star/ucb/CommandFailedException.hpp>
41 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
42 #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
43 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
44 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
45 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
46 #include <com/sun/star/ucb/NameClash.hpp>
47 #include <com/sun/star/ucb/NameClashException.hpp>
48 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
49 #include <com/sun/star/ucb/OpenMode.hpp>
50 #include <com/sun/star/ucb/TransferInfo2.hpp>
51 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
52 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
53 #include <com/sun/star/ucb/XCommandInfo.hpp>
54 #include <com/sun/star/ucb/XContentAccess.hpp>
55 #include <com/sun/star/ucb/XContentCreator.hpp>
56 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
57 #include <com/sun/star/ucb/XInteractionSupplyName.hpp>
58 #include <com/sun/star/uno/Any.hxx>
59 #include <com/sun/star/uno/Sequence.hxx>
60 #include <ucbhelper/cancelcommandexecution.hxx>
61 #include <ucbhelper/simplenameclashresolverequest.hxx>
62 #include "ucbcmds.hxx"
65 using namespace com::sun::star
;
71 // struct TransferCommandContext.
74 struct TransferCommandContext
76 uno::Reference
< uno::XComponentContext
> m_xContext
;
77 uno::Reference
< ucb::XCommandProcessor
> xProcessor
;
78 uno::Reference
< ucb::XCommandEnvironment
> xEnv
;
79 uno::Reference
< ucb::XCommandEnvironment
> xOrigEnv
;
80 ucb::GlobalTransferCommandArgument2 aArg
;
82 TransferCommandContext(
83 const uno::Reference
< uno::XComponentContext
> & xContext
,
84 const uno::Reference
< ucb::XCommandProcessor
> & rxProcessor
,
85 const uno::Reference
< ucb::XCommandEnvironment
> & rxEnv
,
86 const uno::Reference
< ucb::XCommandEnvironment
> & rxOrigEnv
,
87 const ucb::GlobalTransferCommandArgument2
& rArg
)
88 : m_xContext( xContext
), xProcessor( rxProcessor
), xEnv( rxEnv
),
89 xOrigEnv( rxOrigEnv
), aArg( rArg
) {}
93 // class InteractionHandlerProxy.
96 class InteractionHandlerProxy
:
97 public cppu::WeakImplHelper
< task::XInteractionHandler
>
99 uno::Reference
< task::XInteractionHandler
> m_xOrig
;
102 explicit 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
) override
;
113 void SAL_CALL
InteractionHandlerProxy::handle(
114 const uno::Reference
< task::XInteractionRequest
>& Request
)
119 // Filter unwanted requests by just not handling them.
120 uno::Any aRequest
= Request
->getRequest();
123 ucb::InteractiveBadTransferURLException aBadTransferURLEx
;
124 if ( aRequest
>>= aBadTransferURLEx
)
131 ucb::UnsupportedNameClashException aUnsupportedNameClashEx
;
132 if ( aRequest
>>= aUnsupportedNameClashEx
)
134 if ( aUnsupportedNameClashEx
.NameClash
135 != ucb::NameClash::ERROR
)
141 ucb::NameClashException aNameClashEx
;
142 if ( aRequest
>>= aNameClashEx
)
149 ucb::UnsupportedCommandException aUnsupportedCommandEx
;
150 if ( aRequest
>>= aUnsupportedCommandEx
)
158 // not filtered; let the original handler do the work.
159 m_xOrig
->handle( Request
);
163 // class ActiveDataSink.
166 class ActiveDataSink
: public cppu::WeakImplHelper
< io::XActiveDataSink
>
168 uno::Reference
< io::XInputStream
> m_xStream
;
171 // XActiveDataSink methods.
172 virtual void SAL_CALL
setInputStream(
173 const uno::Reference
< io::XInputStream
>& aStream
) override
;
174 virtual uno::Reference
< io::XInputStream
> SAL_CALL
getInputStream() override
;
179 void SAL_CALL
ActiveDataSink::setInputStream(
180 const uno::Reference
< io::XInputStream
>& aStream
)
187 uno::Reference
< io::XInputStream
> SAL_CALL
ActiveDataSink::getInputStream()
193 // class CommandProcessorInfo.
196 class CommandProcessorInfo
:
197 public cppu::WeakImplHelper
< ucb::XCommandInfo
>
199 std::unique_ptr
< uno::Sequence
< ucb::CommandInfo
> > m_pInfo
;
202 CommandProcessorInfo();
204 // XCommandInfo methods
205 virtual uno::Sequence
< ucb::CommandInfo
> SAL_CALL
getCommands() override
;
206 virtual ucb::CommandInfo SAL_CALL
207 getCommandInfoByName( const OUString
& Name
) override
;
208 virtual ucb::CommandInfo SAL_CALL
209 getCommandInfoByHandle( sal_Int32 Handle
) override
;
210 virtual sal_Bool SAL_CALL
hasCommandByName( const OUString
& Name
) override
;
211 virtual sal_Bool SAL_CALL
hasCommandByHandle( sal_Int32 Handle
) override
;
215 CommandProcessorInfo::CommandProcessorInfo()
216 : m_pInfo( new uno::Sequence
< ucb::CommandInfo
>( 3 ) )
220 GETCOMMANDINFO_NAME
, // Name
221 GETCOMMANDINFO_HANDLE
, // Handle
222 cppu::UnoType
<void>::get() ); // ArgType
225 GLOBALTRANSFER_NAME
, // Name
226 GLOBALTRANSFER_HANDLE
, // Handle
227 cppu::UnoType
<ucb::GlobalTransferCommandArgument
>::get() ); // ArgType
230 CHECKIN_NAME
, // Name
231 CHECKIN_HANDLE
, // Handle
232 cppu::UnoType
<ucb::CheckinArgument
>::get() ); // ArgType
237 uno::Sequence
< ucb::CommandInfo
> SAL_CALL
238 CommandProcessorInfo::getCommands()
245 ucb::CommandInfo SAL_CALL
246 CommandProcessorInfo::getCommandInfoByName( const OUString
& Name
)
248 auto pInfo
= std::find_if(m_pInfo
->begin(), m_pInfo
->end(),
249 [&Name
](const ucb::CommandInfo
& rInfo
) { return rInfo
.Name
== Name
; });
250 if (pInfo
!= m_pInfo
->end())
253 throw ucb::UnsupportedCommandException();
258 ucb::CommandInfo SAL_CALL
259 CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle
)
261 auto pInfo
= std::find_if(m_pInfo
->begin(), m_pInfo
->end(),
262 [&Handle
](const ucb::CommandInfo
& rInfo
) { return rInfo
.Handle
== Handle
; });
263 if (pInfo
!= m_pInfo
->end())
266 throw ucb::UnsupportedCommandException();
271 sal_Bool SAL_CALL
CommandProcessorInfo::hasCommandByName(
272 const OUString
& Name
)
274 return std::any_of(m_pInfo
->begin(), m_pInfo
->end(),
275 [&Name
](const ucb::CommandInfo
& rInfo
) { return rInfo
.Name
== Name
; });
280 sal_Bool SAL_CALL
CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle
)
282 return std::any_of(m_pInfo
->begin(), m_pInfo
->end(),
283 [&Handle
](const ucb::CommandInfo
& rInfo
) { return rInfo
.Handle
== Handle
; });
287 OUString
createDesiredName(
288 const OUString
& rSourceURL
, const OUString
& rNewTitle
)
290 OUString
aName( rNewTitle
);
291 if ( aName
.isEmpty() )
293 // calculate name using source URL
295 // @@@ It's not guaranteed that slashes contained in the URL are
296 // actually path separators. This depends on the fact whether the
297 // URL is hierarchical. Only then the slashes are path separators.
298 // Therefore this algorithm is not guaranteed to work! But, ATM
299 // I don't know a better solution. It would have been better to
300 // have a member for the clashing name in
301 // UnsupportedNameClashException...
303 sal_Int32 nLastSlash
= rSourceURL
.lastIndexOf( '/' );
304 bool bTrailingSlash
= false;
305 if ( nLastSlash
== rSourceURL
.getLength() - 1 )
307 nLastSlash
= rSourceURL
.lastIndexOf( '/', nLastSlash
);
308 bTrailingSlash
= true;
311 if ( nLastSlash
!= -1 )
313 if ( bTrailingSlash
)
314 aName
= rSourceURL
.copy(
316 rSourceURL
.getLength() - nLastSlash
- 2 );
318 aName
= rSourceURL
.copy( nLastSlash
+ 1 );
325 // query, fragment present?
326 sal_Int32 nPos
= aName
.indexOf( '?' );
328 nPos
= aName
.indexOf( '#' );
331 aName
= aName
.copy( 0, nPos
);
336 OUString
createDesiredName(
337 const ucb::GlobalTransferCommandArgument
& rArg
)
339 return createDesiredName( rArg
.SourceURL
, rArg
.NewTitle
);
342 OUString
createDesiredName(
343 const ucb::TransferInfo
& rArg
)
345 return createDesiredName( rArg
.SourceURL
, rArg
.NewTitle
);
349 enum NameClashContinuation
{ NOT_HANDLED
, ABORT
, OVERWRITE
, NEW_NAME
, UNKNOWN
};
351 NameClashContinuation
interactiveNameClashResolve(
352 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
353 const OUString
& rTargetURL
,
354 const OUString
& rClashingName
,
355 /* [out] */ uno::Any
& rException
,
356 /* [out] */ OUString
& rNewName
)
358 rtl::Reference
< ucbhelper::SimpleNameClashResolveRequest
> xRequest(
359 new ucbhelper::SimpleNameClashResolveRequest(
360 rTargetURL
, // target folder URL
364 rException
= xRequest
->getRequest();
367 uno::Reference
< task::XInteractionHandler
> xIH
368 = xEnv
->getInteractionHandler();
372 xIH
->handle( xRequest
.get() );
374 rtl::Reference
< ucbhelper::InteractionContinuation
>
375 xSelection( xRequest
->getSelection() );
377 if ( xSelection
.is() )
379 // Handler handled the request.
380 uno::Reference
< task::XInteractionAbort
> xAbort(
381 xSelection
.get(), uno::UNO_QUERY
);
390 ucb::XInteractionReplaceExistingData
>
392 xSelection
.get(), uno::UNO_QUERY
);
395 // Try again: Replace existing data.
401 ucb::XInteractionSupplyName
>
403 xSelection
.get(), uno::UNO_QUERY
);
404 if ( xSupplyName
.is() )
406 // Try again: Use new name.
407 rNewName
= xRequest
->getNewName();
412 OSL_FAIL( "Unknown interaction continuation!" );
423 /// @throws uno::RuntimeException
425 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessor
,
426 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
427 const OUString
& rNewTitle
)
431 uno::Sequence
< beans::PropertyValue
> aPropValues( 1 );
432 aPropValues
[ 0 ].Name
= "Title";
433 aPropValues
[ 0 ].Handle
= -1;
434 aPropValues
[ 0 ].Value
<<= rNewTitle
;
436 ucb::Command
aSetPropsCommand(
439 uno::makeAny( aPropValues
) );
442 = xCommandProcessor
->execute( aSetPropsCommand
, 0, xEnv
);
444 uno::Sequence
< uno::Any
> aErrors
;
447 OSL_ENSURE( aErrors
.getLength() == 1,
448 "getPropertyValues return value invalid!" );
450 if ( aErrors
[ 0 ].hasValue() )
453 OSL_FAIL( "error setting Title property!" );
457 catch ( uno::RuntimeException
const & )
461 catch ( uno::Exception
const & )
469 /// @throws uno::Exception
470 uno::Reference
< ucb::XContent
> createNew(
471 const TransferCommandContext
& rContext
,
472 const uno::Reference
< ucb::XContent
> & xTarget
,
473 bool bSourceIsFolder
,
474 bool bSourceIsDocument
,
479 // (1) Obtain creatable types from target.
482 // First, try it using "CreatabeleContentsInfo" property and
483 // "createNewContent" command -> the "new" way.
485 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessorT(
486 xTarget
, uno::UNO_QUERY
);
487 if ( !xCommandProcessorT
.is() )
489 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
491 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
493 ucbhelper::cancelCommandExecution(
494 ucb::IOErrorCode_CANT_CREATE
,
497 "Target is no XCommandProcessor!",
498 rContext
.xProcessor
);
502 uno::Sequence
< beans::Property
> aPropsToObtain( 1 );
503 aPropsToObtain
[ 0 ].Name
= "CreatableContentsInfo";
504 aPropsToObtain
[ 0 ].Handle
= -1;
506 ucb::Command
aGetPropsCommand(
509 uno::makeAny( aPropsToObtain
) );
511 uno::Reference
< sdbc::XRow
> xRow
;
512 xCommandProcessorT
->execute( aGetPropsCommand
, 0, rContext
.xEnv
) >>= xRow
;
514 uno::Sequence
< ucb::ContentInfo
> aTypesInfo
;
515 bool bGotTypesInfo
= false;
519 uno::Any aValue
= xRow
->getObject(
520 1, uno::Reference
< container::XNameAccess
>() );
521 if ( aValue
.hasValue() && ( aValue
>>= aTypesInfo
) )
523 bGotTypesInfo
= true;
527 uno::Reference
< ucb::XContentCreator
> xCreator
;
529 if ( !bGotTypesInfo
)
531 // Second, try it using XContentCreator interface -> the "old" way (not
532 // providing the chance to supply an XCommandEnvironment.
534 xCreator
.set( xTarget
, uno::UNO_QUERY
);
536 if ( !xCreator
.is() )
538 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
540 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
542 ucbhelper::cancelCommandExecution(
543 ucb::IOErrorCode_CANT_CREATE
,
546 "Target is no XContentCreator!",
547 rContext
.xProcessor
);
551 aTypesInfo
= xCreator
->queryCreatableContentsInfo();
554 if ( !aTypesInfo
.hasElements() )
556 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
558 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
560 ucbhelper::cancelCommandExecution(
561 ucb::IOErrorCode_CANT_CREATE
,
564 "No types creatable!",
565 rContext
.xProcessor
);
569 // (2) Try to find a matching target type for the source object.
571 std::function
<bool(const sal_Int32
)> lCompare
;
573 if ( rContext
.aArg
.Operation
== ucb::TransferCommandOperation_LINK
)
576 lCompare
= [](const sal_Int32 nAttribs
) { return !!( nAttribs
& ucb::ContentInfoAttribute::KIND_LINK
); };
578 else if ( ( rContext
.aArg
.Operation
== ucb::TransferCommandOperation_COPY
) ||
579 ( rContext
.aArg
.Operation
== ucb::TransferCommandOperation_MOVE
) )
582 // Is source a link? Create link in target folder then.
585 lCompare
= [](const sal_Int32 nAttribs
) { return !!( nAttribs
& ucb::ContentInfoAttribute::KIND_LINK
); };
589 // (not a and not b) or (a and b)
590 // not( a or b) or (a and b)
591 lCompare
= [bSourceIsFolder
, bSourceIsDocument
](const sal_Int32 nAttribs
) {
592 return ( bSourceIsFolder
== !!( nAttribs
& ucb::ContentInfoAttribute::KIND_FOLDER
) )
593 && ( bSourceIsDocument
== !!( nAttribs
& ucb::ContentInfoAttribute::KIND_DOCUMENT
) ) ;
599 ucbhelper::cancelCommandExecution(
600 uno::makeAny( lang::IllegalArgumentException(
601 "Unknown transfer operation!",
608 uno::Reference
< ucb::XContent
> xNew
;
609 auto pTypeInfo
= std::find_if(aTypesInfo
.begin(), aTypesInfo
.end(),
610 [&lCompare
](const ucb::ContentInfo
& rTypeInfo
) { return lCompare(rTypeInfo
.Attributes
); });
611 if (pTypeInfo
!= aTypesInfo
.end())
613 // (3) Create a new, empty object of matched type.
615 if ( !xCreator
.is() )
617 // First, try it using "CreatabeleContentsInfo" property and
618 // "createNewContent" command -> the "new" way.
619 ucb::Command
aCreateNewCommand(
622 uno::makeAny( *pTypeInfo
) );
624 xCommandProcessorT
->execute( aCreateNewCommand
, 0, rContext
.xEnv
)
629 // Second, try it using XContentCreator interface -> the "old"
630 // way (not providing the chance to supply an XCommandEnvironment.
632 xNew
= xCreator
->createNewContent( *pTypeInfo
);
637 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
639 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
641 ucbhelper::cancelCommandExecution(
642 ucb::IOErrorCode_CANT_CREATE
,
645 "createNewContent failed!",
646 rContext
.xProcessor
);
654 /// @throws uno::Exception
655 void transferProperties(
656 const TransferCommandContext
& rContext
,
657 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorS
,
658 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorN
)
660 ucb::Command
aGetPropertySetInfoCommand(
661 "getPropertySetInfo",
665 uno::Reference
< beans::XPropertySetInfo
> xInfo
;
666 xCommandProcessorS
->execute( aGetPropertySetInfoCommand
, 0, rContext
.xEnv
)
671 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
673 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
675 ucbhelper::cancelCommandExecution(
676 ucb::IOErrorCode_CANT_READ
,
679 "Unable to get propertyset info from source object!",
680 rContext
.xProcessor
);
684 uno::Sequence
< beans::Property
> aAllProps
= xInfo
->getProperties();
686 ucb::Command
aGetPropsCommand1(
689 uno::makeAny( aAllProps
) );
691 uno::Reference
< sdbc::XRow
> xRow1
;
692 xCommandProcessorS
->execute(
693 aGetPropsCommand1
, 0, rContext
.xEnv
) >>= xRow1
;
697 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
699 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
701 ucbhelper::cancelCommandExecution(
702 ucb::IOErrorCode_CANT_READ
,
705 "Unable to get properties from source object!",
706 rContext
.xProcessor
);
710 // Assemble data structure for setPropertyValues command.
712 // Note: Make room for additional Title and TargetURL too. -> + 2
713 uno::Sequence
< beans::PropertyValue
> aPropValues(
714 aAllProps
.getLength() + 2 );
716 bool bHasTitle
= rContext
.aArg
.NewTitle
.isEmpty();
717 bool bHasTargetURL
= ( rContext
.aArg
.Operation
718 != ucb::TransferCommandOperation_LINK
);
720 sal_Int32 nWritePos
= 0;
721 for ( sal_Int32 m
= 0; m
< aAllProps
.getLength(); ++m
)
723 const beans::Property
& rCurrProp
= aAllProps
[ m
];
724 beans::PropertyValue
& rCurrValue
= aPropValues
[ nWritePos
];
728 if ( rCurrProp
.Name
== "Title" )
730 // Supply new title, if given.
734 aValue
<<= rContext
.aArg
.NewTitle
;
737 else if ( rCurrProp
.Name
== "TargetURL" )
739 // Supply source URL as link target for the new link to create.
740 if ( !bHasTargetURL
)
742 bHasTargetURL
= true;
743 aValue
<<= rContext
.aArg
.SourceURL
;
747 if ( !aValue
.hasValue() )
751 aValue
= xRow1
->getObject(
752 m
+ 1, uno::Reference
< container::XNameAccess
>() );
754 catch ( sdbc::SQLException
const & )
756 // Argh! But try to bring things to an end. Perhaps the
757 // mad property is not really important...
761 if ( aValue
.hasValue() )
763 rCurrValue
.Name
= rCurrProp
.Name
;
764 rCurrValue
.Handle
= rCurrProp
.Handle
;
765 rCurrValue
.Value
= aValue
;
766 // rCurrValue.State =
772 // Title needed, but not set yet?
773 if ( !bHasTitle
&& !rContext
.aArg
.NewTitle
.isEmpty() )
775 aPropValues
[ nWritePos
].Name
= "Title";
776 aPropValues
[ nWritePos
].Handle
= -1;
777 aPropValues
[ nWritePos
].Value
<<= rContext
.aArg
.NewTitle
;
782 // TargetURL needed, but not set yet?
783 if ( !bHasTargetURL
&& ( rContext
.aArg
.Operation
784 == ucb::TransferCommandOperation_LINK
) )
786 aPropValues
[ nWritePos
].Name
= "TargetURL";
787 aPropValues
[ nWritePos
].Handle
= -1;
788 aPropValues
[ nWritePos
].Value
<<= rContext
.aArg
.SourceURL
;
793 aPropValues
.realloc( nWritePos
);
795 // Set properties at new object.
797 ucb::Command
aSetPropsCommand(
800 uno::makeAny( aPropValues
) );
802 xCommandProcessorN
->execute( aSetPropsCommand
, 0, rContext
.xEnv
);
804 // @@@ What to do with source props that are not supported by the
805 // new object? addProperty ???
808 /// @throws uno::Exception
809 uno::Reference
< io::XInputStream
> getInputStream(
810 const TransferCommandContext
& rContext
,
811 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorS
)
813 uno::Reference
< io::XInputStream
> xInputStream
;
816 // (1) Try to get data as XInputStream via XActiveDataSink.
821 uno::Reference
< io::XActiveDataSink
> xSink
= new ActiveDataSink
;
823 ucb::OpenCommandArgument2 aArg
;
824 aArg
.Mode
= ucb::OpenMode::DOCUMENT
;
825 aArg
.Priority
= 0; // unused
827 aArg
.Properties
= uno::Sequence
< beans::Property
>( 0 ); // unused
829 ucb::Command
aOpenCommand(
832 uno::makeAny( aArg
) );
834 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
);
835 xInputStream
= xSink
->getInputStream();
837 catch ( uno::RuntimeException
const & )
841 catch ( uno::Exception
const & )
843 // will be handled below.
846 if ( !xInputStream
.is() )
850 // (2) Try to get data via XOutputStream.
855 uno::Reference
< io::XOutputStream
> xOutputStream( io::Pipe::create(rContext
.m_xContext
), uno::UNO_QUERY_THROW
);
857 ucb::OpenCommandArgument2 aArg
;
858 aArg
.Mode
= ucb::OpenMode::DOCUMENT
;
859 aArg
.Priority
= 0; // unused
860 aArg
.Sink
= xOutputStream
;
861 aArg
.Properties
= uno::Sequence
< beans::Property
>( 0 );
863 ucb::Command
aOpenCommand(
866 uno::makeAny( aArg
) );
868 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
);
870 xInputStream
.set( xOutputStream
, uno::UNO_QUERY
);
872 catch ( uno::RuntimeException
const & )
876 catch ( uno::Exception
const & )
878 OSL_FAIL( "unable to get input stream from document!" );
885 /// @throws uno::Exception
886 uno::Reference
< sdbc::XResultSet
> getResultSet(
887 const TransferCommandContext
& rContext
,
888 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorS
)
890 uno::Reference
< sdbc::XResultSet
> xResultSet
;
892 uno::Sequence
< beans::Property
> aProps( 3 );
894 aProps
[ 0 ].Name
= "IsFolder";
895 aProps
[ 0 ].Handle
= -1; /* unknown */
896 aProps
[ 1 ].Name
= "IsDocument";
897 aProps
[ 1 ].Handle
= -1; /* unknown */
898 aProps
[ 2 ].Name
= "TargetURL";
899 aProps
[ 2 ].Handle
= -1; /* unknown */
901 ucb::OpenCommandArgument2 aArg
;
902 aArg
.Mode
= ucb::OpenMode::ALL
;
903 aArg
.Priority
= 0; // unused
905 aArg
.Properties
= aProps
;
907 ucb::Command
aOpenCommand( "open",
909 uno::makeAny( aArg
) );
912 uno::Reference
< ucb::XDynamicResultSet
> xSet
;
913 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
) >>= xSet
;
916 xResultSet
= xSet
->getStaticResultSet();
918 catch ( uno::RuntimeException
const & )
922 catch ( uno::Exception
const & )
924 OSL_FAIL( "unable to get result set from folder!" );
930 /// @throws uno::Exception
931 void handleNameClashRename(
932 const TransferCommandContext
& rContext
,
933 const uno::Reference
< ucb::XContent
> & xNew
,
934 const uno::Reference
<
935 ucb::XCommandProcessor
> & xCommandProcessorN
,
936 const uno::Reference
<
937 ucb::XCommandProcessor
> & xCommandProcessorS
,
938 /* [inout] */ uno::Reference
< io::XInputStream
> & xInputStream
)
943 uno::Sequence
< beans::Property
> aProps( 1 );
944 aProps
[ 0 ].Name
= "Title";
945 aProps
[ 0 ].Handle
= -1;
947 ucb::Command
aGetPropsCommand(
950 uno::makeAny( aProps
) );
952 uno::Reference
< sdbc::XRow
> xRow
;
953 xCommandProcessorN
->execute( aGetPropsCommand
, 0, rContext
.xEnv
) >>= xRow
;
957 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
959 {"Uri", uno::Any(xNew
->getIdentifier()->getContentIdentifier())}
961 ucbhelper::cancelCommandExecution(
962 ucb::IOErrorCode_CANT_READ
,
965 "Unable to get properties from new object!",
966 rContext
.xProcessor
);
970 OUString aOldTitle
= xRow
->getString( 1 );
971 if ( aOldTitle
.isEmpty() )
973 ucbhelper::cancelCommandExecution(
974 uno::makeAny( beans::UnknownPropertyException(
975 "Unable to get property 'Title' from new object!",
976 rContext
.xProcessor
) ),
981 // Some pseudo-intelligence for not destroying file extensions.
982 OUString aOldTitlePre
;
983 OUString aOldTitlePost
;
984 sal_Int32 nPos
= aOldTitle
.lastIndexOf( '.' );
987 aOldTitlePre
= aOldTitle
.copy( 0, nPos
);
988 aOldTitlePost
= aOldTitle
.copy( nPos
);
991 aOldTitlePre
= aOldTitle
;
996 bool bContinue
= true;
1001 OUString aNewTitle
= aOldTitlePre
+ OUString::number( nTry
) +
1005 setTitle( xCommandProcessorN
, rContext
.xEnv
, aNewTitle
);
1007 // Retry inserting the content.
1010 // Previous try may have read from stream. Seek to begin (if
1011 // optional interface XSeekable is supported) or get a new stream.
1012 if ( xInputStream
.is() )
1014 uno::Reference
< io::XSeekable
> xSeekable(
1015 xInputStream
, uno::UNO_QUERY
);
1016 if ( xSeekable
.is() )
1020 xSeekable
->seek( 0 );
1022 catch ( lang::IllegalArgumentException
const & )
1024 xInputStream
.clear();
1026 catch ( io::IOException
const & )
1028 xInputStream
.clear();
1032 xInputStream
.clear();
1034 if ( !xInputStream
.is() )
1037 = getInputStream( rContext
, xCommandProcessorS
);
1038 if ( !xInputStream
.is() )
1040 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1042 {"Uri", uno::Any(xNew
->getIdentifier()->getContentIdentifier())}
1044 ucbhelper::cancelCommandExecution(
1045 ucb::IOErrorCode_CANT_READ
,
1048 "Got no data stream from source!",
1049 rContext
.xProcessor
);
1055 ucb::InsertCommandArgument2 aArg
;
1056 aArg
.Data
= xInputStream
;
1057 aArg
.ReplaceExisting
= false;
1059 ucb::Command
aInsertCommand(
1062 uno::makeAny( aArg
) );
1064 xCommandProcessorN
->execute( aInsertCommand
, 0, rContext
.xEnv
);
1069 catch ( uno::RuntimeException
const & )
1073 catch ( uno::Exception
const & )
1077 while ( bContinue
&& ( nTry
< 50 ) );
1081 ucbhelper::cancelCommandExecution(
1083 ucb::UnsupportedNameClashException(
1084 "Unable to resolve name clash!",
1085 rContext
.xProcessor
,
1086 ucb::NameClash::RENAME
) ),
1087 rContext
.xOrigEnv
);
1092 /// @throws uno::Exception
1093 void globalTransfer_(
1094 const TransferCommandContext
& rContext
,
1095 const uno::Reference
< ucb::XContent
> & xSource
,
1096 const uno::Reference
< ucb::XContent
> & xTarget
,
1097 const uno::Reference
< sdbc::XRow
> & xSourceProps
)
1099 // IsFolder: property is required.
1100 bool bSourceIsFolder
= xSourceProps
->getBoolean( 1 );
1101 if ( !bSourceIsFolder
&& xSourceProps
->wasNull() )
1103 ucbhelper::cancelCommandExecution(
1104 uno::makeAny( beans::UnknownPropertyException(
1105 "Unable to get property 'IsFolder' from source object!",
1106 rContext
.xProcessor
) ),
1107 rContext
.xOrigEnv
);
1111 // IsDocument: property is required.
1112 bool bSourceIsDocument
= xSourceProps
->getBoolean( 2 );
1113 if ( !bSourceIsDocument
&& xSourceProps
->wasNull() )
1115 ucbhelper::cancelCommandExecution(
1116 uno::makeAny( beans::UnknownPropertyException(
1117 "Unable to get property 'IsDocument' from source object!",
1118 rContext
.xProcessor
) ),
1119 rContext
.xOrigEnv
);
1123 // TargetURL: property is optional.
1124 bool bSourceIsLink
= !xSourceProps
->getString( 3 ).isEmpty();
1127 // (1) Try to find a matching target type for the source object and
1128 // create a new, empty object of that type.
1131 uno::Reference
< ucb::XContent
> xNew
= createNew( rContext
,
1138 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1140 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
1142 ucbhelper::cancelCommandExecution(
1143 ucb::IOErrorCode_CANT_CREATE
,
1146 "No matching content type at target!",
1147 rContext
.xProcessor
);
1152 // (2) Transfer property values from source to new object.
1155 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessorN(
1156 xNew
, uno::UNO_QUERY
);
1157 if ( !xCommandProcessorN
.is() )
1160 = uno::makeAny(beans::PropertyValue(
1164 xNew
->getIdentifier()->
1165 getContentIdentifier()),
1166 beans::PropertyState_DIRECT_VALUE
));
1167 ucbhelper::cancelCommandExecution(
1168 ucb::IOErrorCode_CANT_WRITE
,
1169 uno::Sequence
< uno::Any
>(&aProps
, 1),
1171 "New content is not a XCommandProcessor!",
1172 rContext
.xProcessor
);
1176 // Obtain all properties from source.
1178 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessorS(
1179 xSource
, uno::UNO_QUERY
);
1180 if ( !xCommandProcessorS
.is() )
1182 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1184 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
1186 ucbhelper::cancelCommandExecution(
1187 ucb::IOErrorCode_CANT_READ
,
1190 "Source content is not a XCommandProcessor!",
1191 rContext
.xProcessor
);
1195 transferProperties( rContext
, xCommandProcessorS
, xCommandProcessorN
);
1198 // (3) Try to obtain a data stream from source.
1201 uno::Reference
< io::XInputStream
> xInputStream
;
1203 if ( bSourceIsDocument
&& ( rContext
.aArg
.Operation
1204 != ucb::TransferCommandOperation_LINK
) )
1205 xInputStream
= getInputStream( rContext
, xCommandProcessorS
);
1208 // (4) Try to obtain a resultset (children) from source.
1211 uno::Reference
< sdbc::XResultSet
> xResultSet
;
1213 if ( bSourceIsFolder
&& ( rContext
.aArg
.Operation
1214 != ucb::TransferCommandOperation_LINK
) )
1215 xResultSet
= getResultSet( rContext
, xCommandProcessorS
);
1218 // (5) Insert (store) new content.
1221 ucb::InsertCommandArgument2 aArg
;
1222 aArg
.Data
= xInputStream
;
1223 aArg
.MimeType
= rContext
.aArg
.MimeType
;
1224 aArg
.DocumentId
= rContext
.aArg
.DocumentId
;
1226 switch ( rContext
.aArg
.NameClash
)
1228 case ucb::NameClash::OVERWRITE
:
1229 aArg
.ReplaceExisting
= true;
1232 case ucb::NameClash::ERROR
:
1233 case ucb::NameClash::RENAME
:
1234 case ucb::NameClash::KEEP
: // deprecated
1235 case ucb::NameClash::ASK
:
1236 aArg
.ReplaceExisting
= false;
1240 aArg
.ReplaceExisting
= false;
1241 OSL_FAIL( "Unknown nameclash directive!" );
1245 OUString aDesiredName
= createDesiredName( rContext
.aArg
);
1254 ucb::Command
aInsertCommand(
1257 uno::makeAny( aArg
) );
1259 xCommandProcessorN
->execute( aInsertCommand
, 0, rContext
.xEnv
);
1261 catch ( ucb::UnsupportedNameClashException
const & exc
)
1263 OSL_ENSURE( !aArg
.ReplaceExisting
,
1264 "BUG: UnsupportedNameClashException not allowed here!" );
1266 if (exc
.NameClash
!= ucb::NameClash::ERROR
) {
1267 OSL_FAIL( "BUG: NameClash::ERROR expected!" );
1270 // No chance to solve name clashes, because I'm not able to detect
1271 // whether there is one.
1272 throw ucb::UnsupportedNameClashException(
1273 "Unable to resolve name clashes, no chance to detect "
1274 "that there is one!",
1275 rContext
.xProcessor
,
1276 rContext
.aArg
.NameClash
);
1278 catch ( ucb::NameClashException
const & )
1280 // The 'insert' command throws a NameClashException if the parameter
1281 // ReplaceExisting of the command's argument was set to false and
1282 // there exists a resource with a clashing name in the target folder
1283 // of the operation.
1285 // 'insert' command has no direct support for name clashes other
1286 // than ERROR ( ReplaceExisting == false ) and OVERWRITE
1287 // ( ReplaceExisting == true ). So we have to implement the
1288 // other name clash handling directives on top of the content.
1290 // @@@ 'insert' command should be extended that it accepts a
1291 // name clash handling directive, exactly like 'transfer' command.
1293 switch ( rContext
.aArg
.NameClash
)
1295 case ucb::NameClash::OVERWRITE
:
1297 ucbhelper::cancelCommandExecution(
1299 ucb::UnsupportedNameClashException(
1300 "BUG: insert + replace == true MUST NOT "
1301 "throw NameClashException.",
1302 rContext
.xProcessor
,
1303 rContext
.aArg
.NameClash
) ),
1304 rContext
.xOrigEnv
);
1305 [[fallthrough
]]; // Unreachable
1308 case ucb::NameClash::ERROR
:
1311 case ucb::NameClash::RENAME
:
1313 // "invent" a new valid title.
1314 handleNameClashRename( rContext
,
1322 case ucb::NameClash::ASK
:
1326 NameClashContinuation eCont
1327 = interactiveNameClashResolve(
1328 rContext
.xOrigEnv
, // always use original environment!
1329 rContext
.aArg
.TargetURL
, // target folder URL
1338 cppu::throwException( aExc
);
1339 [[fallthrough
]]; // break;
1342 // Handled, but not clear, how...
1343 // fall through intended.
1346 throw ucb::CommandFailedException(
1347 "abort requested via interaction "
1349 uno::Reference
< uno::XInterface
>(),
1354 OSL_ENSURE( !aArg
.ReplaceExisting
,
1355 "Hu? ReplaceExisting already true?"
1357 aArg
.ReplaceExisting
= true;
1363 // set new name -> set "Title" property...
1364 if ( setTitle( xCommandProcessorN
,
1368 // remember suggested title...
1369 aDesiredName
= aNewTitle
;
1371 // ... and try again.
1376 // error setting title. Abort.
1377 throw ucb::CommandFailedException(
1378 "error setting Title property!",
1379 uno::Reference
< uno::XInterface
>(),
1386 OSL_ENSURE( bRetry
, "bRetry must be true here!!!" );
1390 case ucb::NameClash::KEEP
: // deprecated
1393 ucbhelper::cancelCommandExecution(
1395 ucb::UnsupportedNameClashException(
1396 "default action, don't know how to "
1397 "handle name clash",
1398 rContext
.xProcessor
,
1399 rContext
.aArg
.NameClash
) ),
1400 rContext
.xOrigEnv
);
1409 // (6) Process children of source.
1412 if ( xResultSet
.is() )
1416 // Iterate over children...
1418 uno::Reference
< sdbc::XRow
> xChildRow(
1419 xResultSet
, uno::UNO_QUERY
);
1421 if ( !xChildRow
.is() )
1425 beans::PropertyValue(
1428 uno::makeAny(rContext
.aArg
.SourceURL
),
1429 beans::PropertyState_DIRECT_VALUE
));
1430 ucbhelper::cancelCommandExecution(
1431 ucb::IOErrorCode_CANT_READ
,
1432 uno::Sequence
< uno::Any
>(&aProps
, 1),
1434 "Unable to get properties from children of source!",
1435 rContext
.xProcessor
);
1439 uno::Reference
< ucb::XContentAccess
> xChildAccess(
1440 xResultSet
, uno::UNO_QUERY
);
1442 if ( !xChildAccess
.is() )
1444 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1446 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
1448 ucbhelper::cancelCommandExecution(
1449 ucb::IOErrorCode_CANT_READ
,
1452 "Unable to get children of source!",
1453 rContext
.xProcessor
);
1457 if ( xResultSet
->first() )
1459 ucb::GlobalTransferCommandArgument2
aTransArg(
1460 rContext
.aArg
.Operation
,
1461 OUString(), // SourceURL; filled later
1462 xNew
->getIdentifier()
1463 ->getContentIdentifier(), // TargetURL
1464 OUString(), // NewTitle;
1465 rContext
.aArg
.NameClash
,
1466 rContext
.aArg
.MimeType
,
1467 rContext
.aArg
.DocumentId
);
1469 TransferCommandContext
aSubCtx(
1470 rContext
.m_xContext
,
1471 rContext
.xProcessor
,
1477 uno::Reference
< ucb::XContent
> xChild
1478 = xChildAccess
->queryContent();
1483 aSubCtx
.aArg
.SourceURL
1484 = xChild
->getIdentifier()->getContentIdentifier();
1486 globalTransfer_( aSubCtx
,
1492 while ( xResultSet
->next() );
1495 catch ( sdbc::SQLException
const & )
1501 uno::Reference
< ucb::XCommandProcessor
> xcp(
1502 xTarget
, uno::UNO_QUERY
);
1505 uno::Reference
< ucb::XCommandInfo
> xci
;
1516 const OUString
cmdName("flush");
1517 if((aAny
>>= xci
) && xci
->hasCommandByName(cmdName
))
1526 catch( uno::Exception
const & )
1534 // UniversalContentBroker implementation ( XCommandProcessor commands ).
1537 uno::Reference
< ucb::XCommandInfo
>
1538 UniversalContentBroker::getCommandInfo()
1540 return uno::Reference
< ucb::XCommandInfo
>( new CommandProcessorInfo() );
1544 void UniversalContentBroker::globalTransfer(
1545 const ucb::GlobalTransferCommandArgument2
& rArg
,
1546 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1548 // Use own command environment with own interaction handler intercepting
1549 // some interaction requests that shall not be handled by the user-supplied
1550 // interaction handler.
1551 uno::Reference
< ucb::XCommandEnvironment
> xLocalEnv
;
1554 xLocalEnv
.set( ucb::CommandEnvironment::create(
1556 new InteractionHandlerProxy( xEnv
->getInteractionHandler() ),
1557 xEnv
->getProgressHandler() ) );
1561 // (1) Try to transfer the content using 'transfer' command.
1564 uno::Reference
< ucb::XContent
> xTarget
;
1565 uno::Reference
< ucb::XContentIdentifier
> xId
1566 = createContentIdentifier( rArg
.TargetURL
);
1571 xTarget
= queryContent( xId
);
1573 catch ( ucb::IllegalIdentifierException
const & )
1578 if ( !xTarget
.is() )
1580 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1582 {"Uri", uno::Any(rArg
.TargetURL
)}
1584 ucbhelper::cancelCommandExecution(
1585 ucb::IOErrorCode_CANT_READ
,
1588 "Can't instantiate target object!",
1593 if ( ( rArg
.Operation
== ucb::TransferCommandOperation_COPY
) ||
1594 ( rArg
.Operation
== ucb::TransferCommandOperation_MOVE
) )
1596 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1597 xTarget
, uno::UNO_QUERY
);
1598 if ( !xCommandProcessor
.is() )
1600 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1602 {"Uri", uno::Any(rArg
.TargetURL
)}
1604 ucbhelper::cancelCommandExecution(
1605 ucb::IOErrorCode_CANT_READ
,
1608 "Target content is not a XCommandProcessor!",
1613 ucb::TransferInfo2
aTransferArg(
1615 == ucb::TransferCommandOperation_MOVE
), // MoveData
1628 ucb::Command
aCommand(
1631 uno::makeAny( aTransferArg
) ); // Argument
1633 xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1635 // Command succeeded. We're done.
1638 catch ( ucb::InteractiveBadTransferURLException
const & )
1640 // Source URL is not supported by target. Try to transfer
1641 // the content "manually".
1643 catch ( ucb::UnsupportedCommandException
const & )
1645 // 'transfer' command is not supported by commandprocessor.
1646 // Try to transfer manually.
1648 catch ( ucb::UnsupportedNameClashException
const & exc
)
1650 OSL_ENSURE( aTransferArg
.NameClash
== exc
.NameClash
,
1651 "nameclash mismatch!" );
1652 if ( exc
.NameClash
== ucb::NameClash::ASK
)
1654 // Try to detect a name clash by invoking "transfer" with
1655 // NameClash::ERROR.
1658 ucb::TransferInfo2
aTransferArg1(
1659 aTransferArg
.MoveData
,
1660 aTransferArg
.SourceURL
,
1661 aTransferArg
.NewTitle
,
1662 ucb::NameClash::ERROR
,
1663 aTransferArg
.MimeType
);
1665 ucb::Command
aCommand1(
1668 uno::makeAny( aTransferArg1
) );
1670 xCommandProcessor
->execute( aCommand1
, 0, xLocalEnv
);
1672 // Command succeeded. We're done.
1675 catch ( ucb::UnsupportedNameClashException
const & )
1677 // No chance to solve name clashes, because I'm not
1678 // able to detect whether there is one.
1679 throw exc
; // Not just 'throw;'!
1681 catch ( ucb::NameClashException
const & )
1683 // There's a clash. Use interaction handler to solve it.
1687 NameClashContinuation eCont
1688 = interactiveNameClashResolve(
1689 xEnv
, // always use original environment!
1690 rArg
.TargetURL
, // target folder URL
1692 aTransferArg
), // clashing name
1700 cppu::throwException( aExc
);
1701 [[fallthrough
]]; // break;
1704 // Handled, but not clear, how...
1705 // fall through intended.
1708 throw ucb::CommandFailedException(
1709 "abort requested via interaction "
1711 uno::Reference
< uno::XInterface
>(),
1716 aTransferArg
.NameClash
1717 = ucb::NameClash::OVERWRITE
;
1722 aTransferArg
.NewTitle
= aNewTitle
;
1727 OSL_ENSURE( bRetry
, "bRetry must be true here!!!" );
1740 // (2) Try to transfer the content "manually".
1743 uno::Reference
< ucb::XContent
> xSource
;
1746 uno::Reference
< ucb::XContentIdentifier
> xId2
1747 = createContentIdentifier( rArg
.SourceURL
);
1749 xSource
= queryContent( xId2
);
1751 catch ( ucb::IllegalIdentifierException
const & )
1753 // Error handling via "if ( !xSource.is() )" below.
1756 if ( !xSource
.is() )
1758 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1760 {"Uri", uno::Any(rArg
.SourceURL
)}
1762 ucbhelper::cancelCommandExecution(
1763 ucb::IOErrorCode_CANT_READ
,
1766 "Can't instantiate source object!",
1771 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1772 xSource
, uno::UNO_QUERY
);
1773 if ( !xCommandProcessor
.is() )
1775 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1777 {"Uri", uno::Any(rArg
.SourceURL
)}
1779 ucbhelper::cancelCommandExecution(
1780 ucb::IOErrorCode_CANT_READ
,
1783 "Source content is not a XCommandProcessor!",
1788 // Obtain interesting property values from source...
1790 uno::Sequence
< beans::Property
> aProps( 4 );
1792 aProps
[ 0 ].Name
= "IsFolder";
1793 aProps
[ 0 ].Handle
= -1; /* unknown */
1794 aProps
[ 1 ].Name
= "IsDocument";
1795 aProps
[ 1 ].Handle
= -1; /* unknown */
1796 aProps
[ 2 ].Name
= "TargetURL";
1797 aProps
[ 2 ].Handle
= -1; /* unknown */
1798 aProps
[ 3 ].Name
= "BaseURI";
1799 aProps
[ 3 ].Handle
= -1; /* unknown */
1801 ucb::Command
aGetPropsCommand(
1802 "getPropertyValues",
1804 uno::makeAny( aProps
) );
1806 uno::Reference
< sdbc::XRow
> xRow
;
1807 xCommandProcessor
->execute( aGetPropsCommand
, 0, xLocalEnv
) >>= xRow
;
1811 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1813 {"Uri", uno::Any(rArg
.SourceURL
)}
1815 ucbhelper::cancelCommandExecution(
1816 ucb::IOErrorCode_CANT_READ
,
1819 "Unable to get properties from source object!",
1824 TransferCommandContext
aTransferCtx(
1825 m_xContext
, this, xLocalEnv
, xEnv
, rArg
);
1827 if ( rArg
.NewTitle
.isEmpty() )
1829 // BaseURI: property is optional.
1830 OUString
aBaseURI( xRow
->getString( 4 ) );
1831 if ( !aBaseURI
.isEmpty() )
1833 aTransferCtx
.aArg
.NewTitle
1834 = createDesiredName( aBaseURI
, OUString() );
1839 globalTransfer_( aTransferCtx
, xSource
, xTarget
, xRow
);
1842 // (3) Delete source, if operation is MOVE.
1845 if ( rArg
.Operation
== ucb::TransferCommandOperation_MOVE
)
1849 ucb::Command
aCommand(
1852 uno::makeAny( true ) ); // Argument
1854 xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1856 catch ( uno::Exception
const & )
1858 OSL_FAIL( "Cannot delete source object!" );
1864 uno::Any
UniversalContentBroker::checkIn( const ucb::CheckinArgument
& rArg
,
1865 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1868 // Use own command environment with own interaction handler intercepting
1869 // some interaction requests that shall not be handled by the user-supplied
1870 // interaction handler.
1871 uno::Reference
< ucb::XCommandEnvironment
> xLocalEnv
;
1874 xLocalEnv
.set( ucb::CommandEnvironment::create(
1876 new InteractionHandlerProxy( xEnv
->getInteractionHandler() ),
1877 xEnv
->getProgressHandler() ) );
1880 uno::Reference
< ucb::XContent
> xTarget
;
1881 uno::Reference
< ucb::XContentIdentifier
> xId
1882 = createContentIdentifier( rArg
.TargetURL
);
1887 xTarget
= queryContent( xId
);
1889 catch ( ucb::IllegalIdentifierException
const & )
1894 if ( !xTarget
.is() )
1896 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1898 {"Uri", uno::Any(rArg
.TargetURL
)}
1900 ucbhelper::cancelCommandExecution(
1901 ucb::IOErrorCode_CANT_READ
,
1904 "Can't instantiate target object!",
1909 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1910 xTarget
, uno::UNO_QUERY
);
1911 if ( !xCommandProcessor
.is() )
1913 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1915 {"Uri", uno::Any(rArg
.TargetURL
)}
1917 ucbhelper::cancelCommandExecution(
1918 ucb::IOErrorCode_CANT_READ
,
1921 "Target content is not a XCommandProcessor!",
1928 ucb::Command
aCommand(
1930 uno::makeAny( rArg
) );
1932 aRet
= xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1934 catch ( ucb::UnsupportedCommandException
const & )
1936 // 'checkin' command is not supported by commandprocessor:
1942 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */