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