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