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 .
20 #include <osl/diagnose.h>
21 #include <comphelper/propertysequence.hxx>
22 #include <cppuhelper/implbase.hxx>
23 #include <cppuhelper/exc_hlp.hxx>
24 #include <rtl/ustring.hxx>
25 #include <com/sun/star/uno/XInterface.hpp>
26 #include <com/sun/star/beans/PropertyState.hpp>
27 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <com/sun/star/beans/XPropertySetInfo.hpp>
29 #include <com/sun/star/io/IOException.hpp>
30 #include <com/sun/star/io/Pipe.hpp>
31 #include <com/sun/star/io/XActiveDataSink.hpp>
32 #include <com/sun/star/io/XOutputStream.hpp>
33 #include <com/sun/star/io/XSeekable.hpp>
34 #include <com/sun/star/lang/IllegalArgumentException.hpp>
35 #include <com/sun/star/sdbc/SQLException.hpp>
36 #include <com/sun/star/sdbc/XRow.hpp>
37 #include <com/sun/star/task/XInteractionHandler.hpp>
38 #include <com/sun/star/ucb/CommandEnvironment.hpp>
39 #include <com/sun/star/ucb/CommandFailedException.hpp>
40 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
41 #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
42 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
43 #include <com/sun/star/ucb/InsertCommandArgument2.hpp>
44 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
45 #include <com/sun/star/ucb/NameClash.hpp>
46 #include <com/sun/star/ucb/NameClashException.hpp>
47 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
48 #include <com/sun/star/ucb/OpenMode.hpp>
49 #include <com/sun/star/ucb/TransferInfo2.hpp>
50 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
51 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
52 #include <com/sun/star/ucb/XCommandInfo.hpp>
53 #include <com/sun/star/ucb/XContentAccess.hpp>
54 #include <com/sun/star/ucb/XContentCreator.hpp>
55 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
56 #include <com/sun/star/ucb/XInteractionSupplyName.hpp>
57 #include <com/sun/star/uno/Any.hxx>
58 #include <com/sun/star/uno/Sequence.hxx>
59 #include <ucbhelper/cancelcommandexecution.hxx>
60 #include <ucbhelper/simplenameclashresolverequest.hxx>
62 #include "ucbcmds.hxx"
65 using namespace com::sun::star
;
69 // Helper to provide defaults for type and attributes (save some typing)
70 beans::Property
makeProperty(const OUString
& n
, sal_Int32 h
, uno::Type t
= {}, sal_Int16 a
= {})
72 return { n
, h
, t
, a
};
75 // struct TransferCommandContext.
78 struct TransferCommandContext
80 uno::Reference
< uno::XComponentContext
> m_xContext
;
81 uno::Reference
< ucb::XCommandProcessor
> xProcessor
;
82 uno::Reference
< ucb::XCommandEnvironment
> xEnv
;
83 uno::Reference
< ucb::XCommandEnvironment
> xOrigEnv
;
84 ucb::GlobalTransferCommandArgument2 aArg
;
86 TransferCommandContext(
87 uno::Reference
< uno::XComponentContext
> xContext
,
88 uno::Reference
< ucb::XCommandProcessor
> _xProcessor
,
89 uno::Reference
< ucb::XCommandEnvironment
> _xEnv
,
90 uno::Reference
< ucb::XCommandEnvironment
> _xOrigEnv
,
91 ucb::GlobalTransferCommandArgument2 _aArg
)
92 : m_xContext(std::move( xContext
)), xProcessor(std::move( _xProcessor
)), xEnv(std::move( _xEnv
)),
93 xOrigEnv(std::move( _xOrigEnv
)), aArg(std::move( _aArg
)) {}
99 class InteractionHandlerProxy
:
100 public cppu::WeakImplHelper
< task::XInteractionHandler
>
102 uno::Reference
< task::XInteractionHandler
> m_xOrig
;
105 explicit InteractionHandlerProxy(
106 uno::Reference
< task::XInteractionHandler
> xOrig
)
107 : m_xOrig(std::move( xOrig
)) {}
109 // XInteractionHandler methods.
110 virtual void SAL_CALL
handle(
111 const uno::Reference
< task::XInteractionRequest
>& Request
) override
;
116 void SAL_CALL
InteractionHandlerProxy::handle(
117 const uno::Reference
< task::XInteractionRequest
>& Request
)
122 // Filter unwanted requests by just not handling them.
123 uno::Any aRequest
= Request
->getRequest();
126 ucb::InteractiveBadTransferURLException aBadTransferURLEx
;
127 if ( aRequest
>>= aBadTransferURLEx
)
134 ucb::UnsupportedNameClashException aUnsupportedNameClashEx
;
135 if ( aRequest
>>= aUnsupportedNameClashEx
)
137 if ( aUnsupportedNameClashEx
.NameClash
138 != ucb::NameClash::ERROR
)
144 ucb::NameClashException aNameClashEx
;
145 if ( aRequest
>>= aNameClashEx
)
152 ucb::UnsupportedCommandException aUnsupportedCommandEx
;
153 if ( aRequest
>>= aUnsupportedCommandEx
)
161 // not filtered; let the original handler do the work.
162 m_xOrig
->handle( Request
);
168 class ActiveDataSink
: public cppu::WeakImplHelper
< io::XActiveDataSink
>
170 uno::Reference
< io::XInputStream
> m_xStream
;
173 // XActiveDataSink methods.
174 virtual void SAL_CALL
setInputStream(
175 const uno::Reference
< io::XInputStream
>& aStream
) override
;
176 virtual uno::Reference
< io::XInputStream
> SAL_CALL
getInputStream() override
;
181 void SAL_CALL
ActiveDataSink::setInputStream(
182 const uno::Reference
< io::XInputStream
>& aStream
)
189 uno::Reference
< io::XInputStream
> SAL_CALL
ActiveDataSink::getInputStream()
197 class CommandProcessorInfo
:
198 public cppu::WeakImplHelper
< ucb::XCommandInfo
>
200 uno::Sequence
< ucb::CommandInfo
> m_xInfo
;
203 CommandProcessorInfo();
205 // XCommandInfo methods
206 virtual uno::Sequence
< ucb::CommandInfo
> SAL_CALL
getCommands() override
;
207 virtual ucb::CommandInfo SAL_CALL
208 getCommandInfoByName( const OUString
& Name
) override
;
209 virtual ucb::CommandInfo SAL_CALL
210 getCommandInfoByHandle( sal_Int32 Handle
) override
;
211 virtual sal_Bool SAL_CALL
hasCommandByName( const OUString
& Name
) override
;
212 virtual sal_Bool SAL_CALL
hasCommandByHandle( sal_Int32 Handle
) override
;
216 CommandProcessorInfo::CommandProcessorInfo()
219 GETCOMMANDINFO_NAME
, // Name
220 GETCOMMANDINFO_HANDLE
, // Handle
221 cppu::UnoType
<void>::get() ), // ArgType
223 GLOBALTRANSFER_NAME
, // Name
224 GLOBALTRANSFER_HANDLE
, // Handle
225 cppu::UnoType
<ucb::GlobalTransferCommandArgument
>::get() ), // ArgType
227 CHECKIN_NAME
, // Name
228 CHECKIN_HANDLE
, // Handle
229 cppu::UnoType
<ucb::CheckinArgument
>::get() ) } // ArgType
235 uno::Sequence
< ucb::CommandInfo
> SAL_CALL
236 CommandProcessorInfo::getCommands()
243 ucb::CommandInfo SAL_CALL
244 CommandProcessorInfo::getCommandInfoByName( const OUString
& Name
)
246 auto pInfo
= std::find_if(std::cbegin(m_xInfo
), std::cend(m_xInfo
),
247 [&Name
](const ucb::CommandInfo
& rInfo
) { return rInfo
.Name
== Name
; });
248 if (pInfo
!= std::cend(m_xInfo
))
251 throw ucb::UnsupportedCommandException();
256 ucb::CommandInfo SAL_CALL
257 CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle
)
259 auto pInfo
= std::find_if(std::cbegin(m_xInfo
), std::cend(m_xInfo
),
260 [&Handle
](const ucb::CommandInfo
& rInfo
) { return rInfo
.Handle
== Handle
; });
261 if (pInfo
!= std::cend(m_xInfo
))
264 throw ucb::UnsupportedCommandException();
269 sal_Bool SAL_CALL
CommandProcessorInfo::hasCommandByName(
270 const OUString
& Name
)
272 return std::any_of(std::cbegin(m_xInfo
), std::cend(m_xInfo
),
273 [&Name
](const ucb::CommandInfo
& rInfo
) { return rInfo
.Name
== Name
; });
278 sal_Bool SAL_CALL
CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle
)
280 return std::any_of(std::cbegin(m_xInfo
), std::cend(m_xInfo
),
281 [&Handle
](const ucb::CommandInfo
& rInfo
) { return rInfo
.Handle
== Handle
; });
285 OUString
createDesiredName(
286 const OUString
& rSourceURL
, const OUString
& rNewTitle
)
288 OUString
aName( rNewTitle
);
289 if ( aName
.isEmpty() )
291 // calculate name using source URL
293 // @@@ It's not guaranteed that slashes contained in the URL are
294 // actually path separators. This depends on the fact whether the
295 // URL is hierarchical. Only then the slashes are path separators.
296 // Therefore this algorithm is not guaranteed to work! But, ATM
297 // I don't know a better solution. It would have been better to
298 // have a member for the clashing name in
299 // UnsupportedNameClashException...
301 sal_Int32 nLastSlash
= rSourceURL
.lastIndexOf( '/' );
302 bool bTrailingSlash
= false;
303 if ( nLastSlash
== rSourceURL
.getLength() - 1 )
305 nLastSlash
= rSourceURL
.lastIndexOf( '/', nLastSlash
);
306 bTrailingSlash
= true;
309 if ( nLastSlash
!= -1 )
311 if ( bTrailingSlash
)
312 aName
= rSourceURL
.copy(
314 rSourceURL
.getLength() - nLastSlash
- 2 );
316 aName
= rSourceURL
.copy( nLastSlash
+ 1 );
323 // query, fragment present?
324 sal_Int32 nPos
= aName
.indexOf( '?' );
326 nPos
= aName
.indexOf( '#' );
329 aName
= aName
.copy( 0, nPos
);
334 OUString
createDesiredName(
335 const ucb::GlobalTransferCommandArgument
& rArg
)
337 return createDesiredName( rArg
.SourceURL
, rArg
.NewTitle
);
340 OUString
createDesiredName(
341 const ucb::TransferInfo
& rArg
)
343 return createDesiredName( rArg
.SourceURL
, rArg
.NewTitle
);
347 enum NameClashContinuation
{ NOT_HANDLED
, ABORT
, OVERWRITE
, NEW_NAME
, UNKNOWN
};
349 NameClashContinuation
interactiveNameClashResolve(
350 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
351 const OUString
& rTargetURL
,
352 const OUString
& rClashingName
,
353 /* [out] */ uno::Any
& rException
,
354 /* [out] */ OUString
& rNewName
)
356 rtl::Reference
< ucbhelper::SimpleNameClashResolveRequest
> xRequest(
357 new ucbhelper::SimpleNameClashResolveRequest(
358 rTargetURL
, // target folder URL
362 rException
= xRequest
->getRequest();
365 uno::Reference
< task::XInteractionHandler
> xIH
366 = xEnv
->getInteractionHandler();
370 xIH
->handle( xRequest
);
372 rtl::Reference
< ucbhelper::InteractionContinuation
>
373 xSelection( xRequest
->getSelection() );
375 if ( xSelection
.is() )
377 // Handler handled the request.
378 uno::Reference
< task::XInteractionAbort
> xAbort(
379 xSelection
->getXWeak(), uno::UNO_QUERY
);
388 ucb::XInteractionReplaceExistingData
>
390 xSelection
->getXWeak(), uno::UNO_QUERY
);
393 // Try again: Replace existing data.
399 ucb::XInteractionSupplyName
>
401 xSelection
->getXWeak(), uno::UNO_QUERY
);
402 if ( xSupplyName
.is() )
404 // Try again: Use new name.
405 rNewName
= xRequest
->getNewName();
410 OSL_FAIL( "Unknown interaction continuation!" );
421 /// @throws uno::RuntimeException
423 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessor
,
424 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
425 const OUString
& rNewTitle
)
429 uno::Sequence
< beans::PropertyValue
> aPropValues
{ { /* Name */ u
"Title"_ustr
,
431 /* Value */ uno::Any(rNewTitle
),
434 ucb::Command
aSetPropsCommand(
435 u
"setPropertyValues"_ustr
,
437 uno::Any( aPropValues
) );
440 = xCommandProcessor
->execute( aSetPropsCommand
, 0, xEnv
);
442 uno::Sequence
< uno::Any
> aErrors
;
445 OSL_ENSURE( aErrors
.getLength() == 1,
446 "getPropertyValues return value invalid!" );
448 if ( aErrors
[ 0 ].hasValue() )
451 OSL_FAIL( "error setting Title property!" );
455 catch ( uno::RuntimeException
const & )
459 catch ( uno::Exception
const & )
467 /// @throws uno::Exception
468 uno::Reference
< ucb::XContent
> createNew(
469 const TransferCommandContext
& rContext
,
470 const uno::Reference
< ucb::XContent
> & xTarget
,
471 bool bSourceIsFolder
,
472 bool bSourceIsDocument
,
477 // (1) Obtain creatable types from target.
480 // First, try it using "CreatabeleContentsInfo" property and
481 // "createNewContent" command -> the "new" way.
483 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessorT(
484 xTarget
, uno::UNO_QUERY
);
485 if ( !xCommandProcessorT
.is() )
487 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
489 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
491 ucbhelper::cancelCommandExecution(
492 ucb::IOErrorCode_CANT_CREATE
,
495 u
"Target is no XCommandProcessor!"_ustr
,
496 rContext
.xProcessor
);
500 uno::Sequence
< beans::Property
> aPropsToObtain
{ makeProperty(u
"CreatableContentsInfo"_ustr
, -1) };
502 ucb::Command
aGetPropsCommand(
503 u
"getPropertyValues"_ustr
,
505 uno::Any( aPropsToObtain
) );
507 uno::Reference
< sdbc::XRow
> xRow
;
508 xCommandProcessorT
->execute( aGetPropsCommand
, 0, rContext
.xEnv
) >>= xRow
;
510 uno::Sequence
< ucb::ContentInfo
> aTypesInfo
;
511 bool bGotTypesInfo
= false;
515 uno::Any aValue
= xRow
->getObject(
516 1, uno::Reference
< container::XNameAccess
>() );
517 if ( aValue
.hasValue() && ( aValue
>>= aTypesInfo
) )
519 bGotTypesInfo
= true;
523 uno::Reference
< ucb::XContentCreator
> xCreator
;
525 if ( !bGotTypesInfo
)
527 // Second, try it using XContentCreator interface -> the "old" way (not
528 // providing the chance to supply an XCommandEnvironment.
530 xCreator
.set( xTarget
, uno::UNO_QUERY
);
532 if ( !xCreator
.is() )
534 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
536 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
538 ucbhelper::cancelCommandExecution(
539 ucb::IOErrorCode_CANT_CREATE
,
542 u
"Target is no XContentCreator!"_ustr
,
543 rContext
.xProcessor
);
547 aTypesInfo
= xCreator
->queryCreatableContentsInfo();
550 if ( !aTypesInfo
.hasElements() )
552 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
554 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
556 ucbhelper::cancelCommandExecution(
557 ucb::IOErrorCode_CANT_CREATE
,
560 u
"No types creatable!"_ustr
,
561 rContext
.xProcessor
);
565 // (2) Try to find a matching target type for the source object.
567 std::function
<bool(const sal_Int32
)> lCompare
;
569 if ( rContext
.aArg
.Operation
== ucb::TransferCommandOperation_LINK
)
572 lCompare
= [](const sal_Int32 nAttribs
) { return !!( nAttribs
& ucb::ContentInfoAttribute::KIND_LINK
); };
574 else if ( ( rContext
.aArg
.Operation
== ucb::TransferCommandOperation_COPY
) ||
575 ( rContext
.aArg
.Operation
== ucb::TransferCommandOperation_MOVE
) )
578 // Is source a link? Create link in target folder then.
581 lCompare
= [](const sal_Int32 nAttribs
) { return !!( nAttribs
& ucb::ContentInfoAttribute::KIND_LINK
); };
585 // (not a and not b) or (a and b)
586 // not( a or b) or (a and b)
587 lCompare
= [bSourceIsFolder
, bSourceIsDocument
](const sal_Int32 nAttribs
) {
588 return ( bSourceIsFolder
== !!( nAttribs
& ucb::ContentInfoAttribute::KIND_FOLDER
) )
589 && ( bSourceIsDocument
== !!( nAttribs
& ucb::ContentInfoAttribute::KIND_DOCUMENT
) ) ;
595 ucbhelper::cancelCommandExecution(
596 uno::Any( lang::IllegalArgumentException(
597 u
"Unknown transfer operation!"_ustr
,
604 uno::Reference
< ucb::XContent
> xNew
;
605 auto pTypeInfo
= std::find_if(std::cbegin(aTypesInfo
), std::cend(aTypesInfo
),
606 [&lCompare
](const ucb::ContentInfo
& rTypeInfo
) { return lCompare(rTypeInfo
.Attributes
); });
607 if (pTypeInfo
!= std::cend(aTypesInfo
))
609 // (3) Create a new, empty object of matched type.
611 if ( !xCreator
.is() )
613 // First, try it using "CreatabeleContentsInfo" property and
614 // "createNewContent" command -> the "new" way.
615 ucb::Command
aCreateNewCommand(
616 u
"createNewContent"_ustr
,
618 uno::Any( *pTypeInfo
) );
620 xCommandProcessorT
->execute( aCreateNewCommand
, 0, rContext
.xEnv
)
625 // Second, try it using XContentCreator interface -> the "old"
626 // way (not providing the chance to supply an XCommandEnvironment.
628 xNew
= xCreator
->createNewContent( *pTypeInfo
);
633 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
635 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
637 ucbhelper::cancelCommandExecution(
638 ucb::IOErrorCode_CANT_CREATE
,
641 u
"createNewContent failed!"_ustr
,
642 rContext
.xProcessor
);
650 /// @throws uno::Exception
651 void transferProperties(
652 const TransferCommandContext
& rContext
,
653 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorS
,
654 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorN
)
656 ucb::Command
aGetPropertySetInfoCommand(
657 u
"getPropertySetInfo"_ustr
,
661 uno::Reference
< beans::XPropertySetInfo
> xInfo
;
662 xCommandProcessorS
->execute( aGetPropertySetInfoCommand
, 0, rContext
.xEnv
)
667 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
669 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
671 ucbhelper::cancelCommandExecution(
672 ucb::IOErrorCode_CANT_READ
,
675 u
"Unable to get propertyset info from source object!"_ustr
,
676 rContext
.xProcessor
);
680 uno::Sequence
< beans::Property
> aAllProps
= xInfo
->getProperties();
682 ucb::Command
aGetPropsCommand1(
683 u
"getPropertyValues"_ustr
,
685 uno::Any( aAllProps
) );
687 uno::Reference
< sdbc::XRow
> xRow1
;
688 xCommandProcessorS
->execute(
689 aGetPropsCommand1
, 0, rContext
.xEnv
) >>= xRow1
;
693 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
695 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
697 ucbhelper::cancelCommandExecution(
698 ucb::IOErrorCode_CANT_READ
,
701 u
"Unable to get properties from source object!"_ustr
,
702 rContext
.xProcessor
);
706 // Assemble data structure for setPropertyValues command.
708 // Note: Make room for additional Title and TargetURL too. -> + 2
709 uno::Sequence
< beans::PropertyValue
> aPropValues(
710 aAllProps
.getLength() + 2 );
711 auto pPropValues
= aPropValues
.getArray();
713 bool bHasTitle
= rContext
.aArg
.NewTitle
.isEmpty();
714 bool bHasTargetURL
= ( rContext
.aArg
.Operation
715 != ucb::TransferCommandOperation_LINK
);
717 sal_Int32 nWritePos
= 0;
718 for ( sal_Int32 m
= 0; m
< aAllProps
.getLength(); ++m
)
720 const beans::Property
& rCurrProp
= aAllProps
[ m
];
721 beans::PropertyValue
& rCurrValue
= pPropValues
[ nWritePos
];
725 if ( rCurrProp
.Name
== "Title" )
727 // Supply new title, if given.
731 aValue
<<= rContext
.aArg
.NewTitle
;
734 else if ( rCurrProp
.Name
== "TargetURL" )
736 // Supply source URL as link target for the new link to create.
737 if ( !bHasTargetURL
)
739 bHasTargetURL
= true;
740 aValue
<<= rContext
.aArg
.SourceURL
;
744 if ( !aValue
.hasValue() )
748 aValue
= xRow1
->getObject(
749 m
+ 1, uno::Reference
< container::XNameAccess
>() );
751 catch ( sdbc::SQLException
const & )
753 // Argh! But try to bring things to an end. Perhaps the
754 // mad property is not really important...
758 if ( aValue
.hasValue() )
760 rCurrValue
.Name
= rCurrProp
.Name
;
761 rCurrValue
.Handle
= rCurrProp
.Handle
;
762 rCurrValue
.Value
= std::move(aValue
);
768 // Title needed, but not set yet?
769 if ( !bHasTitle
&& !rContext
.aArg
.NewTitle
.isEmpty() )
771 pPropValues
[ nWritePos
].Name
= "Title";
772 pPropValues
[ nWritePos
].Handle
= -1;
773 pPropValues
[ nWritePos
].Value
<<= rContext
.aArg
.NewTitle
;
778 // TargetURL needed, but not set yet?
779 if ( !bHasTargetURL
&& ( rContext
.aArg
.Operation
780 == ucb::TransferCommandOperation_LINK
) )
782 pPropValues
[ nWritePos
].Name
= "TargetURL";
783 pPropValues
[ nWritePos
].Handle
= -1;
784 pPropValues
[ nWritePos
].Value
<<= rContext
.aArg
.SourceURL
;
789 aPropValues
.realloc( nWritePos
);
791 // Set properties at new object.
793 ucb::Command
aSetPropsCommand(
794 u
"setPropertyValues"_ustr
,
796 uno::Any( aPropValues
) );
798 xCommandProcessorN
->execute( aSetPropsCommand
, 0, rContext
.xEnv
);
800 // @@@ What to do with source props that are not supported by the
801 // new object? addProperty ???
804 /// @throws uno::Exception
805 uno::Reference
< io::XInputStream
> getInputStream(
806 const TransferCommandContext
& rContext
,
807 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorS
)
809 uno::Reference
< io::XInputStream
> xInputStream
;
812 // (1) Try to get data as XInputStream via XActiveDataSink.
817 uno::Reference
< io::XActiveDataSink
> xSink
= new ActiveDataSink
;
819 ucb::OpenCommandArgument2 aArg
;
820 aArg
.Mode
= ucb::OpenMode::DOCUMENT
;
821 aArg
.Priority
= 0; // unused
823 aArg
.Properties
= uno::Sequence
< beans::Property
>( 0 ); // unused
825 ucb::Command
aOpenCommand(
830 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
);
831 xInputStream
= xSink
->getInputStream();
833 catch ( uno::RuntimeException
const & )
837 catch ( uno::Exception
const & )
839 // will be handled below.
842 if ( !xInputStream
.is() )
846 // (2) Try to get data via XOutputStream.
851 uno::Reference
< io::XOutputStream
> xOutputStream( io::Pipe::create(rContext
.m_xContext
), uno::UNO_QUERY_THROW
);
853 ucb::OpenCommandArgument2 aArg
;
854 aArg
.Mode
= ucb::OpenMode::DOCUMENT
;
855 aArg
.Priority
= 0; // unused
856 aArg
.Sink
= xOutputStream
;
857 aArg
.Properties
= uno::Sequence
< beans::Property
>( 0 );
859 ucb::Command
aOpenCommand(
864 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
);
866 xInputStream
.set( xOutputStream
, uno::UNO_QUERY
);
868 catch ( uno::RuntimeException
const & )
872 catch ( uno::Exception
const & )
874 OSL_FAIL( "unable to get input stream from document!" );
881 /// @throws uno::Exception
882 uno::Reference
< sdbc::XResultSet
> getResultSet(
883 const TransferCommandContext
& rContext
,
884 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorS
)
886 uno::Reference
< sdbc::XResultSet
> xResultSet
;
888 ucb::OpenCommandArgument2 aArg
;
889 aArg
.Mode
= ucb::OpenMode::ALL
;
890 aArg
.Priority
= 0; // unused
892 aArg
.Properties
= { makeProperty(u
"IsFolder"_ustr
, -1 /* unknown */),
893 makeProperty(u
"IsDocument"_ustr
, -1 /* unknown */),
894 makeProperty(u
"TargetURL"_ustr
, -1 /* unknown */) };
896 ucb::Command
aOpenCommand( u
"open"_ustr
,
901 uno::Reference
< ucb::XDynamicResultSet
> xSet
;
902 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
) >>= xSet
;
905 xResultSet
= xSet
->getStaticResultSet();
907 catch ( uno::RuntimeException
const & )
911 catch ( uno::Exception
const & )
913 OSL_FAIL( "unable to get result set from folder!" );
919 /// @throws uno::Exception
920 void handleNameClashRename(
921 const TransferCommandContext
& rContext
,
922 const uno::Reference
< ucb::XContent
> & xNew
,
923 const uno::Reference
<
924 ucb::XCommandProcessor
> & xCommandProcessorN
,
925 const uno::Reference
<
926 ucb::XCommandProcessor
> & xCommandProcessorS
,
927 /* [inout] */ uno::Reference
< io::XInputStream
> & xInputStream
)
932 uno::Sequence
< beans::Property
> aProps
{ makeProperty(u
"Title"_ustr
, -1) };
934 ucb::Command
aGetPropsCommand(
935 u
"getPropertyValues"_ustr
,
937 uno::Any( aProps
) );
939 uno::Reference
< sdbc::XRow
> xRow
;
940 xCommandProcessorN
->execute( aGetPropsCommand
, 0, rContext
.xEnv
) >>= xRow
;
944 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
946 {"Uri", uno::Any(xNew
->getIdentifier()->getContentIdentifier())}
948 ucbhelper::cancelCommandExecution(
949 ucb::IOErrorCode_CANT_READ
,
952 u
"Unable to get properties from new object!"_ustr
,
953 rContext
.xProcessor
);
957 OUString aOldTitle
= xRow
->getString( 1 );
958 if ( aOldTitle
.isEmpty() )
960 ucbhelper::cancelCommandExecution(
961 uno::Any( beans::UnknownPropertyException(
962 u
"Unable to get property 'Title' from new object!"_ustr
,
963 rContext
.xProcessor
) ),
968 // Some pseudo-intelligence for not destroying file extensions.
969 OUString aOldTitlePre
;
970 OUString aOldTitlePost
;
971 sal_Int32 nPos
= aOldTitle
.lastIndexOf( '.' );
974 aOldTitlePre
= aOldTitle
.copy( 0, nPos
);
975 aOldTitlePost
= aOldTitle
.copy( nPos
);
978 aOldTitlePre
= aOldTitle
;
983 bool bContinue
= true;
988 OUString aNewTitle
= aOldTitlePre
+ OUString::number( nTry
) +
992 setTitle( xCommandProcessorN
, rContext
.xEnv
, aNewTitle
);
994 // Retry inserting the content.
997 // Previous try may have read from stream. Seek to begin (if
998 // optional interface XSeekable is supported) or get a new stream.
999 if ( xInputStream
.is() )
1001 uno::Reference
< io::XSeekable
> xSeekable(
1002 xInputStream
, uno::UNO_QUERY
);
1003 if ( xSeekable
.is() )
1007 xSeekable
->seek( 0 );
1009 catch ( lang::IllegalArgumentException
const & )
1011 xInputStream
.clear();
1013 catch ( io::IOException
const & )
1015 xInputStream
.clear();
1019 xInputStream
.clear();
1021 if ( !xInputStream
.is() )
1024 = getInputStream( rContext
, xCommandProcessorS
);
1025 if ( !xInputStream
.is() )
1027 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1029 {"Uri", uno::Any(xNew
->getIdentifier()->getContentIdentifier())}
1031 ucbhelper::cancelCommandExecution(
1032 ucb::IOErrorCode_CANT_READ
,
1035 u
"Got no data stream from source!"_ustr
,
1036 rContext
.xProcessor
);
1042 ucb::InsertCommandArgument2 aArg
;
1043 aArg
.Data
= xInputStream
;
1044 aArg
.ReplaceExisting
= false;
1046 ucb::Command
aInsertCommand(
1051 xCommandProcessorN
->execute( aInsertCommand
, 0, rContext
.xEnv
);
1056 catch ( uno::RuntimeException
const & )
1060 catch ( uno::Exception
const & )
1064 while ( bContinue
&& ( nTry
< 50 ) );
1068 ucbhelper::cancelCommandExecution(
1070 ucb::UnsupportedNameClashException(
1071 u
"Unable to resolve name clash!"_ustr
,
1072 rContext
.xProcessor
,
1073 ucb::NameClash::RENAME
) ),
1074 rContext
.xOrigEnv
);
1079 /// @throws uno::Exception
1080 void globalTransfer_(
1081 const TransferCommandContext
& rContext
,
1082 const uno::Reference
< ucb::XContent
> & xSource
,
1083 const uno::Reference
< ucb::XContent
> & xTarget
,
1084 const uno::Reference
< sdbc::XRow
> & xSourceProps
)
1086 // IsFolder: property is required.
1087 bool bSourceIsFolder
= xSourceProps
->getBoolean( 1 );
1088 if ( !bSourceIsFolder
&& xSourceProps
->wasNull() )
1090 ucbhelper::cancelCommandExecution(
1091 uno::Any( beans::UnknownPropertyException(
1092 u
"Unable to get property 'IsFolder' from source object!"_ustr
,
1093 rContext
.xProcessor
) ),
1094 rContext
.xOrigEnv
);
1098 // IsDocument: property is required.
1099 bool bSourceIsDocument
= xSourceProps
->getBoolean( 2 );
1100 if ( !bSourceIsDocument
&& xSourceProps
->wasNull() )
1102 ucbhelper::cancelCommandExecution(
1103 uno::Any( beans::UnknownPropertyException(
1104 u
"Unable to get property 'IsDocument' from source object!"_ustr
,
1105 rContext
.xProcessor
) ),
1106 rContext
.xOrigEnv
);
1110 // TargetURL: property is optional.
1111 bool bSourceIsLink
= !xSourceProps
->getString( 3 ).isEmpty();
1114 // (1) Try to find a matching target type for the source object and
1115 // create a new, empty object of that type.
1118 uno::Reference
< ucb::XContent
> xNew
= createNew( rContext
,
1125 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1127 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
1129 ucbhelper::cancelCommandExecution(
1130 ucb::IOErrorCode_CANT_CREATE
,
1133 u
"No matching content type at target!"_ustr
,
1134 rContext
.xProcessor
);
1139 // (2) Transfer property values from source to new object.
1142 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessorN(
1143 xNew
, uno::UNO_QUERY
);
1144 if ( !xCommandProcessorN
.is() )
1146 uno::Any
aProps(beans::PropertyValue(
1150 xNew
->getIdentifier()->
1151 getContentIdentifier()),
1152 beans::PropertyState_DIRECT_VALUE
));
1153 ucbhelper::cancelCommandExecution(
1154 ucb::IOErrorCode_CANT_WRITE
,
1155 uno::Sequence
< uno::Any
>(&aProps
, 1),
1157 u
"New content is not a XCommandProcessor!"_ustr
,
1158 rContext
.xProcessor
);
1162 // Obtain all properties from source.
1164 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessorS(
1165 xSource
, uno::UNO_QUERY
);
1166 if ( !xCommandProcessorS
.is() )
1168 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1170 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
1172 ucbhelper::cancelCommandExecution(
1173 ucb::IOErrorCode_CANT_READ
,
1176 u
"Source content is not a XCommandProcessor!"_ustr
,
1177 rContext
.xProcessor
);
1181 transferProperties( rContext
, xCommandProcessorS
, xCommandProcessorN
);
1184 // (3) Try to obtain a data stream from source.
1187 uno::Reference
< io::XInputStream
> xInputStream
;
1189 if ( bSourceIsDocument
&& ( rContext
.aArg
.Operation
1190 != ucb::TransferCommandOperation_LINK
) )
1191 xInputStream
= getInputStream( rContext
, xCommandProcessorS
);
1194 // (4) Try to obtain a resultset (children) from source.
1197 uno::Reference
< sdbc::XResultSet
> xResultSet
;
1199 if ( bSourceIsFolder
&& ( rContext
.aArg
.Operation
1200 != ucb::TransferCommandOperation_LINK
) )
1201 xResultSet
= getResultSet( rContext
, xCommandProcessorS
);
1204 // (5) Insert (store) new content.
1207 ucb::InsertCommandArgument2 aArg
;
1208 aArg
.Data
= xInputStream
;
1209 aArg
.MimeType
= rContext
.aArg
.MimeType
;
1210 aArg
.DocumentId
= rContext
.aArg
.DocumentId
;
1212 switch ( rContext
.aArg
.NameClash
)
1214 case ucb::NameClash::OVERWRITE
:
1215 aArg
.ReplaceExisting
= true;
1218 case ucb::NameClash::ERROR
:
1219 case ucb::NameClash::RENAME
:
1220 case ucb::NameClash::KEEP
: // deprecated
1221 case ucb::NameClash::ASK
:
1222 aArg
.ReplaceExisting
= false;
1226 aArg
.ReplaceExisting
= false;
1227 OSL_FAIL( "Unknown nameclash directive!" );
1231 OUString aDesiredName
= createDesiredName( rContext
.aArg
);
1240 ucb::Command
aInsertCommand(
1245 xCommandProcessorN
->execute( aInsertCommand
, 0, rContext
.xEnv
);
1247 catch ( ucb::UnsupportedNameClashException
const & exc
)
1249 OSL_ENSURE( !aArg
.ReplaceExisting
,
1250 "BUG: UnsupportedNameClashException not allowed here!" );
1252 if (exc
.NameClash
!= ucb::NameClash::ERROR
) {
1253 OSL_FAIL( "BUG: NameClash::ERROR expected!" );
1256 // No chance to solve name clashes, because I'm not able to detect
1257 // whether there is one.
1258 throw ucb::UnsupportedNameClashException(
1259 u
"Unable to resolve name clashes, no chance to detect "
1260 "that there is one!"_ustr
,
1261 rContext
.xProcessor
,
1262 rContext
.aArg
.NameClash
);
1264 catch ( ucb::NameClashException
const & )
1266 // The 'insert' command throws a NameClashException if the parameter
1267 // ReplaceExisting of the command's argument was set to false and
1268 // there exists a resource with a clashing name in the target folder
1269 // of the operation.
1271 // 'insert' command has no direct support for name clashes other
1272 // than ERROR ( ReplaceExisting == false ) and OVERWRITE
1273 // ( ReplaceExisting == true ). So we have to implement the
1274 // other name clash handling directives on top of the content.
1276 // @@@ 'insert' command should be extended that it accepts a
1277 // name clash handling directive, exactly like 'transfer' command.
1279 switch ( rContext
.aArg
.NameClash
)
1281 case ucb::NameClash::OVERWRITE
:
1283 ucbhelper::cancelCommandExecution(
1285 ucb::UnsupportedNameClashException(
1286 u
"BUG: insert + replace == true MUST NOT "
1287 "throw NameClashException."_ustr
,
1288 rContext
.xProcessor
,
1289 rContext
.aArg
.NameClash
) ),
1290 rContext
.xOrigEnv
);
1291 [[fallthrough
]]; // Unreachable
1294 case ucb::NameClash::ERROR
:
1297 case ucb::NameClash::RENAME
:
1299 // "invent" a new valid title.
1300 handleNameClashRename( rContext
,
1308 case ucb::NameClash::ASK
:
1312 NameClashContinuation eCont
1313 = interactiveNameClashResolve(
1314 rContext
.xOrigEnv
, // always use original environment!
1315 rContext
.aArg
.TargetURL
, // target folder URL
1324 cppu::throwException( aExc
);
1325 [[fallthrough
]]; // break;
1328 // Handled, but not clear, how...
1329 // fall through intended.
1332 throw ucb::CommandFailedException(
1333 u
"abort requested via interaction "
1335 uno::Reference
< uno::XInterface
>(),
1340 OSL_ENSURE( !aArg
.ReplaceExisting
,
1341 "Hu? ReplaceExisting already true?"
1343 aArg
.ReplaceExisting
= true;
1349 // set new name -> set "Title" property...
1350 if ( setTitle( xCommandProcessorN
,
1354 // remember suggested title...
1355 aDesiredName
= aNewTitle
;
1357 // ... and try again.
1362 // error setting title. Abort.
1363 throw ucb::CommandFailedException(
1364 u
"error setting Title property!"_ustr
,
1365 uno::Reference
< uno::XInterface
>(),
1372 OSL_ENSURE( bRetry
, "bRetry must be true here!!!" );
1376 case ucb::NameClash::KEEP
: // deprecated
1379 ucbhelper::cancelCommandExecution(
1381 ucb::UnsupportedNameClashException(
1382 u
"default action, don't know how to "
1383 "handle name clash"_ustr
,
1384 rContext
.xProcessor
,
1385 rContext
.aArg
.NameClash
) ),
1386 rContext
.xOrigEnv
);
1395 // (6) Process children of source.
1398 if ( xResultSet
.is() )
1402 // Iterate over children...
1404 uno::Reference
< sdbc::XRow
> xChildRow(
1405 xResultSet
, uno::UNO_QUERY
);
1407 if ( !xChildRow
.is() )
1410 beans::PropertyValue(
1413 uno::Any(rContext
.aArg
.SourceURL
),
1414 beans::PropertyState_DIRECT_VALUE
));
1415 ucbhelper::cancelCommandExecution(
1416 ucb::IOErrorCode_CANT_READ
,
1417 uno::Sequence
< uno::Any
>(&aProps
, 1),
1419 u
"Unable to get properties from children of source!"_ustr
,
1420 rContext
.xProcessor
);
1424 uno::Reference
< ucb::XContentAccess
> xChildAccess(
1425 xResultSet
, uno::UNO_QUERY
);
1427 if ( !xChildAccess
.is() )
1429 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1431 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
1433 ucbhelper::cancelCommandExecution(
1434 ucb::IOErrorCode_CANT_READ
,
1437 u
"Unable to get children of source!"_ustr
,
1438 rContext
.xProcessor
);
1442 if ( xResultSet
->first() )
1444 ucb::GlobalTransferCommandArgument2
aTransArg(
1445 rContext
.aArg
.Operation
,
1446 OUString(), // SourceURL; filled later
1447 xNew
->getIdentifier()
1448 ->getContentIdentifier(), // TargetURL
1449 OUString(), // NewTitle;
1450 rContext
.aArg
.NameClash
,
1451 rContext
.aArg
.MimeType
,
1452 rContext
.aArg
.DocumentId
);
1454 TransferCommandContext
aSubCtx(
1455 rContext
.m_xContext
,
1456 rContext
.xProcessor
,
1459 std::move(aTransArg
) );
1462 uno::Reference
< ucb::XContent
> xChild
1463 = xChildAccess
->queryContent();
1468 aSubCtx
.aArg
.SourceURL
1469 = xChild
->getIdentifier()->getContentIdentifier();
1471 globalTransfer_( aSubCtx
,
1477 while ( xResultSet
->next() );
1480 catch ( sdbc::SQLException
const & )
1486 uno::Reference
< ucb::XCommandProcessor
> xcp(
1487 xTarget
, uno::UNO_QUERY
);
1490 uno::Reference
< ucb::XCommandInfo
> xci
;
1495 u
"getCommandInfo"_ustr
,
1501 static constexpr OUString
cmdName(u
"flush"_ustr
);
1502 if((aAny
>>= xci
) && xci
->hasCommandByName(cmdName
))
1511 catch( uno::Exception
const & )
1519 // UniversalContentBroker implementation ( XCommandProcessor commands ).
1522 uno::Reference
< ucb::XCommandInfo
>
1523 UniversalContentBroker::getCommandInfo()
1525 return uno::Reference
< ucb::XCommandInfo
>( new CommandProcessorInfo() );
1529 void UniversalContentBroker::globalTransfer(
1530 const ucb::GlobalTransferCommandArgument2
& rArg
,
1531 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1533 // Use own command environment with own interaction handler intercepting
1534 // some interaction requests that shall not be handled by the user-supplied
1535 // interaction handler.
1536 uno::Reference
< ucb::XCommandEnvironment
> xLocalEnv
;
1539 xLocalEnv
.set( ucb::CommandEnvironment::create(
1541 new InteractionHandlerProxy( xEnv
->getInteractionHandler() ),
1542 xEnv
->getProgressHandler() ) );
1546 // (1) Try to transfer the content using 'transfer' command.
1549 uno::Reference
< ucb::XContent
> xTarget
;
1550 uno::Reference
< ucb::XContentIdentifier
> xId
1551 = createContentIdentifier( rArg
.TargetURL
);
1556 xTarget
= queryContent( xId
);
1558 catch ( ucb::IllegalIdentifierException
const & )
1563 if ( !xTarget
.is() )
1565 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1567 {"Uri", uno::Any(rArg
.TargetURL
)}
1569 ucbhelper::cancelCommandExecution(
1570 ucb::IOErrorCode_CANT_READ
,
1573 u
"Can't instantiate target object!"_ustr
,
1578 if ( ( rArg
.Operation
== ucb::TransferCommandOperation_COPY
) ||
1579 ( rArg
.Operation
== ucb::TransferCommandOperation_MOVE
) )
1581 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1582 xTarget
, uno::UNO_QUERY
);
1583 if ( !xCommandProcessor
.is() )
1585 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1587 {"Uri", uno::Any(rArg
.TargetURL
)}
1589 ucbhelper::cancelCommandExecution(
1590 ucb::IOErrorCode_CANT_READ
,
1593 u
"Target content is not a XCommandProcessor!"_ustr
,
1598 ucb::TransferInfo2
aTransferArg(
1600 == ucb::TransferCommandOperation_MOVE
), // MoveData
1613 ucb::Command
aCommand(
1614 u
"transfer"_ustr
, // Name
1616 uno::Any( aTransferArg
) ); // Argument
1618 xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1620 // Command succeeded. We're done.
1623 catch ( ucb::InteractiveBadTransferURLException
const & )
1625 // Source URL is not supported by target. Try to transfer
1626 // the content "manually".
1628 catch ( ucb::UnsupportedCommandException
const & )
1630 // 'transfer' command is not supported by commandprocessor.
1631 // Try to transfer manually.
1633 catch ( ucb::UnsupportedNameClashException
const & exc
)
1635 OSL_ENSURE( aTransferArg
.NameClash
== exc
.NameClash
,
1636 "nameclash mismatch!" );
1637 if ( exc
.NameClash
== ucb::NameClash::ASK
)
1639 // Try to detect a name clash by invoking "transfer" with
1640 // NameClash::ERROR.
1643 ucb::TransferInfo2
aTransferArg1(
1644 aTransferArg
.MoveData
,
1645 aTransferArg
.SourceURL
,
1646 aTransferArg
.NewTitle
,
1647 ucb::NameClash::ERROR
,
1648 aTransferArg
.MimeType
);
1650 ucb::Command
aCommand1(
1653 uno::Any( aTransferArg1
) );
1655 xCommandProcessor
->execute( aCommand1
, 0, xLocalEnv
);
1657 // Command succeeded. We're done.
1660 catch ( ucb::UnsupportedNameClashException
const & )
1662 // No chance to solve name clashes, because I'm not
1663 // able to detect whether there is one.
1664 throw exc
; // Not just 'throw;'!
1666 catch ( ucb::NameClashException
const & )
1668 // There's a clash. Use interaction handler to solve it.
1672 NameClashContinuation eCont
1673 = interactiveNameClashResolve(
1674 xEnv
, // always use original environment!
1675 rArg
.TargetURL
, // target folder URL
1677 aTransferArg
), // clashing name
1685 cppu::throwException( aExc
);
1686 [[fallthrough
]]; // break;
1689 // Handled, but not clear, how...
1690 // fall through intended.
1693 throw ucb::CommandFailedException(
1694 u
"abort requested via interaction "
1696 uno::Reference
< uno::XInterface
>(),
1701 aTransferArg
.NameClash
1702 = ucb::NameClash::OVERWRITE
;
1707 aTransferArg
.NewTitle
= aNewTitle
;
1712 OSL_ENSURE( bRetry
, "bRetry must be true here!!!" );
1725 // (2) Try to transfer the content "manually".
1728 uno::Reference
< ucb::XContent
> xSource
;
1731 uno::Reference
< ucb::XContentIdentifier
> xId2
1732 = createContentIdentifier( rArg
.SourceURL
);
1734 xSource
= queryContent( xId2
);
1736 catch ( ucb::IllegalIdentifierException
const & )
1738 // Error handling via "if ( !xSource.is() )" below.
1741 if ( !xSource
.is() )
1743 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1745 {"Uri", uno::Any(rArg
.SourceURL
)}
1747 ucbhelper::cancelCommandExecution(
1748 ucb::IOErrorCode_CANT_READ
,
1751 u
"Can't instantiate source object!"_ustr
,
1756 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1757 xSource
, uno::UNO_QUERY
);
1758 if ( !xCommandProcessor
.is() )
1760 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1762 {"Uri", uno::Any(rArg
.SourceURL
)}
1764 ucbhelper::cancelCommandExecution(
1765 ucb::IOErrorCode_CANT_READ
,
1768 u
"Source content is not a XCommandProcessor!"_ustr
,
1773 // Obtain interesting property values from source...
1775 uno::Sequence
< beans::Property
> aProps
{ makeProperty(u
"IsFolder"_ustr
, -1 /* unknown */),
1776 makeProperty(u
"IsDocument"_ustr
, -1 /* unknown */),
1777 makeProperty(u
"TargetURL"_ustr
, -1 /* unknown */),
1778 makeProperty(u
"BaseURI"_ustr
, -1 /* unknown */) };
1780 ucb::Command
aGetPropsCommand(
1781 u
"getPropertyValues"_ustr
,
1783 uno::Any( aProps
) );
1785 uno::Reference
< sdbc::XRow
> xRow
;
1786 xCommandProcessor
->execute( aGetPropsCommand
, 0, xLocalEnv
) >>= xRow
;
1790 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1792 {"Uri", uno::Any(rArg
.SourceURL
)}
1794 ucbhelper::cancelCommandExecution(
1795 ucb::IOErrorCode_CANT_READ
,
1798 u
"Unable to get properties from source object!"_ustr
,
1803 TransferCommandContext
aTransferCtx(
1804 m_xContext
, this, xLocalEnv
, xEnv
, rArg
);
1806 if ( rArg
.NewTitle
.isEmpty() )
1808 // BaseURI: property is optional.
1809 OUString
aBaseURI( xRow
->getString( 4 ) );
1810 if ( !aBaseURI
.isEmpty() )
1812 aTransferCtx
.aArg
.NewTitle
1813 = createDesiredName( aBaseURI
, OUString() );
1818 globalTransfer_( aTransferCtx
, xSource
, xTarget
, xRow
);
1821 // (3) Delete source, if operation is MOVE.
1824 if ( rArg
.Operation
!= ucb::TransferCommandOperation_MOVE
)
1829 ucb::Command
aCommand(
1830 u
"delete"_ustr
, // Name
1832 uno::Any( true ) ); // Argument
1834 xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1836 catch ( uno::Exception
const & )
1838 OSL_FAIL( "Cannot delete source object!" );
1843 uno::Any
UniversalContentBroker::checkIn( const ucb::CheckinArgument
& rArg
,
1844 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1847 // Use own command environment with own interaction handler intercepting
1848 // some interaction requests that shall not be handled by the user-supplied
1849 // interaction handler.
1850 uno::Reference
< ucb::XCommandEnvironment
> xLocalEnv
;
1853 xLocalEnv
.set( ucb::CommandEnvironment::create(
1855 new InteractionHandlerProxy( xEnv
->getInteractionHandler() ),
1856 xEnv
->getProgressHandler() ) );
1859 uno::Reference
< ucb::XContent
> xTarget
;
1860 uno::Reference
< ucb::XContentIdentifier
> xId
1861 = createContentIdentifier( rArg
.TargetURL
);
1866 xTarget
= queryContent( xId
);
1868 catch ( ucb::IllegalIdentifierException
const & )
1873 if ( !xTarget
.is() )
1875 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1877 {"Uri", uno::Any(rArg
.TargetURL
)}
1879 ucbhelper::cancelCommandExecution(
1880 ucb::IOErrorCode_CANT_READ
,
1883 u
"Can't instantiate target object!"_ustr
,
1888 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1889 xTarget
, uno::UNO_QUERY
);
1890 if ( !xCommandProcessor
.is() )
1892 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1894 {"Uri", uno::Any(rArg
.TargetURL
)}
1896 ucbhelper::cancelCommandExecution(
1897 ucb::IOErrorCode_CANT_READ
,
1900 u
"Target content is not a XCommandProcessor!"_ustr
,
1907 ucb::Command
aCommand(
1908 u
"checkin"_ustr
, -1,
1911 aRet
= xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1913 catch ( ucb::UnsupportedCommandException
const & )
1915 // 'checkin' command is not supported by commandprocessor:
1921 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */