1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/macros.h>
22 #include <unotools/ucblockbytes.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <salhelper/condition.hxx>
25 #include <osl/thread.hxx>
26 #include <tools/urlobj.hxx>
27 #include <ucbhelper/interactionrequest.hxx>
28 #include <com/sun/star/task/XInteractionAbort.hpp>
29 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
30 #include <com/sun/star/ucb/CommandFailedException.hpp>
31 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
32 #include <com/sun/star/ucb/InteractiveIOException.hpp>
33 #include <com/sun/star/io/XActiveDataStreamer.hpp>
34 #include <com/sun/star/io/TempFile.hpp>
35 #include <com/sun/star/ucb/DocumentHeaderField.hpp>
36 #include <com/sun/star/ucb/XCommandInfo.hpp>
37 #include <com/sun/star/ucb/XCommandProcessor.hpp>
38 #include <com/sun/star/task/XInteractionHandler.hpp>
39 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
40 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
41 #include <com/sun/star/ucb/OpenMode.hpp>
42 #include <com/sun/star/beans/Property.hpp>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/beans/XPropertiesChangeNotifier.hpp>
45 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
46 #include <com/sun/star/sdbc/XRow.hpp>
47 #include <com/sun/star/io/XActiveDataSink.hpp>
48 #include <com/sun/star/io/XActiveDataControl.hpp>
49 #include <com/sun/star/io/XSeekable.hpp>
50 #include <cppuhelper/implbase1.hxx>
51 #include <cppuhelper/implbase2.hxx>
52 #include <tools/inetmsg.hxx>
53 #include <com/sun/star/io/XTruncate.hpp>
54 #include <com/sun/star/lang/IllegalArgumentException.hpp>
56 #include <comphelper/storagehelper.hxx>
57 #include <ucbhelper/content.hxx>
59 using namespace ::com::sun::star::uno
;
60 using namespace ::com::sun::star::io
;
61 using namespace ::com::sun::star::ucb
;
62 using namespace ::com::sun::star::task
;
63 using namespace ::com::sun::star::lang
;
64 using namespace ::com::sun::star::beans
;
71 Helper class for getting a XInputStream when opening a content
73 class UcbDataSink_Impl
: public ::cppu::WeakImplHelper2
< XActiveDataControl
, XActiveDataSink
>
75 UcbLockBytesRef m_xLockBytes
;
78 UcbDataSink_Impl( UcbLockBytes
* pLockBytes
)
79 : m_xLockBytes( pLockBytes
)
82 SvLockBytes
* getLockBytes (void)
83 { return m_xLockBytes
; }
85 // XActiveDataControl.
86 virtual void SAL_CALL
addListener ( const Reference
<XStreamListener
> &/*rxListener*/) throw(RuntimeException
) {}
87 virtual void SAL_CALL
removeListener ( const Reference
<XStreamListener
> &/*rxListener*/) throw(RuntimeException
) {}
88 virtual void SAL_CALL
start (void) throw(RuntimeException
) {}
89 virtual void SAL_CALL
terminate (void) throw(RuntimeException
)
90 { m_xLockBytes
->terminate_Impl(); }
93 virtual void SAL_CALL
setInputStream ( const Reference
<XInputStream
> &rxInputStream
) throw(RuntimeException
)
94 { m_xLockBytes
->setInputStream_Impl (rxInputStream
); }
95 virtual Reference
<XInputStream
> SAL_CALL
getInputStream (void) throw(RuntimeException
)
96 { return m_xLockBytes
->getInputStream_Impl(); }
100 Helper class for getting a XStream when opening a content
102 class UcbStreamer_Impl
: public ::cppu::WeakImplHelper2
< XActiveDataStreamer
, XActiveDataControl
>
104 Reference
< XStream
> m_xStream
;
105 UcbLockBytesRef m_xLockBytes
;
108 UcbStreamer_Impl( UcbLockBytes
* pLockBytes
)
109 : m_xLockBytes( pLockBytes
)
112 // XActiveDataControl.
113 virtual void SAL_CALL
addListener ( const Reference
<XStreamListener
> &/*rxListener*/) throw(RuntimeException
) {}
114 virtual void SAL_CALL
removeListener ( const Reference
<XStreamListener
> &/*rxListener*/) throw(RuntimeException
) {}
115 virtual void SAL_CALL
start (void) throw(RuntimeException
) {}
116 virtual void SAL_CALL
terminate (void) throw(RuntimeException
)
117 { m_xLockBytes
->terminate_Impl(); }
119 // XActiveDataStreamer
120 virtual void SAL_CALL
setStream( const Reference
< XStream
>& aStream
) throw(RuntimeException
)
121 { m_xStream
= aStream
; m_xLockBytes
->setStream_Impl( aStream
); }
122 virtual Reference
< XStream
> SAL_CALL
getStream() throw(RuntimeException
)
123 { return m_xStream
; }
127 Helper class for progress handling while executing UCB commands
129 class ProgressHandler_Impl
: public ::cppu::WeakImplHelper1
< XProgressHandler
>
134 ProgressHandler_Impl( const Link
& rLink
)
135 : m_aProgress( rLink
)
138 virtual void SAL_CALL
push(const Any
& /*rStatus*/) throw (RuntimeException
) {}
139 virtual void SAL_CALL
pop() throw (RuntimeException
) {}
140 virtual void SAL_CALL
update(const Any
& /*rStatus*/) throw (RuntimeException
)
141 { if ( m_aProgress
.IsSet() ) m_aProgress
.Call( 0 ); }
145 Helper class for managing interactions and progress when executing UCB commands
147 class UcbTaskEnvironment
: public ::cppu::WeakImplHelper1
< XCommandEnvironment
>
149 Reference
< XInteractionHandler
> m_xInteractionHandler
;
150 Reference
< XProgressHandler
> m_xProgressHandler
;
153 UcbTaskEnvironment( const Reference
< XInteractionHandler
>& rxInteractionHandler
,
154 const Reference
< XProgressHandler
>& rxProgressHandler
)
155 : m_xInteractionHandler( rxInteractionHandler
)
156 , m_xProgressHandler( rxProgressHandler
)
159 virtual Reference
<XInteractionHandler
> SAL_CALL
getInteractionHandler() throw (RuntimeException
)
160 { return m_xInteractionHandler
; }
162 virtual Reference
<XProgressHandler
> SAL_CALL
getProgressHandler() throw (RuntimeException
)
163 { return m_xProgressHandler
; }
168 Helper class for property change notifies when executing UCB commands
170 class UcbPropertiesChangeListener_Impl
: public ::cppu::WeakImplHelper1
< XPropertiesChangeListener
>
173 UcbLockBytesRef m_xLockBytes
;
175 UcbPropertiesChangeListener_Impl( UcbLockBytesRef rRef
)
176 : m_xLockBytes( rRef
)
179 virtual void SAL_CALL
disposing ( const EventObject
&/*rEvent*/) throw(RuntimeException
) {}
180 virtual void SAL_CALL
propertiesChange ( const Sequence
<PropertyChangeEvent
> &rEvent
) throw(RuntimeException
);
183 void SAL_CALL
UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence
<PropertyChangeEvent
> &rEvent
) throw(RuntimeException
)
185 sal_Int32 i
, n
= rEvent
.getLength();
186 for (i
= 0; i
< n
; i
++)
188 PropertyChangeEvent
evt (rEvent
[i
]);
189 if (evt
.PropertyName
== OUString("DocumentHeader"))
191 Sequence
<DocumentHeaderField
> aHead
;
192 if (evt
.NewValue
>>= aHead
)
194 sal_Int32 k
, m
= aHead
.getLength();
195 for (k
= 0; k
< m
; k
++)
197 String
aName( aHead
[k
].Name
);
198 String
aValue( aHead
[k
].Value
);
200 if (aName
.CompareIgnoreCaseToAscii("Expires") == COMPARE_EQUAL
)
202 DateTime
aExpires (0, 0);
203 if (INetRFC822Message::ParseDateField (aValue
, aExpires
))
205 aExpires
.ConvertToLocalTime();
206 m_xLockBytes
->SetExpireDate_Impl( aExpires
);
212 m_xLockBytes
->SetStreamValid_Impl();
214 else if (evt
.PropertyName
== OUString("PresentationURL"))
217 if (evt
.NewValue
>>= aUrl
)
219 OUString
aBad ("private:");
220 if (!aUrl
.startsWith(aBad
))
222 // URL changed (Redirection).
223 m_xLockBytes
->SetRealURL_Impl( aUrl
);
227 else if (evt
.PropertyName
== OUString("MediaType"))
229 OUString aContentType
;
230 if (evt
.NewValue
>>= aContentType
)
231 m_xLockBytes
->SetContentType_Impl( aContentType
);
241 // usage restriction:
242 // It might be possible, that the call to the interactionhandler and/or
243 // progresshandler is done asynchrounsly, while the 'execute' simply
244 // returns. This would imply that these class must be refcounted !!!
248 Reference
< XContent
>& xContent
,
249 Reference
< XInteractionHandler
>& xInteract
,
250 Reference
< XProgressHandler
>& xProgress
,
254 ContentCreationException
,
264 INTERACTIONREQUEST
, // reply expected
284 : public salhelper::Condition
287 ConditionRes(osl::Mutex
& aMutex
,Moderator
& aModerator
)
288 : salhelper::Condition(aMutex
),
289 m_aModerator(aModerator
)
294 bool applies() const {
295 return m_aModerator
.m_aResultType
!= NORESULT
;
299 Moderator
& m_aModerator
;
306 sal_Int32 ioErrorCode
;
309 Result
getResult(const sal_uInt32 milliSec
);
319 : public salhelper::Condition
322 ConditionRep(osl::Mutex
& aMutex
,Moderator
& aModerator
)
323 : salhelper::Condition(aMutex
),
324 m_aModerator(aModerator
)
329 bool applies() const {
330 return m_aModerator
.m_aReplyType
!= NOREPLY
;
334 Moderator
& m_aModerator
;
337 void setReply(ReplyType
);
339 void handle( const Reference
<XInteractionRequest
>& Request
);
340 void push( const Any
& Status
);
341 void update( const Any
& Status
);
344 void setStream(const Reference
< XStream
>& aStream
);
345 void setInputStream(const Reference
<XInputStream
> &rxInputStream
);
349 virtual void SAL_CALL
run();
350 virtual void SAL_CALL
onTerminated();
355 friend class ConditionRes
;
358 ResultType m_aResultType
;
359 sal_Int32 m_nIOErrorCode
;
362 friend class ConditionRep
;
365 ReplyType m_aReplyType
;
368 ::ucbhelper::Content m_aContent
;
372 class ModeratorsActiveDataStreamer
373 : public ::cppu::WeakImplHelper1
<XActiveDataStreamer
>
377 ModeratorsActiveDataStreamer(Moderator
&theModerator
);
379 ~ModeratorsActiveDataStreamer();
381 // XActiveDataStreamer
382 virtual void SAL_CALL
384 const Reference
< XStream
>& aStream
390 virtual Reference
<XStream
> SAL_CALL
397 osl::MutexGuard
aGuard(m_aMutex
);
403 Moderator
& m_aModerator
;
406 Reference
<XStream
> m_xStream
;
410 class ModeratorsActiveDataSink
411 : public ::cppu::WeakImplHelper1
<XActiveDataSink
>
415 ModeratorsActiveDataSink(Moderator
&theModerator
);
417 ~ModeratorsActiveDataSink();
420 virtual void SAL_CALL
422 const Reference
<XInputStream
> &rxInputStream
428 virtual Reference
<XInputStream
> SAL_CALL
435 osl::MutexGuard
aGuard(m_aMutex
);
441 Moderator
& m_aModerator
;
443 Reference
<XInputStream
> m_xStream
;
448 ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator
&theModerator
)
449 : m_aModerator(theModerator
)
454 ModeratorsActiveDataSink::~ModeratorsActiveDataSink()
460 ModeratorsActiveDataSink::setInputStream (
461 const Reference
<XInputStream
> &rxInputStream
467 m_aModerator
.setInputStream(rxInputStream
);
468 osl::MutexGuard
aGuard(m_aMutex
);
469 m_xStream
= rxInputStream
;
473 ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer(
474 Moderator
&theModerator
476 : m_aModerator(theModerator
)
481 ModeratorsActiveDataStreamer::~ModeratorsActiveDataStreamer()
485 // XActiveDataStreamer.
487 ModeratorsActiveDataStreamer::setStream (
488 const Reference
<XStream
> &rxStream
494 m_aModerator
.setStream(rxStream
);
495 osl::MutexGuard
aGuard(m_aMutex
);
496 m_xStream
= rxStream
;
501 class ModeratorsInteractionHandler
502 : public ::cppu::WeakImplHelper1
<XInteractionHandler
>
506 ModeratorsInteractionHandler(Moderator
&theModerator
);
508 ~ModeratorsInteractionHandler();
510 virtual void SAL_CALL
511 handle( const Reference
<XInteractionRequest
>& Request
)
512 throw (RuntimeException
);
516 Moderator
& m_aModerator
;
520 class ModeratorsProgressHandler
521 : public ::cppu::WeakImplHelper1
<XProgressHandler
>
524 ModeratorsProgressHandler(Moderator
&theModerator
);
526 ~ModeratorsProgressHandler();
528 virtual void SAL_CALL
push( const Any
& Status
)
532 virtual void SAL_CALL
update( const Any
& Status
)
533 throw (RuntimeException
);
535 virtual void SAL_CALL
pop( )
536 throw (RuntimeException
);
540 Moderator
& m_aModerator
;
544 ModeratorsProgressHandler::ModeratorsProgressHandler(Moderator
&theModerator
)
545 : m_aModerator(theModerator
)
549 ModeratorsProgressHandler::~ModeratorsProgressHandler()
554 void SAL_CALL
ModeratorsProgressHandler::push( const Any
& Status
)
558 m_aModerator
.push(Status
);
562 void SAL_CALL
ModeratorsProgressHandler::update( const Any
& Status
)
563 throw (RuntimeException
)
565 m_aModerator
.update(Status
);
569 void SAL_CALL
ModeratorsProgressHandler::pop( )
570 throw (RuntimeException
)
576 ModeratorsInteractionHandler::ModeratorsInteractionHandler(
577 Moderator
&aModerator
)
578 : m_aModerator(aModerator
)
583 ModeratorsInteractionHandler::~ModeratorsInteractionHandler()
589 ModeratorsInteractionHandler::handle(
590 const Reference
<XInteractionRequest
>& Request
596 // wakes up the mainthread
597 m_aModerator
.handle(Request
);
603 Moderator::Moderator(
604 Reference
< XContent
>& xContent
,
605 Reference
< XInteractionHandler
>& xInteract
,
606 Reference
< XProgressHandler
>& xProgress
,
610 ::com::sun::star::ucb::ContentCreationException
,
611 ::com::sun::star::uno::RuntimeException
615 m_aRes(m_aMutex
,*this),
616 m_aResultType(NORESULT
),
620 m_aRep(m_aMutex
,*this),
621 m_aReplyType(NOREPLY
),
626 new UcbTaskEnvironment(
627 xInteract
.is() ? new ModeratorsInteractionHandler(*this) : 0,
628 xProgress
.is() ? new ModeratorsProgressHandler(*this) : 0),
629 comphelper::getProcessComponentContext())
631 // now exchange the whole data sink stuff
632 // with a thread safe version
634 Reference
<XInterface
> *pxSink
= NULL
;
636 PostCommandArgument2 aPostArg
;
637 OpenCommandArgument2 aOpenArg
;
640 if(m_aArg
.Argument
>>= aPostArg
) {
641 pxSink
= &aPostArg
.Sink
;
644 else if(m_aArg
.Argument
>>= aOpenArg
) {
645 pxSink
= &aOpenArg
.Sink
;
650 throw ContentCreationException();
652 Reference
< XActiveDataSink
> xActiveSink(*pxSink
,UNO_QUERY
);
654 *pxSink
= Reference
<XInterface
>(
655 (cppu::OWeakObject
*)new ModeratorsActiveDataSink(*this));
657 Reference
<XActiveDataStreamer
> xStreamer( *pxSink
, UNO_QUERY
);
658 if ( xStreamer
.is() )
659 *pxSink
= Reference
<XInterface
>(
660 (cppu::OWeakObject
*)new ModeratorsActiveDataStreamer(*this));
663 m_aArg
.Argument
<<= aPostArg
;
665 m_aArg
.Argument
<<= aOpenArg
;
669 Moderator::~Moderator()
674 Moderator::Result
Moderator::getResult(const sal_uInt32 milliSec
)
678 salhelper::ConditionWaiter
aWaiter(m_aRes
,milliSec
);
679 ret
.type
= m_aResultType
;
680 ret
.result
= m_aResult
;
681 ret
.ioErrorCode
= m_nIOErrorCode
;
684 m_aResultType
= NORESULT
;
686 catch (const salhelper::ConditionWaiter::timedout
&)
695 void Moderator::setReply(ReplyType aReplyType
)
697 salhelper::ConditionModifier
aMod(m_aRep
);
698 m_aReplyType
= aReplyType
;
702 void Moderator::handle( const Reference
<XInteractionRequest
>& Request
)
704 ReplyType aReplyType
;
708 salhelper::ConditionModifier
aMod(m_aRes
);
709 m_aResultType
= INTERACTIONREQUEST
;
710 m_aResult
<<= Request
;
714 salhelper::ConditionWaiter
aWait(m_aRep
);
715 aReplyType
= m_aReplyType
;
718 m_aReplyType
= NOREPLY
;
721 if(aReplyType
== EXIT
) {
722 Sequence
<Reference
<XInteractionContinuation
> > aSeq(
723 Request
->getContinuations());
724 for(sal_Int32 i
= 0; i
< aSeq
.getLength(); ++i
) {
725 Reference
<XInteractionAbort
> aRef(aSeq
[i
],UNO_QUERY
);
731 // resignal the exitcondition
735 } while(aReplyType
!= REQUESTHANDLED
);
739 void Moderator::push( const Any
& Status
)
742 salhelper::ConditionModifier
aMod(m_aRes
);
743 m_aResultType
= PROGRESSPUSH
;
746 ReplyType aReplyType
;
748 salhelper::ConditionWaiter
aWait(m_aRep
);
749 aReplyType
= m_aReplyType
;
750 m_aReplyType
= NOREPLY
;
752 if(aReplyType
== EXIT
)
757 void Moderator::update( const Any
& Status
)
760 salhelper::ConditionModifier
aMod(m_aRes
);
761 m_aResultType
= PROGRESSUPDATE
;
764 ReplyType aReplyType
;
766 salhelper::ConditionWaiter
aWait(m_aRep
);
767 aReplyType
= m_aReplyType
;
768 m_aReplyType
= NOREPLY
;
770 if(aReplyType
== EXIT
)
775 void Moderator::pop( )
778 salhelper::ConditionModifier
aMod(m_aRes
);
779 m_aResultType
= PROGRESSPOP
;
781 ReplyType aReplyType
;
783 salhelper::ConditionWaiter
aWait(m_aRep
);
784 aReplyType
= m_aReplyType
;
785 m_aReplyType
= NOREPLY
;
787 if(aReplyType
== EXIT
)
792 void Moderator::setStream(const Reference
< XStream
>& aStream
)
795 salhelper::ConditionModifier
aMod(m_aRes
);
796 m_aResultType
= STREAM
;
797 m_aResult
<<= aStream
;
799 ReplyType aReplyType
;
801 salhelper::ConditionWaiter
aWait(m_aRep
);
802 aReplyType
= m_aReplyType
;
803 m_aReplyType
= NOREPLY
;
805 if(aReplyType
== EXIT
)
810 void Moderator::setInputStream(const Reference
<XInputStream
> &rxInputStream
)
813 salhelper::ConditionModifier
aMod(m_aRes
);
814 m_aResultType
= INPUTSTREAM
;
815 m_aResult
<<= rxInputStream
;
817 ReplyType aReplyType
;
819 salhelper::ConditionWaiter
aWait(m_aRep
);
820 aReplyType
= m_aReplyType
;
821 m_aReplyType
= NOREPLY
;
823 if(aReplyType
== EXIT
)
828 void SAL_CALL
Moderator::run()
830 ResultType aResultType
;
832 sal_Int32 nIOErrorCode
= 0;
836 aResult
= m_aContent
.executeCommand(m_aArg
.Name
,m_aArg
.Argument
);
837 aResultType
= RESULT
;
839 catch (const CommandAbortedException
&)
841 aResultType
= COMMANDABORTED
;
843 catch (const CommandFailedException
&)
845 aResultType
= COMMANDFAILED
;
847 catch (const InteractiveIOException
& r
)
849 nIOErrorCode
= r
.Code
;
850 aResultType
= INTERACTIVEIO
;
852 catch (const UnsupportedDataSinkException
&)
854 aResultType
= UNSUPPORTED
;
856 catch (const Exception
&)
858 aResultType
= GENERAL
;
862 salhelper::ConditionModifier
aMod(m_aRes
);
863 m_aResultType
= aResultType
;
865 m_nIOErrorCode
= nIOErrorCode
;
869 void SAL_CALL
Moderator::onTerminated()
872 salhelper::ConditionWaiter
aWaiter(m_aRep
);
878 Function for opening UCB contents synchronously,
879 but with handled timeout;
881 static sal_Bool
_UCBOpenContentSync(
882 UcbLockBytesRef xLockBytes
,
883 Reference
< XContent
> xContent
,
885 Reference
< XInterface
> xSink
,
886 Reference
< XInteractionHandler
> xInteract
,
887 Reference
< XProgressHandler
> xProgress
,
888 UcbLockBytesHandlerRef xHandler
);
891 static sal_Bool
UCBOpenContentSync(
892 UcbLockBytesRef xLockBytes
,
893 Reference
< XContent
> xContent
,
895 Reference
< XInterface
> xSink
,
896 Reference
< XInteractionHandler
> xInteract
,
897 Reference
< XProgressHandler
> xProgress
,
898 UcbLockBytesHandlerRef xHandler
)
900 // http protocol must be handled in a special way:
901 // during the opening process the input stream may change
902 // only the last inputstream after notifying the document
905 Reference
<XContentIdentifier
> xContId(
906 xContent
.is() ? xContent
->getIdentifier() : 0 );
910 aScheme
= xContId
->getContentProviderScheme();
912 // now determine whether we use a timeout or not;
913 if( ! aScheme
.equalsIgnoreAsciiCase("http") &&
914 ! aScheme
.equalsIgnoreAsciiCase("https") &&
915 ! aScheme
.equalsIgnoreAsciiCase("vnd.sun.star.webdav") &&
916 ! aScheme
.equalsIgnoreAsciiCase("ftp"))
917 return _UCBOpenContentSync(
918 xLockBytes
,xContent
,rArg
,xSink
,xInteract
,xProgress
,xHandler
);
920 if ( (aScheme
.compareToAscii( "http" ) != COMPARE_EQUAL
) ||
921 (aScheme
.compareToAscii( "https" ) != COMPARE_EQUAL
) )
922 xLockBytes
->SetStreamValid_Impl();
924 Reference
< XPropertiesChangeListener
> xListener
;
925 Reference
< XPropertiesChangeNotifier
> xProps(xContent
,UNO_QUERY
);
928 new UcbPropertiesChangeListener_Impl(xLockBytes
);
929 xProps
->addPropertiesChangeListener(
930 Sequence
< OUString
>(),
935 bool bException(false);
936 bool bAborted(false);
937 bool bResultAchieved(false);
942 pMod
= new Moderator(xContent
,xInteract
,xProgress
,rArg
);
945 catch (const ContentCreationException
&)
947 bResultAchieved
= bException
= true;
948 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
951 sal_uInt32
nTimeout(5000); // initially 5000 milliSec
952 while(!bResultAchieved
) {
954 Moderator::Result res
;
955 // try to get the result for with timeout
956 res
= pMod
->getResult(nTimeout
);
959 case Moderator::PROGRESSPUSH
:
962 xProgress
->push(res
.result
);
963 pMod
->setReply(Moderator::REQUESTHANDLED
);
966 case Moderator::PROGRESSUPDATE
:
969 xProgress
->update(res
.result
);
970 pMod
->setReply(Moderator::REQUESTHANDLED
);
973 case Moderator::PROGRESSPOP
:
977 pMod
->setReply(Moderator::REQUESTHANDLED
);
980 case Moderator::STREAM
:
982 Reference
<XStream
> result
;
983 if(res
.result
>>= result
) {
984 Reference
< XActiveDataStreamer
> xStreamer(
989 xStreamer
->setStream(result
);
991 pMod
->setReply(Moderator::REQUESTHANDLED
);
994 case Moderator::INPUTSTREAM
:
996 Reference
<XInputStream
> result
;
997 res
.result
>>= result
;
998 Reference
< XActiveDataSink
> xActiveSink(
1002 if(xActiveSink
.is())
1003 xActiveSink
->setInputStream(result
);
1004 pMod
->setReply(Moderator::REQUESTHANDLED
);
1007 case Moderator::TIMEDOUT
:
1009 Reference
<XInteractionRetry
> xRet
;
1010 if(xInteract
.is()) {
1011 InteractiveNetworkConnectException aExcep
;
1014 xContId
->getContentIdentifier() :
1016 aExcep
.Server
= aURL
.GetHost();
1017 aExcep
.Classification
= InteractionClassification_ERROR
;
1019 OUString( "server not responding after five seconds");
1022 ucbhelper::InteractionRequest
*ir
=
1023 new ucbhelper::InteractionRequest(request
);
1024 Reference
<XInteractionRequest
> xIR(ir
);
1025 Sequence
<Reference
<XInteractionContinuation
> > aSeq(2);
1026 ucbhelper::InteractionRetry
*retryP
=
1027 new ucbhelper::InteractionRetry(ir
);
1029 ucbhelper::InteractionAbort
*abortP
=
1030 new ucbhelper::InteractionAbort(ir
);
1033 ir
->setContinuations(aSeq
);
1034 xInteract
->handle(xIR
);
1035 rtl::Reference
< ucbhelper::InteractionContinuation
> ref
1036 = ir
->getSelection();
1038 Reference
<XInterface
> xInt(ref
.get());
1039 xRet
= Reference
<XInteractionRetry
>(xInt
,UNO_QUERY
);
1045 xLockBytes
->SetError(ERRCODE_ABORT
);
1050 case Moderator::INTERACTIONREQUEST
:
1052 Reference
<XInteractionRequest
> Request
;
1053 res
.result
>>= Request
;
1054 xInteract
->handle(Request
);
1055 pMod
->setReply(Moderator::REQUESTHANDLED
);
1058 case Moderator::RESULT
:
1060 bResultAchieved
= true;
1061 aResult
= res
.result
;
1064 case Moderator::COMMANDABORTED
:
1067 xLockBytes
->SetError( ERRCODE_ABORT
);
1070 case Moderator::COMMANDFAILED
:
1073 xLockBytes
->SetError( ERRCODE_ABORT
);
1076 case Moderator::INTERACTIVEIO
:
1079 if ( res
.ioErrorCode
== IOErrorCode_ACCESS_DENIED
||
1080 res
.ioErrorCode
== IOErrorCode_LOCKING_VIOLATION
)
1081 xLockBytes
->SetError( ERRCODE_IO_ACCESSDENIED
);
1082 else if ( res
.ioErrorCode
== IOErrorCode_NOT_EXISTING
)
1083 xLockBytes
->SetError( ERRCODE_IO_NOTEXISTS
);
1084 else if ( res
.ioErrorCode
== IOErrorCode_CANT_READ
)
1085 xLockBytes
->SetError( ERRCODE_IO_CANTREAD
);
1087 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1090 case Moderator::UNSUPPORTED
:
1093 xLockBytes
->SetError( ERRCODE_IO_NOTSUPPORTED
);
1099 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1104 bResultAchieved
|= bException
;
1105 bResultAchieved
|= bAborted
;
1106 if(nTimeout
== 5000) nTimeout
*= 2;
1109 if(pMod
) pMod
->setReply(Moderator::EXIT
);
1111 if ( bAborted
|| bException
)
1114 xHandler
->Handle( UcbLockBytesHandler::CANCEL
, xLockBytes
);
1116 Reference
< XActiveDataSink
> xActiveSink( xSink
, UNO_QUERY
);
1117 if ( xActiveSink
.is() )
1118 xActiveSink
->setInputStream( Reference
< XInputStream
>() );
1120 Reference
< XActiveDataStreamer
> xStreamer( xSink
, UNO_QUERY
);
1121 if ( xStreamer
.is() )
1122 xStreamer
->setStream( Reference
< XStream
>() );
1125 Reference
< XActiveDataControl
> xControl( xSink
, UNO_QUERY
);
1126 if ( xControl
.is() )
1127 xControl
->terminate();
1130 xProps
->removePropertiesChangeListener(
1131 Sequence
< OUString
>(),
1134 return ( bAborted
|| bException
);
1138 Function for opening UCB contents synchronously
1140 static sal_Bool
_UCBOpenContentSync(
1141 UcbLockBytesRef xLockBytes
,
1142 Reference
< XContent
> xContent
,
1143 const Command
& rArg
,
1144 Reference
< XInterface
> xSink
,
1145 Reference
< XInteractionHandler
> xInteract
,
1146 Reference
< XProgressHandler
> xProgress
,
1147 UcbLockBytesHandlerRef xHandler
)
1149 ::ucbhelper::Content
aContent(
1150 xContent
, new UcbTaskEnvironment( xInteract
, xProgress
),
1151 comphelper::getProcessComponentContext() );
1152 Reference
< XContentIdentifier
> xIdent
= xContent
->getIdentifier();
1153 OUString aScheme
= xIdent
->getContentProviderScheme();
1155 // http protocol must be handled in a special way: during the opening process the input stream may change
1156 // only the last inputstream after notifying the document headers is valid
1157 if ( aScheme
.compareToAscii("http") != COMPARE_EQUAL
)
1158 xLockBytes
->SetStreamValid_Impl();
1160 Reference
< XPropertiesChangeListener
> xListener
= new UcbPropertiesChangeListener_Impl( xLockBytes
);
1161 Reference
< XPropertiesChangeNotifier
> xProps ( xContent
, UNO_QUERY
);
1163 xProps
->addPropertiesChangeListener( Sequence
< OUString
>(), xListener
);
1166 bool bException
= false;
1167 bool bAborted
= false;
1171 aResult
= aContent
.executeCommand( rArg
.Name
, rArg
.Argument
);
1173 catch (const CommandAbortedException
&)
1176 xLockBytes
->SetError( ERRCODE_ABORT
);
1178 catch (const CommandFailedException
&)
1181 xLockBytes
->SetError( ERRCODE_ABORT
);
1183 catch (const InteractiveIOException
& r
)
1186 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
|| r
.Code
== IOErrorCode_LOCKING_VIOLATION
)
1187 xLockBytes
->SetError( ERRCODE_IO_ACCESSDENIED
);
1188 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
1189 xLockBytes
->SetError( ERRCODE_IO_NOTEXISTS
);
1190 else if ( r
.Code
== IOErrorCode_CANT_READ
)
1191 xLockBytes
->SetError( ERRCODE_IO_CANTREAD
);
1193 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1195 catch (const UnsupportedDataSinkException
&)
1198 xLockBytes
->SetError( ERRCODE_IO_NOTSUPPORTED
);
1200 catch (const Exception
&)
1203 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1206 if ( bAborted
|| bException
)
1209 xHandler
->Handle( UcbLockBytesHandler::CANCEL
, xLockBytes
);
1211 Reference
< XActiveDataSink
> xActiveSink( xSink
, UNO_QUERY
);
1212 if ( xActiveSink
.is() )
1213 xActiveSink
->setInputStream( Reference
< XInputStream
>() );
1215 Reference
< XActiveDataStreamer
> xStreamer( xSink
, UNO_QUERY
);
1216 if ( xStreamer
.is() )
1217 xStreamer
->setStream( Reference
< XStream
>() );
1220 Reference
< XActiveDataControl
> xControl( xSink
, UNO_QUERY
);
1221 if ( xControl
.is() )
1222 xControl
->terminate();
1226 xProps
->removePropertiesChangeListener( Sequence
< OUString
>(), xListener
);
1228 return ( bAborted
|| bException
);
1231 //----------------------------------------------------------------------------
1232 UcbLockBytes::UcbLockBytes( UcbLockBytesHandler
* pHandler
)
1233 : m_aExpireDate( DateTime::EMPTY
)
1234 , m_xInputStream (NULL
)
1235 , m_pCommandThread( NULL
)
1236 , m_xHandler( pHandler
)
1237 , m_nError( ERRCODE_NONE
)
1238 , m_bTerminated (sal_False
)
1239 , m_bDontClose( sal_False
)
1240 , m_bStreamValid (sal_False
)
1242 SetSynchronMode( sal_True
);
1245 //----------------------------------------------------------------------------
1246 UcbLockBytes::~UcbLockBytes()
1248 if ( !m_bDontClose
)
1250 if ( m_xInputStream
.is() )
1254 m_xInputStream
->closeInput();
1256 catch (const RuntimeException
&)
1259 catch (const IOException
&)
1265 if ( !m_xInputStream
.is() && m_xOutputStream
.is() )
1269 m_xOutputStream
->closeOutput();
1271 catch (const RuntimeException
&)
1274 catch (const IOException
&)
1280 Reference
< XInputStream
> UcbLockBytes::getInputStream()
1282 osl::MutexGuard
aGuard( m_aMutex
);
1283 m_bDontClose
= sal_True
;
1284 return m_xInputStream
;
1287 //----------------------------------------------------------------------------
1289 sal_Bool
UcbLockBytes::setStream_Impl( const Reference
<XStream
>& aStream
)
1291 osl::MutexGuard
aGuard( m_aMutex
);
1294 m_xOutputStream
= aStream
->getOutputStream();
1295 setInputStream_Impl( aStream
->getInputStream(), sal_False
);
1296 m_xSeekable
= Reference
< XSeekable
> ( aStream
, UNO_QUERY
);
1300 m_xOutputStream
= Reference
< XOutputStream
>();
1301 setInputStream_Impl( Reference
< XInputStream
>() );
1304 return m_xInputStream
.is();
1307 sal_Bool
UcbLockBytes::setInputStream_Impl( const Reference
<XInputStream
> &rxInputStream
, sal_Bool bSetXSeekable
)
1309 sal_Bool bRet
= sal_False
;
1313 osl::MutexGuard
aGuard( m_aMutex
);
1315 if ( !m_bDontClose
&& m_xInputStream
.is() )
1316 m_xInputStream
->closeInput();
1318 m_xInputStream
= rxInputStream
;
1322 m_xSeekable
= Reference
< XSeekable
> ( rxInputStream
, UNO_QUERY
);
1323 if( !m_xSeekable
.is() && rxInputStream
.is() )
1325 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
1326 Reference
< XOutputStream
> rxTempOut
= Reference
< XOutputStream
> ( TempFile::create(xContext
), UNO_QUERY_THROW
);
1328 ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream
, rxTempOut
);
1329 m_xInputStream
= Reference
< XInputStream
>( rxTempOut
, UNO_QUERY
);
1330 m_xSeekable
= Reference
< XSeekable
> ( rxTempOut
, UNO_QUERY
);
1334 bRet
= m_xInputStream
.is();
1336 catch (const Exception
&)
1340 if ( m_bStreamValid
&& m_xInputStream
.is() )
1341 m_aInitialized
.set();
1346 void UcbLockBytes::SetStreamValid_Impl()
1348 m_bStreamValid
= sal_True
;
1349 if ( m_xInputStream
.is() )
1350 m_aInitialized
.set();
1353 //----------------------------------------------------------------------------
1354 void UcbLockBytes::terminate_Impl()
1356 m_bTerminated
= sal_True
;
1357 m_aInitialized
.set();
1358 m_aTerminated
.set();
1360 if ( GetError() == ERRCODE_NONE
&& !m_xInputStream
.is() )
1362 OSL_FAIL("No InputStream, but no error set!" );
1363 SetError( ERRCODE_IO_NOTEXISTS
);
1366 if ( m_xHandler
.Is() )
1367 m_xHandler
->Handle( UcbLockBytesHandler::DONE
, this );
1370 //----------------------------------------------------------------------------
1371 void UcbLockBytes::SetSynchronMode (sal_Bool bSynchron
)
1373 SvLockBytes::SetSynchronMode (bSynchron
);
1376 //----------------------------------------------------------------------------
1377 ErrCode
UcbLockBytes::ReadAt ( sal_uLong nPos
, void *pBuffer
, sal_uLong nCount
, sal_uLong
*pRead
) const
1379 if ( IsSynchronMode() )
1381 UcbLockBytes
* pThis
= const_cast < UcbLockBytes
* >( this );
1382 pThis
->m_aInitialized
.wait();
1385 Reference
<XInputStream
> xStream
= getInputStream_Impl();
1386 if ( !xStream
.is() )
1388 if ( m_bTerminated
)
1389 return ERRCODE_IO_CANTREAD
;
1391 return ERRCODE_IO_PENDING
;
1397 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1398 if ( !xSeekable
.is() )
1399 return ERRCODE_IO_CANTREAD
;
1403 xSeekable
->seek( nPos
);
1405 catch (const IOException
&)
1407 return ERRCODE_IO_CANTSEEK
;
1409 catch (const com::sun::star::lang::IllegalArgumentException
&)
1411 return ERRCODE_IO_CANTSEEK
;
1414 Sequence
<sal_Int8
> aData
;
1417 if(nCount
> 0x7FFFFFFF)
1419 nCount
= 0x7FFFFFFF;
1423 if ( !m_bTerminated
&& !IsSynchronMode() )
1425 sal_uInt64 nLen
= xSeekable
->getLength();
1426 if ( nPos
+ nCount
> nLen
)
1427 return ERRCODE_IO_PENDING
;
1430 nSize
= xStream
->readBytes( aData
, sal_Int32(nCount
) );
1432 catch (const IOException
&)
1434 return ERRCODE_IO_CANTREAD
;
1437 memcpy (pBuffer
, aData
.getConstArray(), nSize
);
1439 *pRead
= sal_uLong(nSize
);
1441 return ERRCODE_NONE
;
1444 //----------------------------------------------------------------------------
1445 ErrCode
UcbLockBytes::WriteAt ( sal_uLong nPos
, const void *pBuffer
, sal_uLong nCount
, sal_uLong
*pWritten
)
1450 DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" );
1451 DBG_ASSERT( m_aInitialized
.check(), "Writing bevor stream is ready!" );
1453 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1454 Reference
<XOutputStream
> xOutputStream
= getOutputStream_Impl();
1455 if ( !xOutputStream
.is() || !xSeekable
.is() )
1456 return ERRCODE_IO_CANTWRITE
;
1460 xSeekable
->seek( nPos
);
1462 catch (const IOException
&)
1464 return ERRCODE_IO_CANTSEEK
;
1467 sal_Int8
* pData
= (sal_Int8
*) pBuffer
;
1468 Sequence
<sal_Int8
> aData( pData
, nCount
);
1471 xOutputStream
->writeBytes( aData
);
1475 catch (const Exception
&)
1477 return ERRCODE_IO_CANTWRITE
;
1480 return ERRCODE_NONE
;
1483 //----------------------------------------------------------------------------
1484 ErrCode
UcbLockBytes::Flush() const
1486 Reference
<XOutputStream
> xOutputStream
= getOutputStream_Impl();
1487 if ( !xOutputStream
.is() )
1488 return ERRCODE_IO_CANTWRITE
;
1492 xOutputStream
->flush();
1494 catch (const Exception
&)
1496 return ERRCODE_IO_CANTWRITE
;
1499 return ERRCODE_NONE
;
1502 //----------------------------------------------------------------------------
1503 ErrCode
UcbLockBytes::SetSize (sal_uLong nNewSize
)
1505 SvLockBytesStat aStat
;
1506 Stat( &aStat
, (SvLockBytesStatFlag
) 0 );
1507 sal_uLong nSize
= aStat
.nSize
;
1509 if ( nSize
> nNewSize
)
1511 Reference
< XTruncate
> xTrunc( getOutputStream_Impl(), UNO_QUERY
);
1518 DBG_WARNING("Not truncatable!");
1522 if ( nSize
< nNewSize
)
1524 sal_uLong nDiff
= nNewSize
-nSize
, nCount
=0;
1525 sal_uInt8
* pBuffer
= new sal_uInt8
[ nDiff
];
1526 memset(pBuffer
, 0, nDiff
); // initialize for enhanced security
1527 WriteAt( nSize
, pBuffer
, nDiff
, &nCount
);
1529 if ( nCount
!= nDiff
)
1530 return ERRCODE_IO_CANTWRITE
;
1533 return ERRCODE_NONE
;
1536 //----------------------------------------------------------------------------
1537 ErrCode
UcbLockBytes::Stat( SvLockBytesStat
*pStat
, SvLockBytesStatFlag
) const
1539 if ( IsSynchronMode() )
1541 UcbLockBytes
* pThis
= const_cast < UcbLockBytes
* >( this );
1542 pThis
->m_aInitialized
.wait();
1546 return ERRCODE_IO_INVALIDPARAMETER
;
1548 Reference
<XInputStream
> xStream
= getInputStream_Impl();
1549 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1551 if ( !xStream
.is() )
1553 if ( m_bTerminated
)
1554 return ERRCODE_IO_INVALIDACCESS
;
1556 return ERRCODE_IO_PENDING
;
1558 else if( !xSeekable
.is() )
1559 return ERRCODE_IO_CANTTELL
;
1563 pStat
->nSize
= sal_uLong(xSeekable
->getLength());
1565 catch (const IOException
&)
1567 return ERRCODE_IO_CANTTELL
;
1570 return ERRCODE_NONE
;
1573 //----------------------------------------------------------------------------
1574 IMPL_LINK_NOARG(UcbLockBytes
, DataAvailHdl
)
1576 if ( hasInputStream_Impl() && m_xHandler
.Is() )
1577 m_xHandler
->Handle( UcbLockBytesHandler::DATA_AVAILABLE
, this );
1582 UcbLockBytesRef
UcbLockBytes::CreateInputLockBytes( const Reference
< XInputStream
>& xInputStream
)
1584 if( !xInputStream
.is() )
1587 UcbLockBytesRef xLockBytes
= new UcbLockBytes();
1588 xLockBytes
->setDontClose_Impl();
1589 xLockBytes
->setInputStream_Impl( xInputStream
);
1590 xLockBytes
->terminate_Impl();
1594 UcbLockBytesRef
UcbLockBytes::CreateLockBytes( const Reference
< XStream
>& xStream
)
1599 UcbLockBytesRef xLockBytes
= new UcbLockBytes();
1600 xLockBytes
->setDontClose_Impl();
1601 xLockBytes
->setStream_Impl( xStream
);
1602 xLockBytes
->terminate_Impl();
1606 UcbLockBytesRef
UcbLockBytes::CreateLockBytes( const Reference
< XContent
>& xContent
, const Sequence
< PropertyValue
>& rProps
,
1607 StreamMode eOpenMode
, const Reference
< XInteractionHandler
>& xInteractionHandler
, UcbLockBytesHandler
* pHandler
)
1609 if( !xContent
.is() )
1612 UcbLockBytesRef xLockBytes
= new UcbLockBytes( pHandler
);
1613 xLockBytes
->SetSynchronMode( !pHandler
);
1614 Reference
< XActiveDataControl
> xSink
;
1615 if ( eOpenMode
& STREAM_WRITE
)
1616 xSink
= (XActiveDataControl
*) new UcbStreamer_Impl( xLockBytes
);
1618 xSink
= (XActiveDataControl
*) new UcbDataSink_Impl( xLockBytes
);
1620 if ( rProps
.getLength() )
1622 Reference
< XCommandProcessor
> xProcessor( xContent
, UNO_QUERY
);
1624 aCommand
.Name
= OUString("setPropertyValues");
1625 aCommand
.Handle
= -1; /* unknown */
1626 aCommand
.Argument
<<= rProps
;
1627 xProcessor
->execute( aCommand
, 0, Reference
< XCommandEnvironment
>() );
1630 OpenCommandArgument2 aArgument
;
1631 aArgument
.Sink
= xSink
;
1632 aArgument
.Mode
= OpenMode::DOCUMENT
;
1635 aCommand
.Name
= OUString( "open" );
1636 aCommand
.Argument
<<= aArgument
;
1638 Reference
< XProgressHandler
> xProgressHdl
= new ProgressHandler_Impl( LINK( &xLockBytes
, UcbLockBytes
, DataAvailHdl
) );
1640 sal_Bool bError
= UCBOpenContentSync( xLockBytes
,
1644 xInteractionHandler
,
1648 if ( xLockBytes
->GetError() == ERRCODE_NONE
&& ( bError
|| !xLockBytes
->getInputStream().is() ) )
1650 OSL_FAIL("No InputStream, but no error set!" );
1651 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1659 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */