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
.get(), uno::UNO_QUERY
);
388 ucb::XInteractionReplaceExistingData
>
390 xSelection
.get(), uno::UNO_QUERY
);
393 // Try again: Replace existing data.
399 ucb::XInteractionSupplyName
>
401 xSelection
.get(), 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 */ "Title",
431 /* Value */ uno::Any(rNewTitle
),
434 ucb::Command
aSetPropsCommand(
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 "Target is no XCommandProcessor!",
496 rContext
.xProcessor
);
500 uno::Sequence
< beans::Property
> aPropsToObtain
{ makeProperty("CreatableContentsInfo", -1) };
502 ucb::Command
aGetPropsCommand(
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 "Target is no XContentCreator!",
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 "No types creatable!",
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 "Unknown transfer operation!",
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(
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 "createNewContent failed!",
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 "getPropertySetInfo",
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 "Unable to get propertyset info from source object!",
676 rContext
.xProcessor
);
680 uno::Sequence
< beans::Property
> aAllProps
= xInfo
->getProperties();
682 ucb::Command
aGetPropsCommand1(
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 "Unable to get properties from source object!",
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
= aValue
;
763 // rCurrValue.State =
769 // Title needed, but not set yet?
770 if ( !bHasTitle
&& !rContext
.aArg
.NewTitle
.isEmpty() )
772 pPropValues
[ nWritePos
].Name
= "Title";
773 pPropValues
[ nWritePos
].Handle
= -1;
774 pPropValues
[ nWritePos
].Value
<<= rContext
.aArg
.NewTitle
;
779 // TargetURL needed, but not set yet?
780 if ( !bHasTargetURL
&& ( rContext
.aArg
.Operation
781 == ucb::TransferCommandOperation_LINK
) )
783 pPropValues
[ nWritePos
].Name
= "TargetURL";
784 pPropValues
[ nWritePos
].Handle
= -1;
785 pPropValues
[ nWritePos
].Value
<<= rContext
.aArg
.SourceURL
;
790 aPropValues
.realloc( nWritePos
);
792 // Set properties at new object.
794 ucb::Command
aSetPropsCommand(
797 uno::Any( aPropValues
) );
799 xCommandProcessorN
->execute( aSetPropsCommand
, 0, rContext
.xEnv
);
801 // @@@ What to do with source props that are not supported by the
802 // new object? addProperty ???
805 /// @throws uno::Exception
806 uno::Reference
< io::XInputStream
> getInputStream(
807 const TransferCommandContext
& rContext
,
808 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorS
)
810 uno::Reference
< io::XInputStream
> xInputStream
;
813 // (1) Try to get data as XInputStream via XActiveDataSink.
818 uno::Reference
< io::XActiveDataSink
> xSink
= new ActiveDataSink
;
820 ucb::OpenCommandArgument2 aArg
;
821 aArg
.Mode
= ucb::OpenMode::DOCUMENT
;
822 aArg
.Priority
= 0; // unused
824 aArg
.Properties
= uno::Sequence
< beans::Property
>( 0 ); // unused
826 ucb::Command
aOpenCommand(
831 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
);
832 xInputStream
= xSink
->getInputStream();
834 catch ( uno::RuntimeException
const & )
838 catch ( uno::Exception
const & )
840 // will be handled below.
843 if ( !xInputStream
.is() )
847 // (2) Try to get data via XOutputStream.
852 uno::Reference
< io::XOutputStream
> xOutputStream( io::Pipe::create(rContext
.m_xContext
), uno::UNO_QUERY_THROW
);
854 ucb::OpenCommandArgument2 aArg
;
855 aArg
.Mode
= ucb::OpenMode::DOCUMENT
;
856 aArg
.Priority
= 0; // unused
857 aArg
.Sink
= xOutputStream
;
858 aArg
.Properties
= uno::Sequence
< beans::Property
>( 0 );
860 ucb::Command
aOpenCommand(
865 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
);
867 xInputStream
.set( xOutputStream
, uno::UNO_QUERY
);
869 catch ( uno::RuntimeException
const & )
873 catch ( uno::Exception
const & )
875 OSL_FAIL( "unable to get input stream from document!" );
882 /// @throws uno::Exception
883 uno::Reference
< sdbc::XResultSet
> getResultSet(
884 const TransferCommandContext
& rContext
,
885 const uno::Reference
< ucb::XCommandProcessor
> & xCommandProcessorS
)
887 uno::Reference
< sdbc::XResultSet
> xResultSet
;
889 uno::Sequence
< beans::Property
> aProps
{ makeProperty("IsFolder", -1 /* unknown */),
890 makeProperty("IsDocument", -1 /* unknown */),
891 makeProperty("TargetURL", -1 /* unknown */) };
893 ucb::OpenCommandArgument2 aArg
;
894 aArg
.Mode
= ucb::OpenMode::ALL
;
895 aArg
.Priority
= 0; // unused
897 aArg
.Properties
= aProps
;
899 ucb::Command
aOpenCommand( "open",
904 uno::Reference
< ucb::XDynamicResultSet
> xSet
;
905 xCommandProcessorS
->execute( aOpenCommand
, 0, rContext
.xEnv
) >>= xSet
;
908 xResultSet
= xSet
->getStaticResultSet();
910 catch ( uno::RuntimeException
const & )
914 catch ( uno::Exception
const & )
916 OSL_FAIL( "unable to get result set from folder!" );
922 /// @throws uno::Exception
923 void handleNameClashRename(
924 const TransferCommandContext
& rContext
,
925 const uno::Reference
< ucb::XContent
> & xNew
,
926 const uno::Reference
<
927 ucb::XCommandProcessor
> & xCommandProcessorN
,
928 const uno::Reference
<
929 ucb::XCommandProcessor
> & xCommandProcessorS
,
930 /* [inout] */ uno::Reference
< io::XInputStream
> & xInputStream
)
935 uno::Sequence
< beans::Property
> aProps
{ makeProperty("Title", -1) };
937 ucb::Command
aGetPropsCommand(
940 uno::Any( aProps
) );
942 uno::Reference
< sdbc::XRow
> xRow
;
943 xCommandProcessorN
->execute( aGetPropsCommand
, 0, rContext
.xEnv
) >>= xRow
;
947 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
949 {"Uri", uno::Any(xNew
->getIdentifier()->getContentIdentifier())}
951 ucbhelper::cancelCommandExecution(
952 ucb::IOErrorCode_CANT_READ
,
955 "Unable to get properties from new object!",
956 rContext
.xProcessor
);
960 OUString aOldTitle
= xRow
->getString( 1 );
961 if ( aOldTitle
.isEmpty() )
963 ucbhelper::cancelCommandExecution(
964 uno::Any( beans::UnknownPropertyException(
965 "Unable to get property 'Title' from new object!",
966 rContext
.xProcessor
) ),
971 // Some pseudo-intelligence for not destroying file extensions.
972 OUString aOldTitlePre
;
973 OUString aOldTitlePost
;
974 sal_Int32 nPos
= aOldTitle
.lastIndexOf( '.' );
977 aOldTitlePre
= aOldTitle
.copy( 0, nPos
);
978 aOldTitlePost
= aOldTitle
.copy( nPos
);
981 aOldTitlePre
= aOldTitle
;
986 bool bContinue
= true;
991 OUString aNewTitle
= aOldTitlePre
+ OUString::number( nTry
) +
995 setTitle( xCommandProcessorN
, rContext
.xEnv
, aNewTitle
);
997 // Retry inserting the content.
1000 // Previous try may have read from stream. Seek to begin (if
1001 // optional interface XSeekable is supported) or get a new stream.
1002 if ( xInputStream
.is() )
1004 uno::Reference
< io::XSeekable
> xSeekable(
1005 xInputStream
, uno::UNO_QUERY
);
1006 if ( xSeekable
.is() )
1010 xSeekable
->seek( 0 );
1012 catch ( lang::IllegalArgumentException
const & )
1014 xInputStream
.clear();
1016 catch ( io::IOException
const & )
1018 xInputStream
.clear();
1022 xInputStream
.clear();
1024 if ( !xInputStream
.is() )
1027 = getInputStream( rContext
, xCommandProcessorS
);
1028 if ( !xInputStream
.is() )
1030 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1032 {"Uri", uno::Any(xNew
->getIdentifier()->getContentIdentifier())}
1034 ucbhelper::cancelCommandExecution(
1035 ucb::IOErrorCode_CANT_READ
,
1038 "Got no data stream from source!",
1039 rContext
.xProcessor
);
1045 ucb::InsertCommandArgument2 aArg
;
1046 aArg
.Data
= xInputStream
;
1047 aArg
.ReplaceExisting
= false;
1049 ucb::Command
aInsertCommand(
1054 xCommandProcessorN
->execute( aInsertCommand
, 0, rContext
.xEnv
);
1059 catch ( uno::RuntimeException
const & )
1063 catch ( uno::Exception
const & )
1067 while ( bContinue
&& ( nTry
< 50 ) );
1071 ucbhelper::cancelCommandExecution(
1073 ucb::UnsupportedNameClashException(
1074 "Unable to resolve name clash!",
1075 rContext
.xProcessor
,
1076 ucb::NameClash::RENAME
) ),
1077 rContext
.xOrigEnv
);
1082 /// @throws uno::Exception
1083 void globalTransfer_(
1084 const TransferCommandContext
& rContext
,
1085 const uno::Reference
< ucb::XContent
> & xSource
,
1086 const uno::Reference
< ucb::XContent
> & xTarget
,
1087 const uno::Reference
< sdbc::XRow
> & xSourceProps
)
1089 // IsFolder: property is required.
1090 bool bSourceIsFolder
= xSourceProps
->getBoolean( 1 );
1091 if ( !bSourceIsFolder
&& xSourceProps
->wasNull() )
1093 ucbhelper::cancelCommandExecution(
1094 uno::Any( beans::UnknownPropertyException(
1095 "Unable to get property 'IsFolder' from source object!",
1096 rContext
.xProcessor
) ),
1097 rContext
.xOrigEnv
);
1101 // IsDocument: property is required.
1102 bool bSourceIsDocument
= xSourceProps
->getBoolean( 2 );
1103 if ( !bSourceIsDocument
&& xSourceProps
->wasNull() )
1105 ucbhelper::cancelCommandExecution(
1106 uno::Any( beans::UnknownPropertyException(
1107 "Unable to get property 'IsDocument' from source object!",
1108 rContext
.xProcessor
) ),
1109 rContext
.xOrigEnv
);
1113 // TargetURL: property is optional.
1114 bool bSourceIsLink
= !xSourceProps
->getString( 3 ).isEmpty();
1117 // (1) Try to find a matching target type for the source object and
1118 // create a new, empty object of that type.
1121 uno::Reference
< ucb::XContent
> xNew
= createNew( rContext
,
1128 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1130 {"Folder", uno::Any(rContext
.aArg
.TargetURL
)}
1132 ucbhelper::cancelCommandExecution(
1133 ucb::IOErrorCode_CANT_CREATE
,
1136 "No matching content type at target!",
1137 rContext
.xProcessor
);
1142 // (2) Transfer property values from source to new object.
1145 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessorN(
1146 xNew
, uno::UNO_QUERY
);
1147 if ( !xCommandProcessorN
.is() )
1149 uno::Any
aProps(beans::PropertyValue(
1153 xNew
->getIdentifier()->
1154 getContentIdentifier()),
1155 beans::PropertyState_DIRECT_VALUE
));
1156 ucbhelper::cancelCommandExecution(
1157 ucb::IOErrorCode_CANT_WRITE
,
1158 uno::Sequence
< uno::Any
>(&aProps
, 1),
1160 "New content is not a XCommandProcessor!",
1161 rContext
.xProcessor
);
1165 // Obtain all properties from source.
1167 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessorS(
1168 xSource
, uno::UNO_QUERY
);
1169 if ( !xCommandProcessorS
.is() )
1171 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1173 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
1175 ucbhelper::cancelCommandExecution(
1176 ucb::IOErrorCode_CANT_READ
,
1179 "Source content is not a XCommandProcessor!",
1180 rContext
.xProcessor
);
1184 transferProperties( rContext
, xCommandProcessorS
, xCommandProcessorN
);
1187 // (3) Try to obtain a data stream from source.
1190 uno::Reference
< io::XInputStream
> xInputStream
;
1192 if ( bSourceIsDocument
&& ( rContext
.aArg
.Operation
1193 != ucb::TransferCommandOperation_LINK
) )
1194 xInputStream
= getInputStream( rContext
, xCommandProcessorS
);
1197 // (4) Try to obtain a resultset (children) from source.
1200 uno::Reference
< sdbc::XResultSet
> xResultSet
;
1202 if ( bSourceIsFolder
&& ( rContext
.aArg
.Operation
1203 != ucb::TransferCommandOperation_LINK
) )
1204 xResultSet
= getResultSet( rContext
, xCommandProcessorS
);
1207 // (5) Insert (store) new content.
1210 ucb::InsertCommandArgument2 aArg
;
1211 aArg
.Data
= xInputStream
;
1212 aArg
.MimeType
= rContext
.aArg
.MimeType
;
1213 aArg
.DocumentId
= rContext
.aArg
.DocumentId
;
1215 switch ( rContext
.aArg
.NameClash
)
1217 case ucb::NameClash::OVERWRITE
:
1218 aArg
.ReplaceExisting
= true;
1221 case ucb::NameClash::ERROR
:
1222 case ucb::NameClash::RENAME
:
1223 case ucb::NameClash::KEEP
: // deprecated
1224 case ucb::NameClash::ASK
:
1225 aArg
.ReplaceExisting
= false;
1229 aArg
.ReplaceExisting
= false;
1230 OSL_FAIL( "Unknown nameclash directive!" );
1234 OUString aDesiredName
= createDesiredName( rContext
.aArg
);
1243 ucb::Command
aInsertCommand(
1248 xCommandProcessorN
->execute( aInsertCommand
, 0, rContext
.xEnv
);
1250 catch ( ucb::UnsupportedNameClashException
const & exc
)
1252 OSL_ENSURE( !aArg
.ReplaceExisting
,
1253 "BUG: UnsupportedNameClashException not allowed here!" );
1255 if (exc
.NameClash
!= ucb::NameClash::ERROR
) {
1256 OSL_FAIL( "BUG: NameClash::ERROR expected!" );
1259 // No chance to solve name clashes, because I'm not able to detect
1260 // whether there is one.
1261 throw ucb::UnsupportedNameClashException(
1262 "Unable to resolve name clashes, no chance to detect "
1263 "that there is one!",
1264 rContext
.xProcessor
,
1265 rContext
.aArg
.NameClash
);
1267 catch ( ucb::NameClashException
const & )
1269 // The 'insert' command throws a NameClashException if the parameter
1270 // ReplaceExisting of the command's argument was set to false and
1271 // there exists a resource with a clashing name in the target folder
1272 // of the operation.
1274 // 'insert' command has no direct support for name clashes other
1275 // than ERROR ( ReplaceExisting == false ) and OVERWRITE
1276 // ( ReplaceExisting == true ). So we have to implement the
1277 // other name clash handling directives on top of the content.
1279 // @@@ 'insert' command should be extended that it accepts a
1280 // name clash handling directive, exactly like 'transfer' command.
1282 switch ( rContext
.aArg
.NameClash
)
1284 case ucb::NameClash::OVERWRITE
:
1286 ucbhelper::cancelCommandExecution(
1288 ucb::UnsupportedNameClashException(
1289 "BUG: insert + replace == true MUST NOT "
1290 "throw NameClashException.",
1291 rContext
.xProcessor
,
1292 rContext
.aArg
.NameClash
) ),
1293 rContext
.xOrigEnv
);
1294 [[fallthrough
]]; // Unreachable
1297 case ucb::NameClash::ERROR
:
1300 case ucb::NameClash::RENAME
:
1302 // "invent" a new valid title.
1303 handleNameClashRename( rContext
,
1311 case ucb::NameClash::ASK
:
1315 NameClashContinuation eCont
1316 = interactiveNameClashResolve(
1317 rContext
.xOrigEnv
, // always use original environment!
1318 rContext
.aArg
.TargetURL
, // target folder URL
1327 cppu::throwException( aExc
);
1328 [[fallthrough
]]; // break;
1331 // Handled, but not clear, how...
1332 // fall through intended.
1335 throw ucb::CommandFailedException(
1336 "abort requested via interaction "
1338 uno::Reference
< uno::XInterface
>(),
1343 OSL_ENSURE( !aArg
.ReplaceExisting
,
1344 "Hu? ReplaceExisting already true?"
1346 aArg
.ReplaceExisting
= true;
1352 // set new name -> set "Title" property...
1353 if ( setTitle( xCommandProcessorN
,
1357 // remember suggested title...
1358 aDesiredName
= aNewTitle
;
1360 // ... and try again.
1365 // error setting title. Abort.
1366 throw ucb::CommandFailedException(
1367 "error setting Title property!",
1368 uno::Reference
< uno::XInterface
>(),
1375 OSL_ENSURE( bRetry
, "bRetry must be true here!!!" );
1379 case ucb::NameClash::KEEP
: // deprecated
1382 ucbhelper::cancelCommandExecution(
1384 ucb::UnsupportedNameClashException(
1385 "default action, don't know how to "
1386 "handle name clash",
1387 rContext
.xProcessor
,
1388 rContext
.aArg
.NameClash
) ),
1389 rContext
.xOrigEnv
);
1398 // (6) Process children of source.
1401 if ( xResultSet
.is() )
1405 // Iterate over children...
1407 uno::Reference
< sdbc::XRow
> xChildRow(
1408 xResultSet
, uno::UNO_QUERY
);
1410 if ( !xChildRow
.is() )
1413 beans::PropertyValue(
1416 uno::Any(rContext
.aArg
.SourceURL
),
1417 beans::PropertyState_DIRECT_VALUE
));
1418 ucbhelper::cancelCommandExecution(
1419 ucb::IOErrorCode_CANT_READ
,
1420 uno::Sequence
< uno::Any
>(&aProps
, 1),
1422 "Unable to get properties from children of source!",
1423 rContext
.xProcessor
);
1427 uno::Reference
< ucb::XContentAccess
> xChildAccess(
1428 xResultSet
, uno::UNO_QUERY
);
1430 if ( !xChildAccess
.is() )
1432 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1434 {"Uri", uno::Any(rContext
.aArg
.SourceURL
)}
1436 ucbhelper::cancelCommandExecution(
1437 ucb::IOErrorCode_CANT_READ
,
1440 "Unable to get children of source!",
1441 rContext
.xProcessor
);
1445 if ( xResultSet
->first() )
1447 ucb::GlobalTransferCommandArgument2
aTransArg(
1448 rContext
.aArg
.Operation
,
1449 OUString(), // SourceURL; filled later
1450 xNew
->getIdentifier()
1451 ->getContentIdentifier(), // TargetURL
1452 OUString(), // NewTitle;
1453 rContext
.aArg
.NameClash
,
1454 rContext
.aArg
.MimeType
,
1455 rContext
.aArg
.DocumentId
);
1457 TransferCommandContext
aSubCtx(
1458 rContext
.m_xContext
,
1459 rContext
.xProcessor
,
1462 std::move(aTransArg
) );
1465 uno::Reference
< ucb::XContent
> xChild
1466 = xChildAccess
->queryContent();
1471 aSubCtx
.aArg
.SourceURL
1472 = xChild
->getIdentifier()->getContentIdentifier();
1474 globalTransfer_( aSubCtx
,
1480 while ( xResultSet
->next() );
1483 catch ( sdbc::SQLException
const & )
1489 uno::Reference
< ucb::XCommandProcessor
> xcp(
1490 xTarget
, uno::UNO_QUERY
);
1493 uno::Reference
< ucb::XCommandInfo
> xci
;
1504 static const OUStringLiteral
cmdName(u
"flush");
1505 if((aAny
>>= xci
) && xci
->hasCommandByName(cmdName
))
1514 catch( uno::Exception
const & )
1522 // UniversalContentBroker implementation ( XCommandProcessor commands ).
1525 uno::Reference
< ucb::XCommandInfo
>
1526 UniversalContentBroker::getCommandInfo()
1528 return uno::Reference
< ucb::XCommandInfo
>( new CommandProcessorInfo() );
1532 void UniversalContentBroker::globalTransfer(
1533 const ucb::GlobalTransferCommandArgument2
& rArg
,
1534 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1536 // Use own command environment with own interaction handler intercepting
1537 // some interaction requests that shall not be handled by the user-supplied
1538 // interaction handler.
1539 uno::Reference
< ucb::XCommandEnvironment
> xLocalEnv
;
1542 xLocalEnv
.set( ucb::CommandEnvironment::create(
1544 new InteractionHandlerProxy( xEnv
->getInteractionHandler() ),
1545 xEnv
->getProgressHandler() ) );
1549 // (1) Try to transfer the content using 'transfer' command.
1552 uno::Reference
< ucb::XContent
> xTarget
;
1553 uno::Reference
< ucb::XContentIdentifier
> xId
1554 = createContentIdentifier( rArg
.TargetURL
);
1559 xTarget
= queryContent( xId
);
1561 catch ( ucb::IllegalIdentifierException
const & )
1566 if ( !xTarget
.is() )
1568 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1570 {"Uri", uno::Any(rArg
.TargetURL
)}
1572 ucbhelper::cancelCommandExecution(
1573 ucb::IOErrorCode_CANT_READ
,
1576 "Can't instantiate target object!",
1581 if ( ( rArg
.Operation
== ucb::TransferCommandOperation_COPY
) ||
1582 ( rArg
.Operation
== ucb::TransferCommandOperation_MOVE
) )
1584 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1585 xTarget
, uno::UNO_QUERY
);
1586 if ( !xCommandProcessor
.is() )
1588 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1590 {"Uri", uno::Any(rArg
.TargetURL
)}
1592 ucbhelper::cancelCommandExecution(
1593 ucb::IOErrorCode_CANT_READ
,
1596 "Target content is not a XCommandProcessor!",
1601 ucb::TransferInfo2
aTransferArg(
1603 == ucb::TransferCommandOperation_MOVE
), // MoveData
1616 ucb::Command
aCommand(
1619 uno::Any( aTransferArg
) ); // Argument
1621 xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1623 // Command succeeded. We're done.
1626 catch ( ucb::InteractiveBadTransferURLException
const & )
1628 // Source URL is not supported by target. Try to transfer
1629 // the content "manually".
1631 catch ( ucb::UnsupportedCommandException
const & )
1633 // 'transfer' command is not supported by commandprocessor.
1634 // Try to transfer manually.
1636 catch ( ucb::UnsupportedNameClashException
const & exc
)
1638 OSL_ENSURE( aTransferArg
.NameClash
== exc
.NameClash
,
1639 "nameclash mismatch!" );
1640 if ( exc
.NameClash
== ucb::NameClash::ASK
)
1642 // Try to detect a name clash by invoking "transfer" with
1643 // NameClash::ERROR.
1646 ucb::TransferInfo2
aTransferArg1(
1647 aTransferArg
.MoveData
,
1648 aTransferArg
.SourceURL
,
1649 aTransferArg
.NewTitle
,
1650 ucb::NameClash::ERROR
,
1651 aTransferArg
.MimeType
);
1653 ucb::Command
aCommand1(
1656 uno::Any( aTransferArg1
) );
1658 xCommandProcessor
->execute( aCommand1
, 0, xLocalEnv
);
1660 // Command succeeded. We're done.
1663 catch ( ucb::UnsupportedNameClashException
const & )
1665 // No chance to solve name clashes, because I'm not
1666 // able to detect whether there is one.
1667 throw exc
; // Not just 'throw;'!
1669 catch ( ucb::NameClashException
const & )
1671 // There's a clash. Use interaction handler to solve it.
1675 NameClashContinuation eCont
1676 = interactiveNameClashResolve(
1677 xEnv
, // always use original environment!
1678 rArg
.TargetURL
, // target folder URL
1680 aTransferArg
), // clashing name
1688 cppu::throwException( aExc
);
1689 [[fallthrough
]]; // break;
1692 // Handled, but not clear, how...
1693 // fall through intended.
1696 throw ucb::CommandFailedException(
1697 "abort requested via interaction "
1699 uno::Reference
< uno::XInterface
>(),
1704 aTransferArg
.NameClash
1705 = ucb::NameClash::OVERWRITE
;
1710 aTransferArg
.NewTitle
= aNewTitle
;
1715 OSL_ENSURE( bRetry
, "bRetry must be true here!!!" );
1728 // (2) Try to transfer the content "manually".
1731 uno::Reference
< ucb::XContent
> xSource
;
1734 uno::Reference
< ucb::XContentIdentifier
> xId2
1735 = createContentIdentifier( rArg
.SourceURL
);
1737 xSource
= queryContent( xId2
);
1739 catch ( ucb::IllegalIdentifierException
const & )
1741 // Error handling via "if ( !xSource.is() )" below.
1744 if ( !xSource
.is() )
1746 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1748 {"Uri", uno::Any(rArg
.SourceURL
)}
1750 ucbhelper::cancelCommandExecution(
1751 ucb::IOErrorCode_CANT_READ
,
1754 "Can't instantiate source object!",
1759 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1760 xSource
, uno::UNO_QUERY
);
1761 if ( !xCommandProcessor
.is() )
1763 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1765 {"Uri", uno::Any(rArg
.SourceURL
)}
1767 ucbhelper::cancelCommandExecution(
1768 ucb::IOErrorCode_CANT_READ
,
1771 "Source content is not a XCommandProcessor!",
1776 // Obtain interesting property values from source...
1778 uno::Sequence
< beans::Property
> aProps
{ makeProperty("IsFolder", -1 /* unknown */),
1779 makeProperty("IsDocument", -1 /* unknown */),
1780 makeProperty("TargetURL", -1 /* unknown */),
1781 makeProperty("BaseURI", -1 /* unknown */) };
1783 ucb::Command
aGetPropsCommand(
1784 "getPropertyValues",
1786 uno::Any( aProps
) );
1788 uno::Reference
< sdbc::XRow
> xRow
;
1789 xCommandProcessor
->execute( aGetPropsCommand
, 0, xLocalEnv
) >>= xRow
;
1793 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1795 {"Uri", uno::Any(rArg
.SourceURL
)}
1797 ucbhelper::cancelCommandExecution(
1798 ucb::IOErrorCode_CANT_READ
,
1801 "Unable to get properties from source object!",
1806 TransferCommandContext
aTransferCtx(
1807 m_xContext
, this, xLocalEnv
, xEnv
, rArg
);
1809 if ( rArg
.NewTitle
.isEmpty() )
1811 // BaseURI: property is optional.
1812 OUString
aBaseURI( xRow
->getString( 4 ) );
1813 if ( !aBaseURI
.isEmpty() )
1815 aTransferCtx
.aArg
.NewTitle
1816 = createDesiredName( aBaseURI
, OUString() );
1821 globalTransfer_( aTransferCtx
, xSource
, xTarget
, xRow
);
1824 // (3) Delete source, if operation is MOVE.
1827 if ( rArg
.Operation
!= ucb::TransferCommandOperation_MOVE
)
1832 ucb::Command
aCommand(
1835 uno::Any( true ) ); // Argument
1837 xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1839 catch ( uno::Exception
const & )
1841 OSL_FAIL( "Cannot delete source object!" );
1846 uno::Any
UniversalContentBroker::checkIn( const ucb::CheckinArgument
& rArg
,
1847 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1850 // Use own command environment with own interaction handler intercepting
1851 // some interaction requests that shall not be handled by the user-supplied
1852 // interaction handler.
1853 uno::Reference
< ucb::XCommandEnvironment
> xLocalEnv
;
1856 xLocalEnv
.set( ucb::CommandEnvironment::create(
1858 new InteractionHandlerProxy( xEnv
->getInteractionHandler() ),
1859 xEnv
->getProgressHandler() ) );
1862 uno::Reference
< ucb::XContent
> xTarget
;
1863 uno::Reference
< ucb::XContentIdentifier
> xId
1864 = createContentIdentifier( rArg
.TargetURL
);
1869 xTarget
= queryContent( xId
);
1871 catch ( ucb::IllegalIdentifierException
const & )
1876 if ( !xTarget
.is() )
1878 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1880 {"Uri", uno::Any(rArg
.TargetURL
)}
1882 ucbhelper::cancelCommandExecution(
1883 ucb::IOErrorCode_CANT_READ
,
1886 "Can't instantiate target object!",
1891 uno::Reference
< ucb::XCommandProcessor
> xCommandProcessor(
1892 xTarget
, uno::UNO_QUERY
);
1893 if ( !xCommandProcessor
.is() )
1895 uno::Sequence
<uno::Any
> aArgs(comphelper::InitAnyPropertySequence(
1897 {"Uri", uno::Any(rArg
.TargetURL
)}
1899 ucbhelper::cancelCommandExecution(
1900 ucb::IOErrorCode_CANT_READ
,
1903 "Target content is not a XCommandProcessor!",
1910 ucb::Command
aCommand(
1914 aRet
= xCommandProcessor
->execute( aCommand
, 0, xLocalEnv
);
1916 catch ( ucb::UnsupportedCommandException
const & )
1918 // 'checkin' command is not supported by commandprocessor:
1924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */