xref: /trunk/main/ucb/source/core/ucbcmds.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_ucb.hxx"
26 
27 /**************************************************************************
28                                 TODO
29  **************************************************************************
30 
31  *************************************************************************/
32 #include <osl/diagnose.h>
33 #include <cppuhelper/implbase1.hxx>
34 #include <cppuhelper/exc_hlp.hxx>
35 #include <rtl/ustring.h>
36 #include <rtl/ustring.hxx>
37 #include <com/sun/star/uno/XInterface.hpp>
38 #include <com/sun/star/beans/PropertyState.hpp>
39 #include <com/sun/star/beans/PropertyValue.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/container/XChild.hpp>
42 #include <com/sun/star/beans/XPropertySetInfo.hpp>
43 #include <com/sun/star/io/XActiveDataSink.hpp>
44 #include <com/sun/star/io/XOutputStream.hpp>
45 #include <com/sun/star/io/XSeekable.hpp>
46 #include <com/sun/star/sdbc/XRow.hpp>
47 #include <com/sun/star/task/XInteractionHandler.hpp>
48 #include <com/sun/star/ucb/CommandEnvironment.hpp>
49 #include <com/sun/star/ucb/CommandFailedException.hpp>
50 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
51 #include <com/sun/star/ucb/GlobalTransferCommandArgument.hpp>
52 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
53 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
54 #include <com/sun/star/ucb/NameClash.hpp>
55 #include <com/sun/star/ucb/NameClashException.hpp>
56 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
57 #include <com/sun/star/ucb/OpenMode.hpp>
58 #include <com/sun/star/ucb/TransferInfo.hpp>
59 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
60 #include <com/sun/star/ucb/XCommandInfo.hpp>
61 #include <com/sun/star/ucb/XContentAccess.hpp>
62 #include <com/sun/star/ucb/XContentCreator.hpp>
63 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
64 #include <com/sun/star/uno/Any.hxx>
65 #include <com/sun/star/uno/Sequence.hxx>
66 #include <ucbhelper/cancelcommandexecution.hxx>
67 #include <ucbhelper/simplenameclashresolverequest.hxx>
68 #include "ucbcmds.hxx"
69 #include "ucb.hxx"
70 
71 using namespace com::sun::star;
72 
73 namespace
74 {
75 
76 //=========================================================================
77 //
78 // struct TransferCommandContext.
79 //
80 //=========================================================================
81 
82 struct TransferCommandContext
83 {
84     uno::Reference< lang::XMultiServiceFactory > xSMgr;
85     uno::Reference< ucb::XCommandProcessor >     xProcessor;
86     uno::Reference< ucb::XCommandEnvironment >   xEnv;
87     uno::Reference< ucb::XCommandEnvironment >   xOrigEnv;
88     ucb::GlobalTransferCommandArgument           aArg;
89 
TransferCommandContext__anon9eb7a7f90111::TransferCommandContext90     TransferCommandContext(
91         const uno::Reference< lang::XMultiServiceFactory > & rxSMgr,
92         const uno::Reference< ucb::XCommandProcessor > & rxProcessor,
93         const uno::Reference< ucb::XCommandEnvironment > & rxEnv,
94         const uno::Reference< ucb::XCommandEnvironment > & rxOrigEnv,
95         const ucb::GlobalTransferCommandArgument & rArg )
96     : xSMgr( rxSMgr ), xProcessor( rxProcessor ), xEnv( rxEnv ),
97       xOrigEnv( rxOrigEnv ), aArg( rArg ) {}
98 };
99 
100 //=========================================================================
101 //
102 // class InteractionHandlerProxy.
103 //
104 //=========================================================================
105 
106 class InteractionHandlerProxy :
107     public cppu::WeakImplHelper1< task::XInteractionHandler >
108 {
109     uno::Reference< task::XInteractionHandler > m_xOrig;
110 
111 public:
InteractionHandlerProxy(const uno::Reference<task::XInteractionHandler> & xOrig)112     InteractionHandlerProxy(
113         const uno::Reference< task::XInteractionHandler > & xOrig )
114     : m_xOrig( xOrig ) {}
115 
116     // XInteractionHandler methods.
117     virtual void SAL_CALL handle(
118             const uno::Reference< task::XInteractionRequest >& Request );
119 };
120 
121 //=========================================================================
122 // virtual
handle(const uno::Reference<task::XInteractionRequest> & Request)123 void SAL_CALL InteractionHandlerProxy::handle(
124             const uno::Reference< task::XInteractionRequest >& Request )
125 {
126     if ( !m_xOrig.is() )
127         return;
128 
129     // Filter unwanted requests by just not handling them.
130     uno::Any aRequest = Request->getRequest();
131 
132     // "transfer"
133     ucb::InteractiveBadTransferURLException aBadTransferURLEx;
134     if ( aRequest >>= aBadTransferURLEx )
135     {
136         return;
137     }
138     else
139     {
140         // "transfer"
141         ucb::UnsupportedNameClashException aUnsupportedNameClashEx;
142         if ( aRequest >>= aUnsupportedNameClashEx )
143         {
144             if ( aUnsupportedNameClashEx.NameClash
145                     != ucb::NameClash::ERROR )
146                 return;
147         }
148         else
149         {
150             // "insert"
151             ucb::NameClashException aNameClashEx;
152             if ( aRequest >>= aNameClashEx )
153             {
154                 return;
155             }
156             else
157             {
158                 // "transfer"
159                 ucb::UnsupportedCommandException aUnsupportedCommandEx;
160                 if ( aRequest >>= aUnsupportedCommandEx )
161                 {
162                     return;
163                 }
164             }
165         }
166     }
167 
168     // not filtered; let the original handler do the work.
169     m_xOrig->handle( Request );
170 }
171 
172 //=========================================================================
173 //
174 // class ActiveDataSink.
175 //
176 //=========================================================================
177 
178 class ActiveDataSink : public cppu::WeakImplHelper1< io::XActiveDataSink >
179 {
180     uno::Reference< io::XInputStream > m_xStream;
181 
182 public:
183     // XActiveDataSink methods.
184     virtual void SAL_CALL setInputStream(
185                         const uno::Reference< io::XInputStream >& aStream );
186     virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream();
187 };
188 
189 //=========================================================================
190 // virtual
setInputStream(const uno::Reference<io::XInputStream> & aStream)191 void SAL_CALL ActiveDataSink::setInputStream(
192                         const uno::Reference< io::XInputStream >& aStream )
193 {
194     m_xStream = aStream;
195 }
196 
197 //=========================================================================
198 // virtual
getInputStream()199 uno::Reference< io::XInputStream > SAL_CALL ActiveDataSink::getInputStream()
200 {
201     return m_xStream;
202 }
203 
204 //=========================================================================
205 //
206 // class CommandProcessorInfo.
207 //
208 //=========================================================================
209 
210 class CommandProcessorInfo :
211     public cppu::WeakImplHelper1< ucb::XCommandInfo >
212 {
213     uno::Sequence< ucb::CommandInfo > * m_pInfo;
214 
215 public:
216     CommandProcessorInfo();
217     virtual ~CommandProcessorInfo();
218 
219     // XCommandInfo methods
220     virtual uno::Sequence< ucb::CommandInfo > SAL_CALL getCommands();
221     virtual ucb::CommandInfo SAL_CALL
222     getCommandInfoByName( const rtl::OUString& Name );
223     virtual ucb::CommandInfo SAL_CALL
224     getCommandInfoByHandle( sal_Int32 Handle );
225     virtual sal_Bool SAL_CALL hasCommandByName( const rtl::OUString& Name );
226     virtual sal_Bool SAL_CALL hasCommandByHandle( sal_Int32 Handle );
227 };
228 
229 //=========================================================================
CommandProcessorInfo()230 CommandProcessorInfo::CommandProcessorInfo()
231 {
232     m_pInfo = new uno::Sequence< ucb::CommandInfo >( 2 );
233 
234     (*m_pInfo)[ 0 ]
235         = ucb::CommandInfo(
236             rtl::OUString::createFromAscii( GETCOMMANDINFO_NAME ), // Name
237             GETCOMMANDINFO_HANDLE, // Handle
238             getCppuVoidType() ); // ArgType
239     (*m_pInfo)[ 1 ]
240         = ucb::CommandInfo(
241             rtl::OUString::createFromAscii( GLOBALTRANSFER_NAME ), // Name
242             GLOBALTRANSFER_HANDLE, // Handle
243             getCppuType(
244                 static_cast<
245                     ucb::GlobalTransferCommandArgument * >( 0 ) ) ); // ArgType
246 }
247 
248 //=========================================================================
249 // virtual
~CommandProcessorInfo()250 CommandProcessorInfo::~CommandProcessorInfo()
251 {
252     delete m_pInfo;
253 }
254 
255 //=========================================================================
256 // virtual
257 uno::Sequence< ucb::CommandInfo > SAL_CALL
getCommands()258 CommandProcessorInfo::getCommands()
259 {
260     return uno::Sequence< ucb::CommandInfo >( *m_pInfo );
261 }
262 
263 //=========================================================================
264 // virtual
265 ucb::CommandInfo SAL_CALL
getCommandInfoByName(const rtl::OUString & Name)266 CommandProcessorInfo::getCommandInfoByName( const rtl::OUString& Name )
267 {
268     for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
269     {
270         if ( (*m_pInfo)[ n ].Name == Name )
271             return ucb::CommandInfo( (*m_pInfo)[ n ] );
272     }
273 
274     throw ucb::UnsupportedCommandException();
275 }
276 
277 //=========================================================================
278 // virtual
279 ucb::CommandInfo SAL_CALL
getCommandInfoByHandle(sal_Int32 Handle)280 CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle )
281 {
282     for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
283     {
284         if ( (*m_pInfo)[ n ].Handle == Handle )
285             return ucb::CommandInfo( (*m_pInfo)[ n ] );
286     }
287 
288     throw ucb::UnsupportedCommandException();
289 }
290 
291 //=========================================================================
292 // virtual
hasCommandByName(const rtl::OUString & Name)293 sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByName(
294                                                 const rtl::OUString& Name )
295 {
296     for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
297     {
298         if ( (*m_pInfo)[ n ].Name == Name )
299             return sal_True;
300     }
301 
302     return sal_False;
303 }
304 
305 //=========================================================================
306 // virtual
hasCommandByHandle(sal_Int32 Handle)307 sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle )
308 {
309     for ( sal_Int32 n = 0; n < m_pInfo->getLength(); ++n )
310     {
311         if ( (*m_pInfo)[ n ].Handle == Handle )
312             return sal_True;
313     }
314 
315     return sal_False;
316 }
317 
318 //=========================================================================
319 //=========================================================================
320 //=========================================================================
321 
createDesiredName(const rtl::OUString & rSourceURL,const rtl::OUString & rNewTitle)322 rtl::OUString createDesiredName(
323     const rtl::OUString & rSourceURL, const rtl::OUString & rNewTitle )
324 {
325     rtl::OUString aName( rNewTitle );
326     if ( aName.getLength() == 0 )
327     {
328         // calculate name using source URL
329 
330         // @@@ It's not guaranteed that slashes contained in the URL are
331         // actually path separators. This depends on the fact whether the
332         // URL is hierarchical. Only then the slashes are path separators.
333         // Therefore this algorithm is not guaranteed to work! But, ATM
334         // I don't know a better solution. It would have been better to
335         // have a member for the clashing name in
336         // UnsupportedNameClashException...
337 
338         sal_Int32 nLastSlash = rSourceURL.lastIndexOf( '/' );
339         bool bTrailingSlash = false;
340         if ( nLastSlash == rSourceURL.getLength() - 1 )
341         {
342             nLastSlash = rSourceURL.lastIndexOf( '/', nLastSlash );
343             bTrailingSlash = true;
344         }
345 
346         if ( nLastSlash != -1 )
347         {
348             if ( bTrailingSlash )
349                 aName = rSourceURL.copy(
350                             nLastSlash + 1,
351                             rSourceURL.getLength() - nLastSlash - 2 );
352             else
353                 aName = rSourceURL.copy( nLastSlash + 1 );
354         }
355         else
356         {
357             aName = rSourceURL;
358         }
359 
360         // query, fragment present?
361     sal_Int32  nPos = aName.indexOf( '?' );
362     if ( nPos == -1 )
363       nPos = aName.indexOf( '#' );
364 
365     if ( nPos != -1 )
366       aName = aName.copy( 0, nPos );
367     }
368     return rtl::OUString( aName );
369 }
370 
createDesiredName(const ucb::GlobalTransferCommandArgument & rArg)371 rtl::OUString createDesiredName(
372     const ucb::GlobalTransferCommandArgument & rArg )
373 {
374     return createDesiredName( rArg.SourceURL, rArg.NewTitle );
375 }
376 
createDesiredName(const ucb::TransferInfo & rArg)377 rtl::OUString createDesiredName(
378     const ucb::TransferInfo & rArg )
379 {
380     return createDesiredName( rArg.SourceURL, rArg.NewTitle );
381 }
382 
383 //=========================================================================
384 enum NameClashContinuation { NOT_HANDLED, ABORT, OVERWRITE, NEW_NAME, UNKNOWN };
385 
interactiveNameClashResolve(const uno::Reference<ucb::XCommandEnvironment> & xEnv,const rtl::OUString & rTargetURL,const rtl::OUString & rClashingName,uno::Any & rException,rtl::OUString & rNewName)386 NameClashContinuation interactiveNameClashResolve(
387     const uno::Reference< ucb::XCommandEnvironment > & xEnv,
388     const rtl::OUString & rTargetURL,
389     const rtl::OUString & rClashingName,
390     /* [out] */ uno::Any & rException,
391     /* [out] */ rtl::OUString & rNewName )
392 {
393     rtl::Reference< ucbhelper::SimpleNameClashResolveRequest > xRequest(
394         new ucbhelper::SimpleNameClashResolveRequest(
395             rTargetURL,  // target folder URL
396             rClashingName,   // clashing name
397             rtl::OUString(), // no proposal for new name
398             sal_True /* bSupportsOverwriteData */ ) );
399 
400     rException = xRequest->getRequest();
401     if ( xEnv.is() )
402     {
403         uno::Reference< task::XInteractionHandler > xIH
404             = xEnv->getInteractionHandler();
405         if ( xIH.is() )
406         {
407 
408             xIH->handle( xRequest.get() );
409 
410             rtl::Reference< ucbhelper::InteractionContinuation >
411                 xSelection( xRequest->getSelection() );
412 
413             if ( xSelection.is() )
414             {
415                 // Handler handled the request.
416                 uno::Reference< task::XInteractionAbort > xAbort(
417                     xSelection.get(), uno::UNO_QUERY );
418                 if ( xAbort.is() )
419                 {
420                     // Abort.
421                     return ABORT;
422                 }
423                 else
424                 {
425                     uno::Reference<
426                         ucb::XInteractionReplaceExistingData >
427                             xReplace(
428                                 xSelection.get(), uno::UNO_QUERY );
429                     if ( xReplace.is() )
430                     {
431                         // Try again: Replace existing data.
432                         return OVERWRITE;
433                     }
434                     else
435                     {
436                         uno::Reference<
437                             ucb::XInteractionSupplyName >
438                                 xSupplyName(
439                                     xSelection.get(), uno::UNO_QUERY );
440                         if ( xSupplyName.is() )
441                         {
442                             // Try again: Use new name.
443                             rNewName = xRequest->getNewName();
444                             return NEW_NAME;
445                         }
446                         else
447                         {
448                             OSL_ENSURE( sal_False,
449                                         "Unknown interaction continuation!" );
450                             return UNKNOWN;
451                         }
452                     }
453                 }
454             }
455         }
456     }
457     return NOT_HANDLED;
458 }
459 
460 //=========================================================================
setTitle(const uno::Reference<ucb::XCommandProcessor> & xCommandProcessor,const uno::Reference<ucb::XCommandEnvironment> & xEnv,const rtl::OUString & rNewTitle)461 bool setTitle(
462         const uno::Reference< ucb::XCommandProcessor > & xCommandProcessor,
463         const uno::Reference< ucb::XCommandEnvironment > & xEnv,
464         const rtl::OUString & rNewTitle )
465 {
466     try
467     {
468         uno::Sequence< beans::PropertyValue > aPropValues( 1 );
469         aPropValues[ 0 ].Name
470             = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
471         aPropValues[ 0 ].Handle = -1;
472         aPropValues[ 0 ].Value  = uno::makeAny( rNewTitle );
473 
474         ucb::Command aSetPropsCommand(
475             rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ),
476             -1,
477             uno::makeAny( aPropValues ) );
478 
479         uno::Any aResult
480             = xCommandProcessor->execute( aSetPropsCommand, 0, xEnv );
481 
482         uno::Sequence< uno::Any > aErrors;
483         aResult >>= aErrors;
484 
485         OSL_ENSURE( aErrors.getLength() == 1,
486                     "getPropertyValues return value invalid!" );
487 
488         if ( aErrors[ 0 ].hasValue() )
489         {
490             // error occurred.
491             OSL_ENSURE( sal_False, "error setting Title property!" );
492             return false;
493         }
494     }
495     catch ( uno::RuntimeException const & )
496     {
497         throw;
498     }
499     catch ( uno::Exception const & )
500     {
501         return false;
502     }
503 
504     return true;
505 }
506 
507 //=========================================================================
createNew(const TransferCommandContext & rContext,const uno::Reference<ucb::XContent> & xTarget,sal_Bool bSourceIsFolder,sal_Bool bSourceIsDocument,sal_Bool bSourceIsLink)508 uno::Reference< ucb::XContent > createNew(
509                     const TransferCommandContext & rContext,
510                     const uno::Reference< ucb::XContent > & xTarget,
511                     sal_Bool bSourceIsFolder,
512                     sal_Bool bSourceIsDocument,
513                     sal_Bool bSourceIsLink )
514 {
515     //////////////////////////////////////////////////////////////////////
516     //
517     // (1) Obtain creatable types from target.
518     //
519     //////////////////////////////////////////////////////////////////////
520 
521     // First, try it using "CreatabeleContentsInfo" property and
522     // "createNewContent" command -> the "new" way.
523 
524     uno::Reference< ucb::XCommandProcessor > xCommandProcessorT(
525                                                     xTarget, uno::UNO_QUERY );
526     if ( !xCommandProcessorT.is() )
527     {
528         uno::Any aProps
529             = uno::makeAny(beans::PropertyValue(
530                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
531                                                     "Folder")),
532                                   -1,
533                                   uno::makeAny(rContext.aArg.TargetURL),
534                                   beans::PropertyState_DIRECT_VALUE));
535         ucbhelper::cancelCommandExecution(
536             ucb::IOErrorCode_CANT_CREATE,
537             uno::Sequence< uno::Any >(&aProps, 1),
538             rContext.xOrigEnv,
539             rtl::OUString::createFromAscii( "Target is no XCommandProcessor!" ),
540             rContext.xProcessor );
541         // Unreachable
542     }
543 
544     uno::Sequence< beans::Property > aPropsToObtain( 1 );
545     aPropsToObtain[ 0 ].Name
546         = rtl::OUString::createFromAscii( "CreatableContentsInfo" );
547     aPropsToObtain[ 0 ].Handle
548         = -1;
549 
550     ucb::Command aGetPropsCommand(
551             rtl::OUString::createFromAscii( "getPropertyValues" ),
552             -1,
553             uno::makeAny( aPropsToObtain ) );
554 
555     uno::Reference< sdbc::XRow > xRow;
556     xCommandProcessorT->execute( aGetPropsCommand, 0, rContext.xEnv )  >>= xRow;
557 
558     uno::Sequence< ucb::ContentInfo > aTypesInfo;
559     bool bGotTypesInfo = false;
560 
561     if ( xRow.is() )
562     {
563         uno::Any  aValue = xRow->getObject(
564             1, uno::Reference< container::XNameAccess >() );
565         if ( aValue.hasValue() && ( aValue >>= aTypesInfo ) )
566         {
567             bGotTypesInfo = true;
568         }
569     }
570 
571     uno::Reference< ucb::XContentCreator > xCreator;
572 
573     if ( !bGotTypesInfo )
574     {
575         // Second, try it using XContentCreator interface -> the "old" way (not
576         // providing the chance to supply an XCommandEnvironment.
577 
578         xCreator.set( xTarget, uno::UNO_QUERY );
579 
580         if ( !xCreator.is() )
581         {
582             uno::Any aProps
583                 = uno::makeAny(beans::PropertyValue(
584                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
585                                                     "Folder")),
586                                   -1,
587                                   uno::makeAny(rContext.aArg.TargetURL),
588                                   beans::PropertyState_DIRECT_VALUE));
589             ucbhelper::cancelCommandExecution(
590                 ucb::IOErrorCode_CANT_CREATE,
591                 uno::Sequence< uno::Any >(&aProps, 1),
592                 rContext.xOrigEnv,
593                 rtl::OUString::createFromAscii( "Target is no XContentCreator!" ),
594                 rContext.xProcessor );
595             // Unreachable
596         }
597 
598         aTypesInfo  = xCreator->queryCreatableContentsInfo();
599     }
600 
601     sal_Int32 nCount = aTypesInfo.getLength();
602     if ( !nCount )
603     {
604         uno::Any aProps
605             = uno::makeAny(beans::PropertyValue(
606                               rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Folder")),
607                               -1,
608                               uno::makeAny(rContext.aArg.TargetURL),
609                               beans::PropertyState_DIRECT_VALUE));
610         ucbhelper::cancelCommandExecution(
611             ucb::IOErrorCode_CANT_CREATE,
612             uno::Sequence< uno::Any >(&aProps, 1),
613             rContext.xOrigEnv,
614             rtl::OUString::createFromAscii( "No types creatable!" ),
615             rContext.xProcessor );
616         // Unreachable
617     }
618 
619     //////////////////////////////////////////////////////////////////////
620     //
621     // (2) Try to find a matching target type for the source object.
622     //
623     //////////////////////////////////////////////////////////////////////
624 
625     uno::Reference< ucb::XContent > xNew;
626     for ( sal_Int32 n = 0; n < nCount; ++n )
627     {
628         sal_Int32 nAttribs = aTypesInfo[ n ].Attributes;
629         sal_Bool  bMatch   = sal_False;
630 
631         if ( rContext.aArg.Operation == ucb::TransferCommandOperation_LINK )
632         {
633             // Create link
634 
635             if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
636             {
637                 // Match!
638                 bMatch = sal_True;
639             }
640         }
641         else if ( ( rContext.aArg.Operation
642                         == ucb::TransferCommandOperation_COPY ) ||
643                   ( rContext.aArg.Operation
644                         == ucb::TransferCommandOperation_MOVE ) )
645         {
646             // Copy / Move
647 
648             // Is source a link? Create link in target folder then.
649             if ( bSourceIsLink )
650             {
651                 if ( nAttribs & ucb::ContentInfoAttribute::KIND_LINK )
652                 {
653                     // Match!
654                     bMatch = sal_True;
655                 }
656             }
657             else
658             {
659                 // (not a and not b) or (a and b)
660                 // not( a or b) or (a and b)
661                 //
662                 if ( ( !!bSourceIsFolder ==
663                         !!( nAttribs
664                             & ucb::ContentInfoAttribute::KIND_FOLDER ) )
665                      &&
666                      ( !!bSourceIsDocument ==
667                         !!( nAttribs
668                             & ucb::ContentInfoAttribute::KIND_DOCUMENT ) )
669                    )
670                 {
671                     // Match!
672                     bMatch = sal_True;
673                 }
674             }
675         }
676         else
677         {
678             ucbhelper::cancelCommandExecution(
679                 uno::makeAny( lang::IllegalArgumentException(
680                                         rtl::OUString::createFromAscii(
681                                             "Unknown transfer operation!" ),
682                                         rContext.xProcessor,
683                                         -1 ) ),
684                               rContext.xOrigEnv );
685             // Unreachable
686         }
687 
688         if ( bMatch )
689         {
690             //////////////////////////////////////////////////////////////
691             //
692             // (3) Create a new, empty object of matched type.
693             //
694             //////////////////////////////////////////////////////////////
695 
696             if ( !xCreator.is() )
697             {
698                 // First, try it using "CreatabeleContentsInfo" property and
699                 // "createNewContent" command -> the "new" way.
700                 ucb::Command aCreateNewCommand(
701                    rtl::OUString::createFromAscii( "createNewContent" ),
702                    -1,
703                    uno::makeAny( aTypesInfo[ n ] ) );
704 
705                 xCommandProcessorT->execute( aCreateNewCommand, 0, rContext.xEnv )
706                     >>= xNew;
707             }
708             else
709             {
710                 // Second, try it using XContentCreator interface -> the "old"
711                 // way (not providing the chance to supply an XCommandEnvironment.
712 
713                 xNew = xCreator->createNewContent( aTypesInfo[ n ] );
714             }
715 
716             if ( !xNew.is() )
717             {
718                 uno::Any aProps
719                     = uno::makeAny(
720                              beans::PropertyValue(
721                                  rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
722                                                    "Folder")),
723                                  -1,
724                                  uno::makeAny(rContext.aArg.TargetURL),
725                                  beans::PropertyState_DIRECT_VALUE));
726                 ucbhelper::cancelCommandExecution(
727                     ucb::IOErrorCode_CANT_CREATE,
728                     uno::Sequence< uno::Any >(&aProps, 1),
729                     rContext.xOrigEnv,
730                     rtl::OUString::createFromAscii(
731                         "createNewContent failed!" ),
732                     rContext.xProcessor );
733                 // Unreachable
734             }
735             break; // escape from 'for' loop
736         }
737     } // for
738 
739     return xNew;
740 }
741 
742 //=========================================================================
transferProperties(const TransferCommandContext & rContext,const uno::Reference<ucb::XCommandProcessor> & xCommandProcessorS,const uno::Reference<ucb::XCommandProcessor> & xCommandProcessorN)743 void transferProperties(
744     const TransferCommandContext & rContext,
745     const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS,
746     const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorN )
747 {
748     ucb::Command aGetPropertySetInfoCommand(
749                 rtl::OUString::createFromAscii( "getPropertySetInfo" ),
750                 -1,
751                 uno::Any() );
752 
753     uno::Reference< beans::XPropertySetInfo > xInfo;
754     xCommandProcessorS->execute( aGetPropertySetInfoCommand, 0, rContext.xEnv )
755         >>= xInfo;
756 
757     if ( !xInfo.is() )
758     {
759         uno::Any aProps
760             = uno::makeAny(beans::PropertyValue(
761                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
762                                                     "Uri")),
763                                   -1,
764                                   uno::makeAny(rContext.aArg.SourceURL),
765                                   beans::PropertyState_DIRECT_VALUE));
766         ucbhelper::cancelCommandExecution(
767             ucb::IOErrorCode_CANT_READ,
768             uno::Sequence< uno::Any >(&aProps, 1),
769             rContext.xOrigEnv,
770             rtl::OUString::createFromAscii(
771                 "Unable to get propertyset info from source object!" ),
772             rContext.xProcessor );
773         // Unreachable
774     }
775 
776     uno::Sequence< beans::Property > aAllProps = xInfo->getProperties();
777 
778     ucb::Command aGetPropsCommand1(
779                 rtl::OUString::createFromAscii( "getPropertyValues" ),
780                 -1,
781                 uno::makeAny( aAllProps ) );
782 
783     uno::Reference< sdbc::XRow > xRow1;
784     xCommandProcessorS->execute(
785         aGetPropsCommand1, 0, rContext.xEnv ) >>= xRow1;
786 
787     if ( !xRow1.is() )
788     {
789         uno::Any aProps
790             = uno::makeAny(beans::PropertyValue(
791                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
792                                                     "Uri")),
793                                   -1,
794                                   uno::makeAny(rContext.aArg.SourceURL),
795                                   beans::PropertyState_DIRECT_VALUE));
796         ucbhelper::cancelCommandExecution(
797             ucb::IOErrorCode_CANT_READ,
798             uno::Sequence< uno::Any >(&aProps, 1),
799             rContext.xOrigEnv,
800             rtl::OUString::createFromAscii(
801                 "Unable to get properties from source object!" ),
802             rContext.xProcessor );
803         // Unreachable
804     }
805 
806     // Assemble data structure for setPropertyValues command.
807 
808     // Note: Make room for additional Title and TargetURL too. -> + 2
809     uno::Sequence< beans::PropertyValue > aPropValues(
810                                                 aAllProps.getLength() + 2 );
811 
812     sal_Bool bHasTitle = ( rContext.aArg.NewTitle.getLength() == 0 );
813     sal_Bool bHasTargetURL = ( rContext.aArg.Operation
814                                 != ucb::TransferCommandOperation_LINK );
815 
816     sal_Int32 nWritePos = 0;
817     for ( sal_Int32 m = 0; m < aAllProps.getLength(); ++m )
818     {
819         const beans::Property & rCurrProp = aAllProps[ m ];
820         beans::PropertyValue & rCurrValue = aPropValues[ nWritePos ];
821 
822         uno::Any aValue;
823 
824         if ( rCurrProp.Name.compareToAscii( "Title" ) == 0 )
825         {
826             // Supply new title, if given.
827             if ( !bHasTitle )
828             {
829                 bHasTitle = sal_True;
830                 aValue <<= rContext.aArg.NewTitle;
831             }
832         }
833         else if ( rCurrProp.Name.compareToAscii( "TargetURL" ) == 0 )
834         {
835             // Supply source URL as link target for the new link to create.
836             if ( !bHasTargetURL )
837             {
838                 bHasTargetURL = sal_True;
839                 aValue <<= rContext.aArg.SourceURL;
840             }
841         }
842 
843         if ( !aValue.hasValue() )
844         {
845             try
846             {
847                 aValue = xRow1->getObject(
848                             m + 1, uno::Reference< container::XNameAccess >() );
849             }
850             catch ( sdbc::SQLException const & )
851             {
852                 // Argh! But try to bring things to an end. Perhaps the
853                 // mad property is not really important...
854             }
855         }
856 
857         if ( aValue.hasValue() )
858         {
859             rCurrValue.Name   = rCurrProp.Name;
860             rCurrValue.Handle = rCurrProp.Handle;
861             rCurrValue.Value  = aValue;
862 //          rCurrValue.State  =
863 
864             nWritePos++;
865         }
866     }
867 
868     // Title needed, but not set yet?
869     if ( !bHasTitle && ( rContext.aArg.NewTitle.getLength() > 0 ) )
870     {
871         aPropValues[ nWritePos ].Name
872             = rtl::OUString::createFromAscii( "Title" );
873         aPropValues[ nWritePos ].Handle = -1;
874         aPropValues[ nWritePos ].Value <<= rContext.aArg.NewTitle;
875 
876         nWritePos++;
877     }
878 
879     // TargetURL needed, but not set yet?
880     if ( !bHasTargetURL && ( rContext.aArg.Operation
881                                 == ucb::TransferCommandOperation_LINK ) )
882     {
883         aPropValues[ nWritePos ].Name
884             = rtl::OUString::createFromAscii( "TargetURL" );
885         aPropValues[ nWritePos ].Handle = -1;
886         aPropValues[ nWritePos ].Value <<= rContext.aArg.SourceURL;
887 
888         nWritePos++;
889     }
890 
891     aPropValues.realloc( nWritePos );
892 
893     // Set properties at new object.
894 
895     ucb::Command aSetPropsCommand(
896                 rtl::OUString::createFromAscii( "setPropertyValues" ),
897                 -1,
898                 uno::makeAny( aPropValues ) );
899 
900     xCommandProcessorN->execute( aSetPropsCommand, 0, rContext.xEnv );
901 
902     // @@@ What to do with source props that are not supported by the
903     //     new object? addProperty ???
904 }
905 
906 //=========================================================================
getInputStream(const TransferCommandContext & rContext,const uno::Reference<ucb::XCommandProcessor> & xCommandProcessorS)907 uno::Reference< io::XInputStream > getInputStream(
908     const TransferCommandContext & rContext,
909     const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
910 {
911     uno::Reference< io::XInputStream > xInputStream;
912 
913     //////////////////////////////////////////////////////////////////////
914     //
915     // (1) Try to get data as XInputStream via XActiveDataSink.
916     //
917     //////////////////////////////////////////////////////////////////////
918 
919     try
920     {
921         uno::Reference< io::XActiveDataSink > xSink = new ActiveDataSink;
922 
923         ucb::OpenCommandArgument2 aArg;
924         aArg.Mode       = ucb::OpenMode::DOCUMENT;
925         aArg.Priority   = 0; // unused
926         aArg.Sink       = xSink;
927         aArg.Properties = uno::Sequence< beans::Property >( 0 ); // unused
928 
929         ucb::Command aOpenCommand(
930                                 rtl::OUString::createFromAscii( "open" ),
931                                 -1,
932                                 uno::makeAny( aArg ) );
933 
934         xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
935         xInputStream = xSink->getInputStream();
936     }
937     catch ( uno::RuntimeException const & )
938     {
939         throw;
940     }
941     catch ( uno::Exception const & )
942     {
943         // will be handled below.
944     }
945 
946     if ( !xInputStream.is() )
947     {
948         //////////////////////////////////////////////////////////////////
949         //
950         // (2) Try to get data via XOutputStream.
951         //
952         //////////////////////////////////////////////////////////////////
953 
954         try
955         {
956             uno::Reference< io::XOutputStream > xOutputStream(
957                 rContext.xSMgr->createInstance(
958                     rtl::OUString::createFromAscii( "com.sun.star.io.Pipe" ) ),
959                 uno::UNO_QUERY );
960 
961             if ( xOutputStream.is() )
962             {
963                 ucb::OpenCommandArgument2 aArg;
964                 aArg.Mode       = ucb::OpenMode::DOCUMENT;
965                 aArg.Priority   = 0; // unused
966                 aArg.Sink       = xOutputStream;
967                 aArg.Properties = uno::Sequence< beans::Property >( 0 );
968 
969                 ucb::Command aOpenCommand(
970                                     rtl::OUString::createFromAscii( "open" ),
971                                     -1,
972                                     uno::makeAny( aArg ) );
973 
974                 xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
975 
976                 xInputStream = uno::Reference< io::XInputStream >(
977                                         xOutputStream, uno::UNO_QUERY );
978             }
979         }
980         catch ( uno::RuntimeException const & )
981         {
982             throw;
983         }
984         catch ( uno::Exception const & )
985         {
986             OSL_ENSURE( sal_False, "unable to get input stream from document!" );
987         }
988     }
989 
990     return xInputStream;
991 }
992 
993 //=========================================================================
getResultSet(const TransferCommandContext & rContext,const uno::Reference<ucb::XCommandProcessor> & xCommandProcessorS)994 uno::Reference< sdbc::XResultSet > getResultSet(
995     const TransferCommandContext & rContext,
996     const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
997 {
998     uno::Reference< sdbc::XResultSet > xResultSet;
999 
1000     uno::Sequence< beans::Property > aProps( 3 );
1001 
1002     aProps[ 0 ].Name   = rtl::OUString::createFromAscii( "IsFolder" );
1003     aProps[ 0 ].Handle = -1; /* unknown */
1004     aProps[ 1 ].Name   = rtl::OUString::createFromAscii( "IsDocument" );
1005     aProps[ 1 ].Handle = -1; /* unknown */
1006     aProps[ 2 ].Name   = rtl::OUString::createFromAscii( "TargetURL" );
1007     aProps[ 2 ].Handle = -1; /* unknown */
1008 
1009     ucb::OpenCommandArgument2 aArg;
1010     aArg.Mode       = ucb::OpenMode::ALL;
1011     aArg.Priority   = 0; // unused
1012     aArg.Sink       = 0;
1013     aArg.Properties = aProps;
1014 
1015     ucb::Command aOpenCommand( rtl::OUString::createFromAscii( "open" ),
1016                                      -1,
1017                                      uno::makeAny( aArg ) );
1018     try
1019     {
1020         uno::Reference< ucb::XDynamicResultSet > xSet;
1021         xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv ) >>= xSet;
1022 
1023         if ( xSet.is() )
1024             xResultSet = xSet->getStaticResultSet();
1025     }
1026     catch ( uno::RuntimeException const & )
1027     {
1028         throw;
1029     }
1030     catch ( uno::Exception const & )
1031     {
1032          OSL_ENSURE( sal_False, "unable to get result set from folder!" );
1033     }
1034 
1035     return xResultSet;
1036 }
1037 
1038 //=========================================================================
handleNameClashRename(const TransferCommandContext & rContext,const uno::Reference<ucb::XContent> & xNew,const uno::Reference<ucb::XCommandProcessor> & xCommandProcessorN,const uno::Reference<ucb::XCommandProcessor> & xCommandProcessorS,uno::Reference<io::XInputStream> & xInputStream)1039 void handleNameClashRename(
1040         const TransferCommandContext & rContext,
1041         const uno::Reference< ucb::XContent > & xNew,
1042         const uno::Reference<
1043             ucb::XCommandProcessor > & xCommandProcessorN,
1044         const uno::Reference<
1045             ucb::XCommandProcessor > & xCommandProcessorS,
1046         /* [inout] */ uno::Reference< io::XInputStream > & xInputStream )
1047 {
1048     sal_Int32 nTry = 0;
1049 
1050     // Obtain old title.
1051     uno::Sequence< beans::Property > aProps( 1 );
1052     aProps[ 0 ].Name   = rtl::OUString::createFromAscii( "Title" );
1053     aProps[ 0 ].Handle = -1;
1054 
1055     ucb::Command aGetPropsCommand(
1056             rtl::OUString::createFromAscii( "getPropertyValues" ),
1057             -1,
1058             uno::makeAny( aProps ) );
1059 
1060     uno::Reference< sdbc::XRow > xRow;
1061     xCommandProcessorN->execute( aGetPropsCommand, 0, rContext.xEnv )  >>= xRow;
1062 
1063     if ( !xRow.is() )
1064     {
1065         uno::Any aProps2
1066             = uno::makeAny(
1067                      beans::PropertyValue(
1068                          rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Uri" ) ),
1069                          -1,
1070                          uno::makeAny(
1071                              xNew->getIdentifier()->getContentIdentifier() ),
1072                          beans::PropertyState_DIRECT_VALUE ) );
1073         ucbhelper::cancelCommandExecution(
1074             ucb::IOErrorCode_CANT_READ,
1075             uno::Sequence< uno::Any >( &aProps2, 1 ),
1076             rContext.xOrigEnv,
1077             rtl::OUString::createFromAscii(
1078                 "Unable to get properties from new object!" ),
1079             rContext.xProcessor );
1080         // Unreachable
1081     }
1082 
1083     rtl::OUString aOldTitle = xRow->getString( 1 );
1084     if ( !aOldTitle.getLength() )
1085     {
1086         ucbhelper::cancelCommandExecution(
1087             uno::makeAny( beans::UnknownPropertyException(
1088                             rtl::OUString::createFromAscii(
1089                                 "Unable to get property 'Title' "
1090                                 "from new object!" ),
1091                             rContext.xProcessor ) ),
1092             rContext.xOrigEnv );
1093         // Unreachable
1094     }
1095 
1096     // Some pseudo-intelligence for not destroying file extensions.
1097     rtl::OUString aOldTitlePre;
1098     rtl::OUString aOldTitlePost;
1099     sal_Int32 nPos = aOldTitle.lastIndexOf( '.' );
1100     if ( nPos != -1 )
1101     {
1102         aOldTitlePre = aOldTitle.copy( 0, nPos );
1103         aOldTitlePost = aOldTitle.copy( nPos );
1104     }
1105     else
1106         aOldTitlePre = aOldTitle;
1107 
1108     if ( nPos > 0 )
1109         aOldTitlePre += rtl::OUString::createFromAscii( "_" );
1110 
1111     sal_Bool bContinue = sal_True;
1112     do
1113     {
1114         nTry++;
1115 
1116         rtl::OUString aNewTitle = aOldTitlePre;
1117         aNewTitle += rtl::OUString::valueOf( nTry );
1118         aNewTitle += aOldTitlePost;
1119 
1120         // Set new title
1121         setTitle( xCommandProcessorN, rContext.xEnv, aNewTitle );
1122 
1123         // Retry inserting the content.
1124         try
1125         {
1126             // Previous try may have read from stream. Seek to begin (if
1127             // optional interface XSeekable is supported) or get a new stream.
1128             if ( xInputStream.is() )
1129             {
1130                 uno::Reference< io::XSeekable > xSeekable(
1131                     xInputStream, uno::UNO_QUERY );
1132                 if ( xSeekable.is() )
1133                 {
1134                     try
1135                     {
1136                         xSeekable->seek( 0 );
1137                     }
1138                     catch ( lang::IllegalArgumentException const & )
1139                     {
1140                         xInputStream.clear();
1141                     }
1142                     catch ( io::IOException const & )
1143                     {
1144                         xInputStream.clear();
1145                     }
1146                 }
1147                 else
1148                     xInputStream.clear();
1149 
1150                 if ( !xInputStream.is() )
1151                 {
1152                     xInputStream
1153                         = getInputStream( rContext, xCommandProcessorS );
1154                     if ( !xInputStream.is() )
1155                     {
1156                         uno::Any aProps2
1157                             = uno::makeAny(
1158                                 beans::PropertyValue(
1159                                     rtl::OUString(
1160                                         RTL_CONSTASCII_USTRINGPARAM( "Uri" ) ),
1161                                     -1,
1162                                     uno::makeAny(
1163                                         xNew->getIdentifier()->
1164                                             getContentIdentifier() ),
1165                                     beans::PropertyState_DIRECT_VALUE ) );
1166                         ucbhelper::cancelCommandExecution(
1167                             ucb::IOErrorCode_CANT_READ,
1168                             uno::Sequence< uno::Any >( &aProps2, 1 ),
1169                             rContext.xOrigEnv,
1170                             rtl::OUString::createFromAscii(
1171                                 "Got no data stream from source!" ),
1172                             rContext.xProcessor );
1173                         // Unreachable
1174                     }
1175                 }
1176             }
1177 
1178             ucb::InsertCommandArgument aArg;
1179             aArg.Data = xInputStream;
1180             aArg.ReplaceExisting = sal_False;
1181 
1182             ucb::Command aInsertCommand(
1183                         rtl::OUString::createFromAscii( "insert" ),
1184                         -1,
1185                         uno::makeAny( aArg ) );
1186 
1187             xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
1188 
1189             // Success!
1190             bContinue = sal_False;
1191         }
1192         catch ( uno::RuntimeException const & )
1193         {
1194             throw;
1195         }
1196         catch ( uno::Exception const & )
1197         {
1198         }
1199     }
1200     while ( bContinue && ( nTry < 50 ) );
1201 
1202     if ( nTry == 50 )
1203     {
1204         ucbhelper::cancelCommandExecution(
1205             uno::makeAny(
1206                 ucb::UnsupportedNameClashException(
1207                     rtl::OUString::createFromAscii(
1208                         "Unable to resolve name clash!" ),
1209                     rContext.xProcessor,
1210                     ucb::NameClash::RENAME ) ),
1211             rContext.xOrigEnv );
1212         // Unreachable
1213     }
1214 }
1215 
1216 //=========================================================================
globalTransfer_(const TransferCommandContext & rContext,const uno::Reference<ucb::XContent> & xSource,const uno::Reference<ucb::XContent> & xTarget,const uno::Reference<sdbc::XRow> & xSourceProps)1217 void globalTransfer_(
1218         const TransferCommandContext & rContext,
1219         const uno::Reference< ucb::XContent > & xSource,
1220         const uno::Reference< ucb::XContent > & xTarget,
1221         const uno::Reference< sdbc::XRow > & xSourceProps )
1222 {
1223     // IsFolder: property is required.
1224     sal_Bool bSourceIsFolder = xSourceProps->getBoolean( 1 );
1225     if ( !bSourceIsFolder && xSourceProps->wasNull() )
1226     {
1227         ucbhelper::cancelCommandExecution(
1228             uno::makeAny( beans::UnknownPropertyException(
1229                             rtl::OUString::createFromAscii(
1230                                 "Unable to get property 'IsFolder' "
1231                                 "from source object!" ),
1232                             rContext.xProcessor ) ),
1233             rContext.xOrigEnv );
1234         // Unreachable
1235     }
1236 
1237     // IsDocument: property is required.
1238     sal_Bool bSourceIsDocument = xSourceProps->getBoolean( 2 );
1239     if ( !bSourceIsDocument && xSourceProps->wasNull() )
1240     {
1241         ucbhelper::cancelCommandExecution(
1242             uno::makeAny( beans::UnknownPropertyException(
1243                             rtl::OUString::createFromAscii(
1244                                 "Unable to get property 'IsDocument' "
1245                                 "from source object!" ),
1246                             rContext.xProcessor ) ),
1247             rContext.xOrigEnv );
1248         // Unreachable
1249     }
1250 
1251     // TargetURL: property is optional.
1252     sal_Bool bSourceIsLink = ( xSourceProps->getString( 3 ).getLength() > 0 );
1253 
1254     //////////////////////////////////////////////////////////////////////
1255     //
1256     // (1) Try to find a matching target type for the source object and
1257     //     create a new, empty object of that type.
1258     //
1259     //////////////////////////////////////////////////////////////////////
1260 
1261     uno::Reference< ucb::XContent > xNew = createNew( rContext,
1262                                                       xTarget,
1263                                                       bSourceIsFolder,
1264                                                       bSourceIsDocument,
1265                                                       bSourceIsLink );
1266     if ( !xNew.is() )
1267     {
1268         uno::Any aProps
1269             = uno::makeAny(beans::PropertyValue(
1270                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1271                                       "Folder")),
1272                                   -1,
1273                                   uno::makeAny(rContext.aArg.TargetURL),
1274                                   beans::PropertyState_DIRECT_VALUE));
1275         ucbhelper::cancelCommandExecution(
1276             ucb::IOErrorCode_CANT_CREATE,
1277             uno::Sequence< uno::Any >(&aProps, 1),
1278             rContext.xOrigEnv,
1279             rtl::OUString::createFromAscii(
1280                 "No matching content type at target!" ),
1281             rContext.xProcessor );
1282         // Unreachable
1283     }
1284 
1285     //////////////////////////////////////////////////////////////////////
1286     //
1287     // (2) Transfer property values from source to new object.
1288     //
1289     //////////////////////////////////////////////////////////////////////
1290 
1291     uno::Reference< ucb::XCommandProcessor > xCommandProcessorN(
1292                                                     xNew, uno::UNO_QUERY );
1293     if ( !xCommandProcessorN.is() )
1294     {
1295         uno::Any aProps
1296             = uno::makeAny(beans::PropertyValue(
1297                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1298                                                     "Uri")),
1299                                   -1,
1300                                   uno::makeAny(
1301                                       xNew->getIdentifier()->
1302                                                 getContentIdentifier()),
1303                                   beans::PropertyState_DIRECT_VALUE));
1304         ucbhelper::cancelCommandExecution(
1305             ucb::IOErrorCode_CANT_WRITE,
1306             uno::Sequence< uno::Any >(&aProps, 1),
1307             rContext.xOrigEnv,
1308             rtl::OUString::createFromAscii(
1309                 "New content is not a XCommandProcessor!" ),
1310             rContext.xProcessor );
1311         // Unreachable
1312     }
1313 
1314     // Obtain all properties from source.
1315 
1316     uno::Reference< ucb::XCommandProcessor > xCommandProcessorS(
1317                                                     xSource, uno::UNO_QUERY );
1318     if ( !xCommandProcessorS.is() )
1319     {
1320         uno::Any aProps
1321             = uno::makeAny(beans::PropertyValue(
1322                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1323                                                     "Uri")),
1324                                   -1,
1325                                   uno::makeAny(rContext.aArg.SourceURL),
1326                                   beans::PropertyState_DIRECT_VALUE));
1327         ucbhelper::cancelCommandExecution(
1328             ucb::IOErrorCode_CANT_READ,
1329             uno::Sequence< uno::Any >(&aProps, 1),
1330             rContext.xOrigEnv,
1331             rtl::OUString::createFromAscii(
1332                 "Source content is not a XCommandProcessor!" ),
1333             rContext.xProcessor );
1334         // Unreachable
1335     }
1336 
1337     transferProperties( rContext, xCommandProcessorS, xCommandProcessorN );
1338 
1339     //////////////////////////////////////////////////////////////////////
1340     //
1341     // (3) Try to obtain a data stream from source.
1342     //
1343     //////////////////////////////////////////////////////////////////////
1344 
1345     uno::Reference< io::XInputStream > xInputStream;
1346 
1347     if ( bSourceIsDocument && ( rContext.aArg.Operation
1348                                 != ucb::TransferCommandOperation_LINK ) )
1349         xInputStream = getInputStream( rContext, xCommandProcessorS );
1350 
1351     //////////////////////////////////////////////////////////////////////
1352     //
1353     // (4) Try to obtain a resultset (children) from source.
1354     //
1355     //////////////////////////////////////////////////////////////////////
1356 
1357     uno::Reference< sdbc::XResultSet > xResultSet;
1358 
1359     if ( bSourceIsFolder && ( rContext.aArg.Operation
1360                                 != ucb::TransferCommandOperation_LINK ) )
1361         xResultSet = getResultSet( rContext, xCommandProcessorS );
1362 
1363     //////////////////////////////////////////////////////////////////////
1364     //
1365     // (5) Insert (store) new content.
1366     //
1367     //////////////////////////////////////////////////////////////////////
1368 
1369     ucb::InsertCommandArgument aArg;
1370     aArg.Data = xInputStream;
1371 
1372     switch ( rContext.aArg.NameClash )
1373     {
1374         case ucb::NameClash::OVERWRITE:
1375             aArg.ReplaceExisting = sal_True;
1376             break;
1377 
1378         case ucb::NameClash::ERROR:
1379         case ucb::NameClash::RENAME:
1380         case ucb::NameClash::KEEP: // deprecated
1381         case ucb::NameClash::ASK:
1382             aArg.ReplaceExisting = sal_False;
1383             break;
1384 
1385         default:
1386             aArg.ReplaceExisting = sal_False;
1387             OSL_ENSURE( sal_False, "Unknown nameclash directive!" );
1388             break;
1389     }
1390 
1391     rtl::OUString aDesiredName = createDesiredName( rContext.aArg );
1392 
1393     bool bRetry;
1394     do
1395     {
1396         bRetry = false;
1397 
1398         try
1399         {
1400             ucb::Command aInsertCommand(
1401                                     rtl::OUString::createFromAscii( "insert" ),
1402                                     -1,
1403                                     uno::makeAny( aArg ) );
1404 
1405             xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
1406         }
1407         catch ( ucb::UnsupportedNameClashException const & exc )
1408         {
1409             OSL_ENSURE( !aArg.ReplaceExisting,
1410                         "BUG: UnsupportedNameClashException not allowed here!" );
1411 
1412             if (exc.NameClash != ucb::NameClash::ERROR) {
1413                 OSL_ENSURE( false, "BUG: NameClash::ERROR expected!" );
1414             }
1415 
1416             // No chance to solve name clashes, because I'm not able to detect
1417             // whether there is one.
1418             throw ucb::UnsupportedNameClashException(
1419                     rtl::OUString::createFromAscii(
1420                         "Unable to resolve name clashes, no chance to detect "
1421                         "that there is one!" ),
1422                     rContext.xProcessor,
1423                     rContext.aArg.NameClash );
1424         }
1425         catch ( ucb::NameClashException const & )
1426         {
1427             // The 'insert' command throws a NameClashException if the parameter
1428             // ReplaceExisting of the command's argument was set to false and
1429             // there exists a resource with a clashing name in the target folder
1430             // of the operation.
1431 
1432             // 'insert' command has no direct support for name clashes other
1433             // than ERROR ( ReplaceExisting == false ) and OVERWRITE
1434             // ( ReplaceExisting == true ). So we have to implement the
1435             // other name clash handling directives on top of the content.
1436 
1437             // @@@ 'insert' command should be extended that it accepts a
1438             //     name clash handling directive, exactly like 'transfer' command.
1439 
1440             switch ( rContext.aArg.NameClash )
1441             {
1442                 case ucb::NameClash::OVERWRITE:
1443                 {
1444                     ucbhelper::cancelCommandExecution(
1445                         uno::makeAny(
1446                             ucb::UnsupportedNameClashException(
1447                                 rtl::OUString::createFromAscii(
1448                                     "BUG: insert + replace == true MUST NOT "
1449                                     "throw NameClashException." ),
1450                                 rContext.xProcessor,
1451                                 rContext.aArg.NameClash ) ),
1452                         rContext.xOrigEnv );
1453                     // Unreachable
1454                 }
1455 
1456                 case ucb::NameClash::ERROR:
1457                     throw;
1458 
1459                 case ucb::NameClash::RENAME:
1460                 {
1461                     // "invent" a new valid title.
1462                     handleNameClashRename( rContext,
1463                                            xNew,
1464                                            xCommandProcessorN,
1465                                            xCommandProcessorS,
1466                                            xInputStream );
1467                     break;
1468                 }
1469 
1470                 case ucb::NameClash::ASK:
1471                     {
1472                         uno::Any aExc;
1473                         rtl::OUString aNewTitle;
1474                         NameClashContinuation eCont
1475                             = interactiveNameClashResolve(
1476                                 rContext.xOrigEnv, // always use original environment!
1477                                 rContext.aArg.TargetURL, // target folder URL
1478                                 aDesiredName,
1479                                 aExc,
1480                                 aNewTitle );
1481 
1482                         switch ( eCont )
1483                         {
1484                             case NOT_HANDLED:
1485                                 // Not handled.
1486                                 cppu::throwException( aExc );
1487     //                            break;
1488 
1489                             case UNKNOWN:
1490                                 // Handled, but not clear, how...
1491                                 // fall-thru intended.
1492 
1493                             case ABORT:
1494                                 throw ucb::CommandFailedException(
1495                                     rtl::OUString(
1496                                         RTL_CONSTASCII_USTRINGPARAM(
1497                                             "abort requested via interaction "
1498                                             "handler" ) ),
1499                                     uno::Reference< uno::XInterface >(),
1500                                     aExc );
1501     //                            break;
1502 
1503                             case OVERWRITE:
1504                                 OSL_ENSURE( aArg.ReplaceExisting == sal_False,
1505                                             "Hu? ReplaceExisting already true?"
1506                                           );
1507                                 aArg.ReplaceExisting = sal_True;
1508                                 bRetry = true;
1509                                 break;
1510 
1511                             case NEW_NAME:
1512                             {
1513                                 // set new name -> set "Title" property...
1514                                 if ( setTitle( xCommandProcessorN,
1515                                                rContext.xEnv,
1516                                                aNewTitle ) )
1517                                 {
1518                                     // remember suggested title...
1519                                     aDesiredName = aNewTitle;
1520 
1521                                     // ... and try again.
1522                                     bRetry = true;
1523                                 }
1524                                 else
1525                                 {
1526                                     // error setting title. Abort.
1527                                     throw ucb::CommandFailedException(
1528                                         rtl::OUString(
1529                                             RTL_CONSTASCII_USTRINGPARAM(
1530                                                 "error setting Title property!"
1531                                             ) ),
1532                                         uno::Reference< uno::XInterface >(),
1533                                         aExc );
1534                                 }
1535                                 break;
1536                             }
1537                         }
1538 
1539                         OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
1540                     }
1541                     break;
1542 
1543                 case ucb::NameClash::KEEP: // deprecated
1544                 default:
1545                 {
1546                     ucbhelper::cancelCommandExecution(
1547                         uno::makeAny(
1548                             ucb::UnsupportedNameClashException(
1549                                 rtl::OUString(
1550                                     RTL_CONSTASCII_USTRINGPARAM(
1551                                         "default action, don't know how to "
1552                                         "handle name clash" ) ),
1553                                 rContext.xProcessor,
1554                                 rContext.aArg.NameClash ) ),
1555                         rContext.xOrigEnv );
1556                     // Unreachable
1557                 }
1558             }
1559         }
1560     }
1561     while ( bRetry );
1562 
1563     //////////////////////////////////////////////////////////////////////
1564     //
1565     // (6) Process children of source.
1566     //
1567     //////////////////////////////////////////////////////////////////////
1568 
1569     if ( xResultSet.is() )
1570     {
1571         try
1572         {
1573             // Iterate over children...
1574 
1575             uno::Reference< sdbc::XRow > xChildRow(
1576                                             xResultSet, uno::UNO_QUERY );
1577 
1578             if ( !xChildRow.is() )
1579             {
1580                 uno::Any aProps
1581                     = uno::makeAny(
1582                              beans::PropertyValue(
1583                                  rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1584                                                    "Uri")),
1585                                  -1,
1586                                  uno::makeAny(rContext.aArg.SourceURL),
1587                                  beans::PropertyState_DIRECT_VALUE));
1588                 ucbhelper::cancelCommandExecution(
1589                     ucb::IOErrorCode_CANT_READ,
1590                     uno::Sequence< uno::Any >(&aProps, 1),
1591                     rContext.xOrigEnv,
1592                     rtl::OUString::createFromAscii(
1593                         "Unable to get properties from children of source!" ),
1594                     rContext.xProcessor );
1595                 // Unreachable
1596             }
1597 
1598             uno::Reference< ucb::XContentAccess > xChildAccess(
1599                                                 xResultSet, uno::UNO_QUERY );
1600 
1601             if ( !xChildAccess.is() )
1602             {
1603                 uno::Any aProps
1604                     = uno::makeAny(
1605                              beans::PropertyValue(
1606                                  rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1607                                      "Uri")),
1608                                  -1,
1609                                  uno::makeAny(rContext.aArg.SourceURL),
1610                                  beans::PropertyState_DIRECT_VALUE));
1611                 ucbhelper::cancelCommandExecution(
1612                     ucb::IOErrorCode_CANT_READ,
1613                     uno::Sequence< uno::Any >(&aProps, 1),
1614                     rContext.xOrigEnv,
1615                     rtl::OUString::createFromAscii(
1616                         "Unable to get children of source!" ),
1617                     rContext.xProcessor );
1618                 // Unreachable
1619             }
1620 
1621             if ( xResultSet->first() )
1622             {
1623                 ucb::GlobalTransferCommandArgument aTransArg(
1624                         rContext.aArg.Operation,      // Operation
1625                         rtl::OUString(),              // SourceURL; filled later
1626                         xNew->getIdentifier()
1627                             ->getContentIdentifier(), // TargetURL
1628                         rtl::OUString(),              // NewTitle;
1629                         rContext.aArg.NameClash );    // NameClash
1630 
1631                 TransferCommandContext aSubCtx(
1632                         rContext.xSMgr,
1633                         rContext.xProcessor,
1634                         rContext.xEnv,
1635                         rContext.xOrigEnv,
1636                         aTransArg );
1637                 do
1638                 {
1639                     uno::Reference< ucb::XContent > xChild
1640                                         = xChildAccess->queryContent();
1641                     if ( xChild.is() )
1642                     {
1643                         // Recursion!
1644 
1645                         aSubCtx.aArg.SourceURL
1646                             = xChild->getIdentifier()->getContentIdentifier();
1647 
1648                         globalTransfer_( aSubCtx,
1649                                          xChild,
1650                                          xNew,
1651                                          xChildRow );
1652                     }
1653                 }
1654                 while ( xResultSet->next() );
1655             }
1656         }
1657         catch ( sdbc::SQLException const & )
1658         {
1659         }
1660     }
1661 
1662     try {
1663         uno::Reference< ucb::XCommandProcessor > xcp(
1664             xTarget, uno::UNO_QUERY );
1665 
1666         uno::Any aAny;
1667         uno::Reference< ucb::XCommandInfo > xci;
1668         if(xcp.is())
1669             aAny =
1670                 xcp->execute(
1671                     ucb::Command(
1672                         rtl::OUString::createFromAscii("getCommandInfo"),
1673                         -1,
1674                         uno::Any()),
1675                     0,
1676                     rContext.xEnv );
1677 
1678         const rtl::OUString cmdName =
1679             rtl::OUString::createFromAscii("flush");
1680         if((aAny >>= xci) && xci->hasCommandByName(cmdName))
1681             xcp->execute(
1682                 ucb::Command(
1683                     cmdName,
1684                     -1,
1685                     uno::Any()) ,
1686                 0,
1687                 rContext.xEnv );
1688     }
1689     catch( uno::Exception const & )
1690     {
1691     }
1692 }
1693 
1694 } /* namescpace */
1695 
1696 //=========================================================================
1697 //
1698 // UniversalContentBroker implementation ( XCommandProcessor commands ).
1699 //
1700 //=========================================================================
1701 
1702 uno::Reference< ucb::XCommandInfo >
getCommandInfo()1703 UniversalContentBroker::getCommandInfo()
1704 {
1705     return uno::Reference< ucb::XCommandInfo >( new CommandProcessorInfo() );
1706 }
1707 
1708 //=========================================================================
globalTransfer(const ucb::GlobalTransferCommandArgument & rArg,const uno::Reference<ucb::XCommandEnvironment> & xEnv)1709 void UniversalContentBroker::globalTransfer(
1710             const ucb::GlobalTransferCommandArgument & rArg,
1711             const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1712 {
1713     // Use own command environment with own interaction handler intercepting
1714     // some interaction requests that shall not be handled by the user-supplied
1715     // interaction handler.
1716     uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
1717     if (xEnv.is())
1718     {
1719         uno::Reference< beans::XPropertySet > const xProps(
1720             m_xSMgr, uno::UNO_QUERY_THROW );
1721         uno::Reference< uno::XComponentContext > xCtx;
1722             xCtx.set( xProps->getPropertyValue(
1723                 rtl::OUString(
1724                     RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ),
1725                 uno::UNO_QUERY_THROW );
1726 
1727             xLocalEnv.set( ucb::CommandEnvironment::create(
1728                xCtx,
1729                new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
1730                xEnv->getProgressHandler() ) );
1731     }
1732 
1733     //////////////////////////////////////////////////////////////////////
1734     //
1735     // (1) Try to transfer the content using 'transfer' command.
1736     //
1737     //////////////////////////////////////////////////////////////////////
1738 
1739     uno::Reference< ucb::XContent > xTarget;
1740     uno::Reference< ucb::XContentIdentifier > xId
1741             = createContentIdentifier( rArg.TargetURL );
1742     if ( xId.is() )
1743     {
1744         try
1745         {
1746             xTarget = queryContent( xId );
1747         }
1748         catch ( ucb::IllegalIdentifierException const & )
1749         {
1750         }
1751     }
1752 
1753     if ( !xTarget.is() )
1754     {
1755         uno::Any aProps
1756             = uno::makeAny(beans::PropertyValue(
1757                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1758                                       "Uri")),
1759                                   -1,
1760                                   uno::makeAny(rArg.TargetURL),
1761                                   beans::PropertyState_DIRECT_VALUE));
1762         ucbhelper::cancelCommandExecution(
1763             ucb::IOErrorCode_CANT_READ,
1764             uno::Sequence< uno::Any >(&aProps, 1),
1765             xEnv,
1766             rtl::OUString::createFromAscii(
1767                 "Can't instantiate target object!" ),
1768             this );
1769         // Unreachable
1770     }
1771 
1772     if ( ( rArg.Operation == ucb::TransferCommandOperation_COPY ) ||
1773          ( rArg.Operation == ucb::TransferCommandOperation_MOVE ) )
1774     {
1775         uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
1776                                                     xTarget, uno::UNO_QUERY );
1777         if ( !xCommandProcessor.is() )
1778         {
1779             uno::Any aProps
1780                 = uno::makeAny(
1781                          beans::PropertyValue(
1782                              rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1783                                                "Uri")),
1784                              -1,
1785                              uno::makeAny(rArg.TargetURL),
1786                              beans::PropertyState_DIRECT_VALUE));
1787             ucbhelper::cancelCommandExecution(
1788                 ucb::IOErrorCode_CANT_READ,
1789                 uno::Sequence< uno::Any >(&aProps, 1),
1790                 xEnv,
1791                 rtl::OUString::createFromAscii(
1792                     "Target content is not a XCommandProcessor!" ),
1793                 this );
1794             // Unreachable
1795         }
1796 
1797         ucb::TransferInfo aTransferArg(
1798             ( rArg.Operation
1799                 == ucb::TransferCommandOperation_MOVE ), // MoveData
1800             rArg.SourceURL,   // SourceURL
1801             rArg.NewTitle,    // NewTitle
1802             rArg.NameClash ); // NameClash
1803 
1804         bool bRetry;
1805         do
1806         {
1807             bRetry = false;
1808 
1809             try
1810             {
1811                 ucb::Command aCommand(
1812                     rtl::OUString::createFromAscii( "transfer" ), // Name
1813                     -1,                                           // Handle
1814                     uno::makeAny( aTransferArg ) );               // Argument
1815 
1816                 xCommandProcessor->execute( aCommand, 0, xLocalEnv );
1817 
1818                 // Command succeeded. We're done.
1819                 return;
1820             }
1821             catch ( ucb::InteractiveBadTransferURLException const & )
1822             {
1823                 // Source URL is not supported by target. Try to transfer
1824                 // the content "manually".
1825             }
1826             catch ( ucb::UnsupportedCommandException const & )
1827             {
1828                 // 'transfer' command is not supported by commandprocessor.
1829                 // Try to transfer manually.
1830             }
1831             catch ( ucb::UnsupportedNameClashException const & exc )
1832             {
1833                 OSL_ENSURE( aTransferArg.NameClash == exc.NameClash,
1834                             "nameclash mismatch!" );
1835                 if ( exc.NameClash == ucb::NameClash::ASK )
1836                 {
1837                     // Try to detect a name clash by invoking "transfer" with
1838                     // NameClash::ERROR.
1839                     try
1840                     {
1841                         ucb::TransferInfo aTransferArg1(
1842                             aTransferArg.MoveData,
1843                             aTransferArg.SourceURL,
1844                             aTransferArg.NewTitle,
1845                             ucb::NameClash::ERROR );
1846 
1847                         ucb::Command aCommand1(
1848                             rtl::OUString::createFromAscii( "transfer" ),
1849                             -1,
1850                             uno::makeAny( aTransferArg1 ) );
1851 
1852                         xCommandProcessor->execute( aCommand1, 0, xLocalEnv );
1853 
1854                         // Command succeeded. We're done.
1855                         return;
1856                     }
1857                     catch ( ucb::UnsupportedNameClashException const & )
1858                     {
1859                         // No chance to solve name clashes, because I'm not
1860                         // able to detect whether there is one.
1861                         throw exc; // Not just 'throw;'!
1862                     }
1863                     catch ( ucb::NameClashException const & )
1864                     {
1865                         // There's a clash. Use interaction handler to solve it.
1866 
1867                         uno::Any aExc;
1868                         rtl::OUString aNewTitle;
1869                         NameClashContinuation eCont
1870                             = interactiveNameClashResolve(
1871                                 xEnv, // always use original environment!
1872                                 rArg.TargetURL,  // target folder URL
1873                                 createDesiredName(
1874                                   aTransferArg ),   // clashing name
1875                                 aExc,
1876                                 aNewTitle );
1877 
1878                         switch ( eCont )
1879                         {
1880                             case NOT_HANDLED:
1881                                 // Not handled.
1882                                 cppu::throwException( aExc );
1883 //                                break;
1884 
1885                             case UNKNOWN:
1886                                 // Handled, but not clear, how...
1887                                 // fall-thru intended.
1888 
1889                             case ABORT:
1890                                 throw ucb::CommandFailedException(
1891                                     rtl::OUString(
1892                                         RTL_CONSTASCII_USTRINGPARAM(
1893                                             "abort requested via interaction "
1894                                             "handler" ) ),
1895                                     uno::Reference< uno::XInterface >(),
1896                                     aExc );
1897 //                                break;
1898 
1899                             case OVERWRITE:
1900                                 aTransferArg.NameClash
1901                                     = ucb::NameClash::OVERWRITE;
1902                                 bRetry = true;
1903                                 break;
1904 
1905                             case NEW_NAME:
1906                                 aTransferArg.NewTitle = aNewTitle;
1907                                 bRetry = true;
1908                                 break;
1909                         }
1910 
1911                         OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
1912                     }
1913                 }
1914                 else
1915                 {
1916                     throw;
1917                 }
1918             }
1919         }
1920         while ( bRetry );
1921     }
1922 
1923     //////////////////////////////////////////////////////////////////////
1924     //
1925     // (2) Try to transfer the content "manually".
1926     //
1927     //////////////////////////////////////////////////////////////////////
1928 
1929     uno::Reference< ucb::XContent > xSource;
1930     try
1931     {
1932         uno::Reference< ucb::XContentIdentifier > xId2
1933             = createContentIdentifier( rArg.SourceURL );
1934         if ( xId2.is() )
1935             xSource = queryContent( xId2 );
1936     }
1937     catch ( ucb::IllegalIdentifierException const & )
1938     {
1939         // Error handling via "if ( !xSource.is() )" below.
1940     }
1941 
1942     if ( !xSource.is() )
1943     {
1944         uno::Any aProps
1945             = uno::makeAny(beans::PropertyValue(
1946                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1947                                                     "Uri")),
1948                                   -1,
1949                                   uno::makeAny(rArg.SourceURL),
1950                                   beans::PropertyState_DIRECT_VALUE));
1951         ucbhelper::cancelCommandExecution(
1952             ucb::IOErrorCode_CANT_READ,
1953             uno::Sequence< uno::Any >(&aProps, 1),
1954             xEnv,
1955             rtl::OUString::createFromAscii(
1956                 "Can't instantiate source object!" ),
1957             this );
1958         // Unreachable
1959     }
1960 
1961     uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
1962                                                 xSource, uno::UNO_QUERY );
1963     if ( !xCommandProcessor.is() )
1964     {
1965         uno::Any aProps
1966             = uno::makeAny(beans::PropertyValue(
1967                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1968                                                     "Uri")),
1969                                   -1,
1970                                   uno::makeAny(rArg.SourceURL),
1971                                   beans::PropertyState_DIRECT_VALUE));
1972         ucbhelper::cancelCommandExecution(
1973             ucb::IOErrorCode_CANT_READ,
1974             uno::Sequence< uno::Any >(&aProps, 1),
1975             xEnv,
1976             rtl::OUString::createFromAscii(
1977                 "Source content is not a XCommandProcessor!" ),
1978             this );
1979         // Unreachable
1980     }
1981 
1982     // Obtain interesting property values from source...
1983 
1984     uno::Sequence< beans::Property > aProps( 4 );
1985 
1986     aProps[ 0 ].Name   = rtl::OUString::createFromAscii( "IsFolder" );
1987     aProps[ 0 ].Handle = -1; /* unknown */
1988     aProps[ 1 ].Name   = rtl::OUString::createFromAscii( "IsDocument" );
1989     aProps[ 1 ].Handle = -1; /* unknown */
1990     aProps[ 2 ].Name   = rtl::OUString::createFromAscii( "TargetURL" );
1991     aProps[ 2 ].Handle = -1; /* unknown */
1992     aProps[ 3 ].Name   = rtl::OUString::createFromAscii( "BaseURI" );
1993     aProps[ 3 ].Handle = -1; /* unknown */
1994 
1995     ucb::Command aGetPropsCommand(
1996                 rtl::OUString::createFromAscii( "getPropertyValues" ),
1997                 -1,
1998                 uno::makeAny( aProps ) );
1999 
2000     uno::Reference< sdbc::XRow > xRow;
2001     xCommandProcessor->execute( aGetPropsCommand, 0, xLocalEnv ) >>= xRow;
2002 
2003     if ( !xRow.is() )
2004     {
2005         uno::Any aProps2
2006             = uno::makeAny(beans::PropertyValue(
2007                                   rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2008                                                     "Uri")),
2009                                   -1,
2010                                   uno::makeAny(rArg.SourceURL),
2011                                   beans::PropertyState_DIRECT_VALUE));
2012         ucbhelper::cancelCommandExecution(
2013             ucb::IOErrorCode_CANT_READ,
2014             uno::Sequence< uno::Any >(&aProps2, 1),
2015             xEnv,
2016             rtl::OUString::createFromAscii(
2017                 "Unable to get properties from source object!" ),
2018             this );
2019         // Unreachable
2020     }
2021 
2022     TransferCommandContext aTransferCtx(
2023         m_xSMgr, this, xLocalEnv, xEnv, rArg );
2024 
2025     if ( rArg.NewTitle.getLength() == 0 )
2026     {
2027         // BaseURI: property is optional.
2028         rtl::OUString aBaseURI( xRow->getString( 4 ) );
2029         if ( aBaseURI.getLength() )
2030         {
2031             aTransferCtx.aArg.NewTitle
2032                 = createDesiredName( aBaseURI, rtl::OUString() );
2033         }
2034     }
2035 
2036     // Do it!
2037     globalTransfer_( aTransferCtx, xSource, xTarget, xRow );
2038 
2039     //////////////////////////////////////////////////////////////////////
2040     //
2041     // (3) Delete source, if operation is MOVE.
2042     //
2043     //////////////////////////////////////////////////////////////////////
2044 
2045     if ( rArg.Operation == ucb::TransferCommandOperation_MOVE )
2046     {
2047         try
2048         {
2049             ucb::Command aCommand(
2050                 rtl::OUString::createFromAscii( "delete" ), // Name
2051                 -1,                                         // Handle
2052                 uno::makeAny( sal_Bool( sal_True ) ) );     // Argument
2053 
2054             xCommandProcessor->execute( aCommand, 0, xLocalEnv );
2055         }
2056         catch ( uno::Exception const & )
2057         {
2058             OSL_ENSURE( sal_False, "Cannot delete source object!" );
2059             throw;
2060         }
2061     }
2062 }
2063