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::uno
;
62 using namespace ::com::sun::star::ucb
;
63 using namespace ::com::sun::star::task
;
64 using namespace ::com::sun::star::lang
;
65 using namespace ::com::sun::star::beans
;
72 Helper class for getting a XInputStream when opening a content
74 class UcbDataSink_Impl
: public ::cppu::WeakImplHelper2
< XActiveDataControl
, XActiveDataSink
>
76 UcbLockBytesRef m_xLockBytes
;
79 UcbDataSink_Impl( UcbLockBytes
* pLockBytes
)
80 : m_xLockBytes( pLockBytes
)
83 SvLockBytes
* getLockBytes (void)
84 { return m_xLockBytes
; }
86 // XActiveDataControl.
87 virtual void SAL_CALL
addListener ( const Reference
<XStreamListener
> &/*rxListener*/) throw(RuntimeException
) {}
88 virtual void SAL_CALL
removeListener ( const Reference
<XStreamListener
> &/*rxListener*/) throw(RuntimeException
) {}
89 virtual void SAL_CALL
start (void) throw(RuntimeException
) {}
90 virtual void SAL_CALL
terminate (void) throw(RuntimeException
)
91 { m_xLockBytes
->terminate_Impl(); }
94 virtual void SAL_CALL
setInputStream ( const Reference
<XInputStream
> &rxInputStream
) throw(RuntimeException
)
95 { m_xLockBytes
->setInputStream_Impl (rxInputStream
); }
96 virtual Reference
<XInputStream
> SAL_CALL
getInputStream (void) throw(RuntimeException
)
97 { return m_xLockBytes
->getInputStream_Impl(); }
101 Helper class for getting a XStream when opening a content
103 class UcbStreamer_Impl
: public ::cppu::WeakImplHelper2
< XActiveDataStreamer
, XActiveDataControl
>
105 Reference
< XStream
> m_xStream
;
106 UcbLockBytesRef m_xLockBytes
;
109 UcbStreamer_Impl( UcbLockBytes
* pLockBytes
)
110 : m_xLockBytes( pLockBytes
)
113 // XActiveDataControl.
114 virtual void SAL_CALL
addListener ( const Reference
<XStreamListener
> &/*rxListener*/) throw(RuntimeException
) {}
115 virtual void SAL_CALL
removeListener ( const Reference
<XStreamListener
> &/*rxListener*/) throw(RuntimeException
) {}
116 virtual void SAL_CALL
start (void) throw(RuntimeException
) {}
117 virtual void SAL_CALL
terminate (void) throw(RuntimeException
)
118 { m_xLockBytes
->terminate_Impl(); }
120 // XActiveDataStreamer
121 virtual void SAL_CALL
setStream( const Reference
< XStream
>& aStream
) throw(RuntimeException
)
122 { m_xStream
= aStream
; m_xLockBytes
->setStream_Impl( aStream
); }
123 virtual Reference
< XStream
> SAL_CALL
getStream() throw(RuntimeException
)
124 { return m_xStream
; }
128 Helper class for progress handling while executing UCB commands
130 class ProgressHandler_Impl
: public ::cppu::WeakImplHelper1
< XProgressHandler
>
135 ProgressHandler_Impl( const Link
& rLink
)
136 : m_aProgress( rLink
)
139 virtual void SAL_CALL
push(const Any
& /*rStatus*/) throw (RuntimeException
) {}
140 virtual void SAL_CALL
pop() throw (RuntimeException
) {}
141 virtual void SAL_CALL
update(const Any
& /*rStatus*/) throw (RuntimeException
)
142 { if ( m_aProgress
.IsSet() ) m_aProgress
.Call( 0 ); }
146 Helper class for managing interactions and progress when executing UCB commands
148 class UcbTaskEnvironment
: public ::cppu::WeakImplHelper1
< XCommandEnvironment
>
150 Reference
< XInteractionHandler
> m_xInteractionHandler
;
151 Reference
< XProgressHandler
> m_xProgressHandler
;
154 UcbTaskEnvironment( const Reference
< XInteractionHandler
>& rxInteractionHandler
,
155 const Reference
< XProgressHandler
>& rxProgressHandler
)
156 : m_xInteractionHandler( rxInteractionHandler
)
157 , m_xProgressHandler( rxProgressHandler
)
160 virtual Reference
<XInteractionHandler
> SAL_CALL
getInteractionHandler() throw (RuntimeException
)
161 { return m_xInteractionHandler
; }
163 virtual Reference
<XProgressHandler
> SAL_CALL
getProgressHandler() throw (RuntimeException
)
164 { return m_xProgressHandler
; }
169 Helper class for property change notifies when executing UCB commands
171 class UcbPropertiesChangeListener_Impl
: public ::cppu::WeakImplHelper1
< XPropertiesChangeListener
>
174 UcbLockBytesRef m_xLockBytes
;
176 UcbPropertiesChangeListener_Impl( UcbLockBytesRef rRef
)
177 : m_xLockBytes( rRef
)
180 virtual void SAL_CALL
disposing ( const EventObject
&/*rEvent*/) throw(RuntimeException
) {}
181 virtual void SAL_CALL
propertiesChange ( const Sequence
<PropertyChangeEvent
> &rEvent
) throw(RuntimeException
);
184 void SAL_CALL
UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence
<PropertyChangeEvent
> &rEvent
) throw(RuntimeException
)
186 sal_Int32 i
, n
= rEvent
.getLength();
187 for (i
= 0; i
< n
; i
++)
189 PropertyChangeEvent
evt (rEvent
[i
]);
190 if (evt
.PropertyName
== ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("DocumentHeader")))
192 Sequence
<DocumentHeaderField
> aHead
;
193 if (evt
.NewValue
>>= aHead
)
195 sal_Int32 k
, m
= aHead
.getLength();
196 for (k
= 0; k
< m
; k
++)
198 String
aName( aHead
[k
].Name
);
199 String
aValue( aHead
[k
].Value
);
201 if (aName
.CompareIgnoreCaseToAscii("Expires") == COMPARE_EQUAL
)
203 DateTime
aExpires (0, 0);
204 if (INetRFC822Message::ParseDateField (aValue
, aExpires
))
206 aExpires
.ConvertToLocalTime();
207 m_xLockBytes
->SetExpireDate_Impl( aExpires
);
213 m_xLockBytes
->SetStreamValid_Impl();
215 else if (evt
.PropertyName
== rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("PresentationURL")))
217 ::rtl::OUString aUrl
;
218 if (evt
.NewValue
>>= aUrl
)
220 ::rtl::OUString
aBad (RTL_CONSTASCII_USTRINGPARAM ("private:"));
221 if (!(aUrl
.compareTo (aBad
, aBad
.getLength()) == 0))
223 // URL changed (Redirection).
224 m_xLockBytes
->SetRealURL_Impl( aUrl
);
228 else if (evt
.PropertyName
== ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("MediaType")))
230 ::rtl::OUString aContentType
;
231 if (evt
.NewValue
>>= aContentType
)
232 m_xLockBytes
->SetContentType_Impl( aContentType
);
242 // usage restriction:
243 // It might be possible, that the call to the interactionhandler and/or
244 // progresshandler is done asynchrounsly, while the 'execute' simply
245 // returns. This would imply that these class must be refcounted !!!
249 Reference
< XContent
>& xContent
,
250 Reference
< XInteractionHandler
>& xInteract
,
251 Reference
< XProgressHandler
>& xProgress
,
255 ContentCreationException
,
265 INTERACTIONREQUEST
, // reply expected
285 : public salhelper::Condition
288 ConditionRes(osl::Mutex
& aMutex
,Moderator
& aModerator
)
289 : salhelper::Condition(aMutex
),
290 m_aModerator(aModerator
)
295 bool applies() const {
296 return m_aModerator
.m_aResultType
!= NORESULT
;
300 Moderator
& m_aModerator
;
307 sal_Int32 ioErrorCode
;
310 Result
getResult(const sal_uInt32 milliSec
);
320 : public salhelper::Condition
323 ConditionRep(osl::Mutex
& aMutex
,Moderator
& aModerator
)
324 : salhelper::Condition(aMutex
),
325 m_aModerator(aModerator
)
330 bool applies() const {
331 return m_aModerator
.m_aReplyType
!= NOREPLY
;
335 Moderator
& m_aModerator
;
338 void setReply(ReplyType
);
340 void handle( const Reference
<XInteractionRequest
>& Request
);
341 void push( const Any
& Status
);
342 void update( const Any
& Status
);
345 void setStream(const Reference
< XStream
>& aStream
);
346 void setInputStream(const Reference
<XInputStream
> &rxInputStream
);
350 virtual void SAL_CALL
run();
351 virtual void SAL_CALL
onTerminated();
356 friend class ConditionRes
;
359 ResultType m_aResultType
;
360 sal_Int32 m_nIOErrorCode
;
363 friend class ConditionRep
;
366 ReplyType m_aReplyType
;
369 ::ucbhelper::Content m_aContent
;
373 class ModeratorsActiveDataStreamer
374 : public ::cppu::WeakImplHelper1
<XActiveDataStreamer
>
378 ModeratorsActiveDataStreamer(Moderator
&theModerator
);
380 ~ModeratorsActiveDataStreamer();
382 // XActiveDataStreamer
383 virtual void SAL_CALL
385 const Reference
< XStream
>& aStream
391 virtual Reference
<XStream
> SAL_CALL
398 osl::MutexGuard
aGuard(m_aMutex
);
404 Moderator
& m_aModerator
;
407 Reference
<XStream
> m_xStream
;
411 class ModeratorsActiveDataSink
412 : public ::cppu::WeakImplHelper1
<XActiveDataSink
>
416 ModeratorsActiveDataSink(Moderator
&theModerator
);
418 ~ModeratorsActiveDataSink();
421 virtual void SAL_CALL
423 const Reference
<XInputStream
> &rxInputStream
429 virtual Reference
<XInputStream
> SAL_CALL
436 osl::MutexGuard
aGuard(m_aMutex
);
442 Moderator
& m_aModerator
;
444 Reference
<XInputStream
> m_xStream
;
449 ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator
&theModerator
)
450 : m_aModerator(theModerator
)
455 ModeratorsActiveDataSink::~ModeratorsActiveDataSink()
461 ModeratorsActiveDataSink::setInputStream (
462 const Reference
<XInputStream
> &rxInputStream
468 m_aModerator
.setInputStream(rxInputStream
);
469 osl::MutexGuard
aGuard(m_aMutex
);
470 m_xStream
= rxInputStream
;
474 ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer(
475 Moderator
&theModerator
477 : m_aModerator(theModerator
)
482 ModeratorsActiveDataStreamer::~ModeratorsActiveDataStreamer()
486 // XActiveDataStreamer.
488 ModeratorsActiveDataStreamer::setStream (
489 const Reference
<XStream
> &rxStream
495 m_aModerator
.setStream(rxStream
);
496 osl::MutexGuard
aGuard(m_aMutex
);
497 m_xStream
= rxStream
;
502 class ModeratorsInteractionHandler
503 : public ::cppu::WeakImplHelper1
<XInteractionHandler
>
507 ModeratorsInteractionHandler(Moderator
&theModerator
);
509 ~ModeratorsInteractionHandler();
511 virtual void SAL_CALL
512 handle( const Reference
<XInteractionRequest
>& Request
)
513 throw (RuntimeException
);
517 Moderator
& m_aModerator
;
521 class ModeratorsProgressHandler
522 : public ::cppu::WeakImplHelper1
<XProgressHandler
>
525 ModeratorsProgressHandler(Moderator
&theModerator
);
527 ~ModeratorsProgressHandler();
529 virtual void SAL_CALL
push( const Any
& Status
)
533 virtual void SAL_CALL
update( const Any
& Status
)
534 throw (RuntimeException
);
536 virtual void SAL_CALL
pop( )
537 throw (RuntimeException
);
541 Moderator
& m_aModerator
;
545 ModeratorsProgressHandler::ModeratorsProgressHandler(Moderator
&theModerator
)
546 : m_aModerator(theModerator
)
550 ModeratorsProgressHandler::~ModeratorsProgressHandler()
555 void SAL_CALL
ModeratorsProgressHandler::push( const Any
& Status
)
559 m_aModerator
.push(Status
);
563 void SAL_CALL
ModeratorsProgressHandler::update( const Any
& Status
)
564 throw (RuntimeException
)
566 m_aModerator
.update(Status
);
570 void SAL_CALL
ModeratorsProgressHandler::pop( )
571 throw (RuntimeException
)
577 ModeratorsInteractionHandler::ModeratorsInteractionHandler(
578 Moderator
&aModerator
)
579 : m_aModerator(aModerator
)
584 ModeratorsInteractionHandler::~ModeratorsInteractionHandler()
590 ModeratorsInteractionHandler::handle(
591 const Reference
<XInteractionRequest
>& Request
597 // wakes up the mainthread
598 m_aModerator
.handle(Request
);
604 Moderator::Moderator(
605 Reference
< XContent
>& xContent
,
606 Reference
< XInteractionHandler
>& xInteract
,
607 Reference
< XProgressHandler
>& xProgress
,
611 ::com::sun::star::ucb::ContentCreationException
,
612 ::com::sun::star::uno::RuntimeException
616 m_aRes(m_aMutex
,*this),
617 m_aResultType(NORESULT
),
621 m_aRep(m_aMutex
,*this),
622 m_aReplyType(NOREPLY
),
627 new UcbTaskEnvironment(
628 xInteract
.is() ? new ModeratorsInteractionHandler(*this) : 0,
629 xProgress
.is() ? new ModeratorsProgressHandler(*this) : 0),
630 comphelper::getProcessComponentContext())
632 // now exchange the whole data sink stuff
633 // with a thread safe version
635 Reference
<XInterface
> *pxSink
= NULL
;
637 PostCommandArgument2 aPostArg
;
638 OpenCommandArgument2 aOpenArg
;
641 if(m_aArg
.Argument
>>= aPostArg
) {
642 pxSink
= &aPostArg
.Sink
;
645 else if(m_aArg
.Argument
>>= aOpenArg
) {
646 pxSink
= &aOpenArg
.Sink
;
651 throw ContentCreationException();
653 Reference
< XActiveDataSink
> xActiveSink(*pxSink
,UNO_QUERY
);
655 *pxSink
= Reference
<XInterface
>(
656 (cppu::OWeakObject
*)new ModeratorsActiveDataSink(*this));
658 Reference
<XActiveDataStreamer
> xStreamer( *pxSink
, UNO_QUERY
);
659 if ( xStreamer
.is() )
660 *pxSink
= Reference
<XInterface
>(
661 (cppu::OWeakObject
*)new ModeratorsActiveDataStreamer(*this));
664 m_aArg
.Argument
<<= aPostArg
;
666 m_aArg
.Argument
<<= aOpenArg
;
670 Moderator::~Moderator()
675 Moderator::Result
Moderator::getResult(const sal_uInt32 milliSec
)
679 salhelper::ConditionWaiter
aWaiter(m_aRes
,milliSec
);
680 ret
.type
= m_aResultType
;
681 ret
.result
= m_aResult
;
682 ret
.ioErrorCode
= m_nIOErrorCode
;
685 m_aResultType
= NORESULT
;
687 catch (const salhelper::ConditionWaiter::timedout
&)
696 void Moderator::setReply(ReplyType aReplyType
)
698 salhelper::ConditionModifier
aMod(m_aRep
);
699 m_aReplyType
= aReplyType
;
703 void Moderator::handle( const Reference
<XInteractionRequest
>& Request
)
705 ReplyType aReplyType
;
709 salhelper::ConditionModifier
aMod(m_aRes
);
710 m_aResultType
= INTERACTIONREQUEST
;
711 m_aResult
<<= Request
;
715 salhelper::ConditionWaiter
aWait(m_aRep
);
716 aReplyType
= m_aReplyType
;
719 m_aReplyType
= NOREPLY
;
722 if(aReplyType
== EXIT
) {
723 Sequence
<Reference
<XInteractionContinuation
> > aSeq(
724 Request
->getContinuations());
725 for(sal_Int32 i
= 0; i
< aSeq
.getLength(); ++i
) {
726 Reference
<XInteractionAbort
> aRef(aSeq
[i
],UNO_QUERY
);
732 // resignal the exitcondition
736 } while(aReplyType
!= REQUESTHANDLED
);
740 void Moderator::push( const Any
& Status
)
743 salhelper::ConditionModifier
aMod(m_aRes
);
744 m_aResultType
= PROGRESSPUSH
;
747 ReplyType aReplyType
;
749 salhelper::ConditionWaiter
aWait(m_aRep
);
750 aReplyType
= m_aReplyType
;
751 m_aReplyType
= NOREPLY
;
753 if(aReplyType
== EXIT
)
758 void Moderator::update( const Any
& Status
)
761 salhelper::ConditionModifier
aMod(m_aRes
);
762 m_aResultType
= PROGRESSUPDATE
;
765 ReplyType aReplyType
;
767 salhelper::ConditionWaiter
aWait(m_aRep
);
768 aReplyType
= m_aReplyType
;
769 m_aReplyType
= NOREPLY
;
771 if(aReplyType
== EXIT
)
776 void Moderator::pop( )
779 salhelper::ConditionModifier
aMod(m_aRes
);
780 m_aResultType
= PROGRESSPOP
;
782 ReplyType aReplyType
;
784 salhelper::ConditionWaiter
aWait(m_aRep
);
785 aReplyType
= m_aReplyType
;
786 m_aReplyType
= NOREPLY
;
788 if(aReplyType
== EXIT
)
793 void Moderator::setStream(const Reference
< XStream
>& aStream
)
796 salhelper::ConditionModifier
aMod(m_aRes
);
797 m_aResultType
= STREAM
;
798 m_aResult
<<= aStream
;
800 ReplyType aReplyType
;
802 salhelper::ConditionWaiter
aWait(m_aRep
);
803 aReplyType
= m_aReplyType
;
804 m_aReplyType
= NOREPLY
;
806 if(aReplyType
== EXIT
)
811 void Moderator::setInputStream(const Reference
<XInputStream
> &rxInputStream
)
814 salhelper::ConditionModifier
aMod(m_aRes
);
815 m_aResultType
= INPUTSTREAM
;
816 m_aResult
<<= rxInputStream
;
818 ReplyType aReplyType
;
820 salhelper::ConditionWaiter
aWait(m_aRep
);
821 aReplyType
= m_aReplyType
;
822 m_aReplyType
= NOREPLY
;
824 if(aReplyType
== EXIT
)
829 void SAL_CALL
Moderator::run()
831 ResultType aResultType
;
833 sal_Int32 nIOErrorCode
= 0;
837 aResult
= m_aContent
.executeCommand(m_aArg
.Name
,m_aArg
.Argument
);
838 aResultType
= RESULT
;
840 catch (const CommandAbortedException
&)
842 aResultType
= COMMANDABORTED
;
844 catch (const CommandFailedException
&)
846 aResultType
= COMMANDFAILED
;
848 catch (const InteractiveIOException
& r
)
850 nIOErrorCode
= r
.Code
;
851 aResultType
= INTERACTIVEIO
;
853 catch (const UnsupportedDataSinkException
&)
855 aResultType
= UNSUPPORTED
;
857 catch (const Exception
&)
859 aResultType
= GENERAL
;
863 salhelper::ConditionModifier
aMod(m_aRes
);
864 m_aResultType
= aResultType
;
866 m_nIOErrorCode
= nIOErrorCode
;
870 void SAL_CALL
Moderator::onTerminated()
873 salhelper::ConditionWaiter
aWaiter(m_aRep
);
879 Function for opening UCB contents synchronously,
880 but with handled timeout;
882 static sal_Bool
_UCBOpenContentSync(
883 UcbLockBytesRef xLockBytes
,
884 Reference
< XContent
> xContent
,
886 Reference
< XInterface
> xSink
,
887 Reference
< XInteractionHandler
> xInteract
,
888 Reference
< XProgressHandler
> xProgress
,
889 UcbLockBytesHandlerRef xHandler
);
892 static sal_Bool
UCBOpenContentSync(
893 UcbLockBytesRef xLockBytes
,
894 Reference
< XContent
> xContent
,
896 Reference
< XInterface
> xSink
,
897 Reference
< XInteractionHandler
> xInteract
,
898 Reference
< XProgressHandler
> xProgress
,
899 UcbLockBytesHandlerRef xHandler
)
901 // http protocol must be handled in a special way:
902 // during the opening process the input stream may change
903 // only the last inputstream after notifying the document
906 Reference
<XContentIdentifier
> xContId(
907 xContent
.is() ? xContent
->getIdentifier() : 0 );
909 rtl::OUString aScheme
;
911 aScheme
= xContId
->getContentProviderScheme();
913 // now determine whether we use a timeout or not;
914 if( ! aScheme
.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("http")) &&
915 ! aScheme
.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("https")) &&
916 ! aScheme
.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.webdav")) &&
917 ! aScheme
.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("ftp")))
918 return _UCBOpenContentSync(
919 xLockBytes
,xContent
,rArg
,xSink
,xInteract
,xProgress
,xHandler
);
921 if ( (aScheme
.compareToAscii( "http" ) != COMPARE_EQUAL
) ||
922 (aScheme
.compareToAscii( "https" ) != COMPARE_EQUAL
) )
923 xLockBytes
->SetStreamValid_Impl();
925 Reference
< XPropertiesChangeListener
> xListener
;
926 Reference
< XPropertiesChangeNotifier
> xProps(xContent
,UNO_QUERY
);
929 new UcbPropertiesChangeListener_Impl(xLockBytes
);
930 xProps
->addPropertiesChangeListener(
931 Sequence
< ::rtl::OUString
>(),
936 bool bException(false);
937 bool bAborted(false);
938 bool bResultAchieved(false);
943 pMod
= new Moderator(xContent
,xInteract
,xProgress
,rArg
);
946 catch (const ContentCreationException
&)
948 bResultAchieved
= bException
= true;
949 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
952 sal_uInt32
nTimeout(5000); // initially 5000 milliSec
953 while(!bResultAchieved
) {
955 Moderator::Result res
;
956 // try to get the result for with timeout
957 res
= pMod
->getResult(nTimeout
);
960 case Moderator::PROGRESSPUSH
:
963 xProgress
->push(res
.result
);
964 pMod
->setReply(Moderator::REQUESTHANDLED
);
967 case Moderator::PROGRESSUPDATE
:
970 xProgress
->update(res
.result
);
971 pMod
->setReply(Moderator::REQUESTHANDLED
);
974 case Moderator::PROGRESSPOP
:
978 pMod
->setReply(Moderator::REQUESTHANDLED
);
981 case Moderator::STREAM
:
983 Reference
<XStream
> result
;
984 if(res
.result
>>= result
) {
985 Reference
< XActiveDataStreamer
> xStreamer(
990 xStreamer
->setStream(result
);
992 pMod
->setReply(Moderator::REQUESTHANDLED
);
995 case Moderator::INPUTSTREAM
:
997 Reference
<XInputStream
> result
;
998 res
.result
>>= result
;
999 Reference
< XActiveDataSink
> xActiveSink(
1003 if(xActiveSink
.is())
1004 xActiveSink
->setInputStream(result
);
1005 pMod
->setReply(Moderator::REQUESTHANDLED
);
1008 case Moderator::TIMEDOUT
:
1010 Reference
<XInteractionRetry
> xRet
;
1011 if(xInteract
.is()) {
1012 InteractiveNetworkConnectException aExcep
;
1015 xContId
->getContentIdentifier() :
1017 aExcep
.Server
= aURL
.GetHost();
1018 aExcep
.Classification
= InteractionClassification_ERROR
;
1020 rtl::OUString( "server not responding after five seconds");
1023 ucbhelper::InteractionRequest
*ir
=
1024 new ucbhelper::InteractionRequest(request
);
1025 Reference
<XInteractionRequest
> xIR(ir
);
1026 Sequence
<Reference
<XInteractionContinuation
> > aSeq(2);
1027 ucbhelper::InteractionRetry
*retryP
=
1028 new ucbhelper::InteractionRetry(ir
);
1030 ucbhelper::InteractionAbort
*abortP
=
1031 new ucbhelper::InteractionAbort(ir
);
1034 ir
->setContinuations(aSeq
);
1035 xInteract
->handle(xIR
);
1036 rtl::Reference
< ucbhelper::InteractionContinuation
> ref
1037 = ir
->getSelection();
1039 Reference
<XInterface
> xInt(ref
.get());
1040 xRet
= Reference
<XInteractionRetry
>(xInt
,UNO_QUERY
);
1046 xLockBytes
->SetError(ERRCODE_ABORT
);
1051 case Moderator::INTERACTIONREQUEST
:
1053 Reference
<XInteractionRequest
> Request
;
1054 res
.result
>>= Request
;
1055 xInteract
->handle(Request
);
1056 pMod
->setReply(Moderator::REQUESTHANDLED
);
1059 case Moderator::RESULT
:
1061 bResultAchieved
= true;
1062 aResult
= res
.result
;
1065 case Moderator::COMMANDABORTED
:
1068 xLockBytes
->SetError( ERRCODE_ABORT
);
1071 case Moderator::COMMANDFAILED
:
1074 xLockBytes
->SetError( ERRCODE_ABORT
);
1077 case Moderator::INTERACTIVEIO
:
1080 if ( res
.ioErrorCode
== IOErrorCode_ACCESS_DENIED
||
1081 res
.ioErrorCode
== IOErrorCode_LOCKING_VIOLATION
)
1082 xLockBytes
->SetError( ERRCODE_IO_ACCESSDENIED
);
1083 else if ( res
.ioErrorCode
== IOErrorCode_NOT_EXISTING
)
1084 xLockBytes
->SetError( ERRCODE_IO_NOTEXISTS
);
1085 else if ( res
.ioErrorCode
== IOErrorCode_CANT_READ
)
1086 xLockBytes
->SetError( ERRCODE_IO_CANTREAD
);
1088 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1091 case Moderator::UNSUPPORTED
:
1094 xLockBytes
->SetError( ERRCODE_IO_NOTSUPPORTED
);
1100 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1105 bResultAchieved
|= bException
;
1106 bResultAchieved
|= bAborted
;
1107 if(nTimeout
== 5000) nTimeout
*= 2;
1110 if(pMod
) pMod
->setReply(Moderator::EXIT
);
1112 if ( bAborted
|| bException
)
1115 xHandler
->Handle( UcbLockBytesHandler::CANCEL
, xLockBytes
);
1117 Reference
< XActiveDataSink
> xActiveSink( xSink
, UNO_QUERY
);
1118 if ( xActiveSink
.is() )
1119 xActiveSink
->setInputStream( Reference
< XInputStream
>() );
1121 Reference
< XActiveDataStreamer
> xStreamer( xSink
, UNO_QUERY
);
1122 if ( xStreamer
.is() )
1123 xStreamer
->setStream( Reference
< XStream
>() );
1126 Reference
< XActiveDataControl
> xControl( xSink
, UNO_QUERY
);
1127 if ( xControl
.is() )
1128 xControl
->terminate();
1131 xProps
->removePropertiesChangeListener(
1132 Sequence
< ::rtl::OUString
>(),
1135 return ( bAborted
|| bException
);
1139 Function for opening UCB contents synchronously
1141 static sal_Bool
_UCBOpenContentSync(
1142 UcbLockBytesRef xLockBytes
,
1143 Reference
< XContent
> xContent
,
1144 const Command
& rArg
,
1145 Reference
< XInterface
> xSink
,
1146 Reference
< XInteractionHandler
> xInteract
,
1147 Reference
< XProgressHandler
> xProgress
,
1148 UcbLockBytesHandlerRef xHandler
)
1150 ::ucbhelper::Content
aContent(
1151 xContent
, new UcbTaskEnvironment( xInteract
, xProgress
),
1152 comphelper::getProcessComponentContext() );
1153 Reference
< XContentIdentifier
> xIdent
= xContent
->getIdentifier();
1154 ::rtl::OUString aScheme
= xIdent
->getContentProviderScheme();
1156 // http protocol must be handled in a special way: during the opening process the input stream may change
1157 // only the last inputstream after notifying the document headers is valid
1158 if ( aScheme
.compareToAscii("http") != COMPARE_EQUAL
)
1159 xLockBytes
->SetStreamValid_Impl();
1161 Reference
< XPropertiesChangeListener
> xListener
= new UcbPropertiesChangeListener_Impl( xLockBytes
);
1162 Reference
< XPropertiesChangeNotifier
> xProps ( xContent
, UNO_QUERY
);
1164 xProps
->addPropertiesChangeListener( Sequence
< ::rtl::OUString
>(), xListener
);
1167 bool bException
= false;
1168 bool bAborted
= false;
1172 aResult
= aContent
.executeCommand( rArg
.Name
, rArg
.Argument
);
1174 catch (const CommandAbortedException
&)
1177 xLockBytes
->SetError( ERRCODE_ABORT
);
1179 catch (const CommandFailedException
&)
1182 xLockBytes
->SetError( ERRCODE_ABORT
);
1184 catch (const InteractiveIOException
& r
)
1187 if ( r
.Code
== IOErrorCode_ACCESS_DENIED
|| r
.Code
== IOErrorCode_LOCKING_VIOLATION
)
1188 xLockBytes
->SetError( ERRCODE_IO_ACCESSDENIED
);
1189 else if ( r
.Code
== IOErrorCode_NOT_EXISTING
)
1190 xLockBytes
->SetError( ERRCODE_IO_NOTEXISTS
);
1191 else if ( r
.Code
== IOErrorCode_CANT_READ
)
1192 xLockBytes
->SetError( ERRCODE_IO_CANTREAD
);
1194 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1196 catch (const UnsupportedDataSinkException
&)
1199 xLockBytes
->SetError( ERRCODE_IO_NOTSUPPORTED
);
1201 catch (const Exception
&)
1204 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1207 if ( bAborted
|| bException
)
1210 xHandler
->Handle( UcbLockBytesHandler::CANCEL
, xLockBytes
);
1212 Reference
< XActiveDataSink
> xActiveSink( xSink
, UNO_QUERY
);
1213 if ( xActiveSink
.is() )
1214 xActiveSink
->setInputStream( Reference
< XInputStream
>() );
1216 Reference
< XActiveDataStreamer
> xStreamer( xSink
, UNO_QUERY
);
1217 if ( xStreamer
.is() )
1218 xStreamer
->setStream( Reference
< XStream
>() );
1221 Reference
< XActiveDataControl
> xControl( xSink
, UNO_QUERY
);
1222 if ( xControl
.is() )
1223 xControl
->terminate();
1227 xProps
->removePropertiesChangeListener( Sequence
< ::rtl::OUString
>(), xListener
);
1229 return ( bAborted
|| bException
);
1232 //----------------------------------------------------------------------------
1233 UcbLockBytes::UcbLockBytes( UcbLockBytesHandler
* pHandler
)
1234 : m_aExpireDate( DateTime::EMPTY
)
1235 , m_xInputStream (NULL
)
1236 , m_pCommandThread( NULL
)
1237 , m_xHandler( pHandler
)
1238 , m_nError( ERRCODE_NONE
)
1239 , m_bTerminated (sal_False
)
1240 , m_bDontClose( sal_False
)
1241 , m_bStreamValid (sal_False
)
1243 SetSynchronMode( sal_True
);
1246 //----------------------------------------------------------------------------
1247 UcbLockBytes::~UcbLockBytes()
1249 if ( !m_bDontClose
)
1251 if ( m_xInputStream
.is() )
1255 m_xInputStream
->closeInput();
1257 catch (const RuntimeException
&)
1260 catch (const IOException
&)
1266 if ( !m_xInputStream
.is() && m_xOutputStream
.is() )
1270 m_xOutputStream
->closeOutput();
1272 catch (const RuntimeException
&)
1275 catch (const IOException
&)
1281 Reference
< XInputStream
> UcbLockBytes::getInputStream()
1283 osl::MutexGuard
aGuard( m_aMutex
);
1284 m_bDontClose
= sal_True
;
1285 return m_xInputStream
;
1288 //----------------------------------------------------------------------------
1290 sal_Bool
UcbLockBytes::setStream_Impl( const Reference
<XStream
>& aStream
)
1292 osl::MutexGuard
aGuard( m_aMutex
);
1295 m_xOutputStream
= aStream
->getOutputStream();
1296 setInputStream_Impl( aStream
->getInputStream(), sal_False
);
1297 m_xSeekable
= Reference
< XSeekable
> ( aStream
, UNO_QUERY
);
1301 m_xOutputStream
= Reference
< XOutputStream
>();
1302 setInputStream_Impl( Reference
< XInputStream
>() );
1305 return m_xInputStream
.is();
1308 sal_Bool
UcbLockBytes::setInputStream_Impl( const Reference
<XInputStream
> &rxInputStream
, sal_Bool bSetXSeekable
)
1310 sal_Bool bRet
= sal_False
;
1314 osl::MutexGuard
aGuard( m_aMutex
);
1316 if ( !m_bDontClose
&& m_xInputStream
.is() )
1317 m_xInputStream
->closeInput();
1319 m_xInputStream
= rxInputStream
;
1323 m_xSeekable
= Reference
< XSeekable
> ( rxInputStream
, UNO_QUERY
);
1324 if( !m_xSeekable
.is() && rxInputStream
.is() )
1326 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
1327 Reference
< XOutputStream
> rxTempOut
= Reference
< XOutputStream
> ( TempFile::create(xContext
), UNO_QUERY_THROW
);
1329 ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream
, rxTempOut
);
1330 m_xInputStream
= Reference
< XInputStream
>( rxTempOut
, UNO_QUERY
);
1331 m_xSeekable
= Reference
< XSeekable
> ( rxTempOut
, UNO_QUERY
);
1335 bRet
= m_xInputStream
.is();
1337 catch (const Exception
&)
1341 if ( m_bStreamValid
&& m_xInputStream
.is() )
1342 m_aInitialized
.set();
1347 void UcbLockBytes::SetStreamValid_Impl()
1349 m_bStreamValid
= sal_True
;
1350 if ( m_xInputStream
.is() )
1351 m_aInitialized
.set();
1354 //----------------------------------------------------------------------------
1355 void UcbLockBytes::terminate_Impl()
1357 m_bTerminated
= sal_True
;
1358 m_aInitialized
.set();
1359 m_aTerminated
.set();
1361 if ( GetError() == ERRCODE_NONE
&& !m_xInputStream
.is() )
1363 OSL_FAIL("No InputStream, but no error set!" );
1364 SetError( ERRCODE_IO_NOTEXISTS
);
1367 if ( m_xHandler
.Is() )
1368 m_xHandler
->Handle( UcbLockBytesHandler::DONE
, this );
1371 //----------------------------------------------------------------------------
1372 void UcbLockBytes::SetSynchronMode (sal_Bool bSynchron
)
1374 SvLockBytes::SetSynchronMode (bSynchron
);
1377 //----------------------------------------------------------------------------
1378 ErrCode
UcbLockBytes::ReadAt ( sal_uLong nPos
, void *pBuffer
, sal_uLong nCount
, sal_uLong
*pRead
) const
1380 if ( IsSynchronMode() )
1382 UcbLockBytes
* pThis
= const_cast < UcbLockBytes
* >( this );
1383 pThis
->m_aInitialized
.wait();
1386 Reference
<XInputStream
> xStream
= getInputStream_Impl();
1387 if ( !xStream
.is() )
1389 if ( m_bTerminated
)
1390 return ERRCODE_IO_CANTREAD
;
1392 return ERRCODE_IO_PENDING
;
1398 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1399 if ( !xSeekable
.is() )
1400 return ERRCODE_IO_CANTREAD
;
1404 xSeekable
->seek( nPos
);
1406 catch (const IOException
&)
1408 return ERRCODE_IO_CANTSEEK
;
1410 catch (const com::sun::star::lang::IllegalArgumentException
&)
1412 return ERRCODE_IO_CANTSEEK
;
1415 Sequence
<sal_Int8
> aData
;
1418 if(nCount
> 0x7FFFFFFF)
1420 nCount
= 0x7FFFFFFF;
1424 if ( !m_bTerminated
&& !IsSynchronMode() )
1426 sal_uInt64 nLen
= xSeekable
->getLength();
1427 if ( nPos
+ nCount
> nLen
)
1428 return ERRCODE_IO_PENDING
;
1431 nSize
= xStream
->readBytes( aData
, sal_Int32(nCount
) );
1433 catch (const IOException
&)
1435 return ERRCODE_IO_CANTREAD
;
1438 memcpy (pBuffer
, aData
.getConstArray(), nSize
);
1440 *pRead
= sal_uLong(nSize
);
1442 return ERRCODE_NONE
;
1445 //----------------------------------------------------------------------------
1446 ErrCode
UcbLockBytes::WriteAt ( sal_uLong nPos
, const void *pBuffer
, sal_uLong nCount
, sal_uLong
*pWritten
)
1451 DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" );
1452 DBG_ASSERT( m_aInitialized
.check(), "Writing bevor stream is ready!" );
1454 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1455 Reference
<XOutputStream
> xOutputStream
= getOutputStream_Impl();
1456 if ( !xOutputStream
.is() || !xSeekable
.is() )
1457 return ERRCODE_IO_CANTWRITE
;
1461 xSeekable
->seek( nPos
);
1463 catch (const IOException
&)
1465 return ERRCODE_IO_CANTSEEK
;
1468 sal_Int8
* pData
= (sal_Int8
*) pBuffer
;
1469 Sequence
<sal_Int8
> aData( pData
, nCount
);
1472 xOutputStream
->writeBytes( aData
);
1476 catch (const Exception
&)
1478 return ERRCODE_IO_CANTWRITE
;
1481 return ERRCODE_NONE
;
1484 //----------------------------------------------------------------------------
1485 ErrCode
UcbLockBytes::Flush() const
1487 Reference
<XOutputStream
> xOutputStream
= getOutputStream_Impl();
1488 if ( !xOutputStream
.is() )
1489 return ERRCODE_IO_CANTWRITE
;
1493 xOutputStream
->flush();
1495 catch (const Exception
&)
1497 return ERRCODE_IO_CANTWRITE
;
1500 return ERRCODE_NONE
;
1503 //----------------------------------------------------------------------------
1504 ErrCode
UcbLockBytes::SetSize (sal_uLong nNewSize
)
1506 SvLockBytesStat aStat
;
1507 Stat( &aStat
, (SvLockBytesStatFlag
) 0 );
1508 sal_uLong nSize
= aStat
.nSize
;
1510 if ( nSize
> nNewSize
)
1512 Reference
< XTruncate
> xTrunc( getOutputStream_Impl(), UNO_QUERY
);
1519 DBG_WARNING("Not truncatable!");
1523 if ( nSize
< nNewSize
)
1525 sal_uLong nDiff
= nNewSize
-nSize
, nCount
=0;
1526 sal_uInt8
* pBuffer
= new sal_uInt8
[ nDiff
];
1527 memset(pBuffer
, 0, nDiff
); // initialize for enhanced security
1528 WriteAt( nSize
, pBuffer
, nDiff
, &nCount
);
1530 if ( nCount
!= nDiff
)
1531 return ERRCODE_IO_CANTWRITE
;
1534 return ERRCODE_NONE
;
1537 //----------------------------------------------------------------------------
1538 ErrCode
UcbLockBytes::Stat( SvLockBytesStat
*pStat
, SvLockBytesStatFlag
) const
1540 if ( IsSynchronMode() )
1542 UcbLockBytes
* pThis
= const_cast < UcbLockBytes
* >( this );
1543 pThis
->m_aInitialized
.wait();
1547 return ERRCODE_IO_INVALIDPARAMETER
;
1549 Reference
<XInputStream
> xStream
= getInputStream_Impl();
1550 Reference
<XSeekable
> xSeekable
= getSeekable_Impl();
1552 if ( !xStream
.is() )
1554 if ( m_bTerminated
)
1555 return ERRCODE_IO_INVALIDACCESS
;
1557 return ERRCODE_IO_PENDING
;
1559 else if( !xSeekable
.is() )
1560 return ERRCODE_IO_CANTTELL
;
1564 pStat
->nSize
= sal_uLong(xSeekable
->getLength());
1566 catch (const IOException
&)
1568 return ERRCODE_IO_CANTTELL
;
1571 return ERRCODE_NONE
;
1574 //----------------------------------------------------------------------------
1575 IMPL_LINK_NOARG(UcbLockBytes
, DataAvailHdl
)
1577 if ( hasInputStream_Impl() && m_xHandler
.Is() )
1578 m_xHandler
->Handle( UcbLockBytesHandler::DATA_AVAILABLE
, this );
1583 UcbLockBytesRef
UcbLockBytes::CreateInputLockBytes( const Reference
< XInputStream
>& xInputStream
)
1585 if( !xInputStream
.is() )
1588 UcbLockBytesRef xLockBytes
= new UcbLockBytes();
1589 xLockBytes
->setDontClose_Impl();
1590 xLockBytes
->setInputStream_Impl( xInputStream
);
1591 xLockBytes
->terminate_Impl();
1595 UcbLockBytesRef
UcbLockBytes::CreateLockBytes( const Reference
< XStream
>& xStream
)
1600 UcbLockBytesRef xLockBytes
= new UcbLockBytes();
1601 xLockBytes
->setDontClose_Impl();
1602 xLockBytes
->setStream_Impl( xStream
);
1603 xLockBytes
->terminate_Impl();
1607 UcbLockBytesRef
UcbLockBytes::CreateLockBytes( const Reference
< XContent
>& xContent
, const Sequence
< PropertyValue
>& rProps
,
1608 StreamMode eOpenMode
, const Reference
< XInteractionHandler
>& xInteractionHandler
, UcbLockBytesHandler
* pHandler
)
1610 if( !xContent
.is() )
1613 UcbLockBytesRef xLockBytes
= new UcbLockBytes( pHandler
);
1614 xLockBytes
->SetSynchronMode( !pHandler
);
1615 Reference
< XActiveDataControl
> xSink
;
1616 if ( eOpenMode
& STREAM_WRITE
)
1617 xSink
= (XActiveDataControl
*) new UcbStreamer_Impl( xLockBytes
);
1619 xSink
= (XActiveDataControl
*) new UcbDataSink_Impl( xLockBytes
);
1621 if ( rProps
.getLength() )
1623 Reference
< XCommandProcessor
> xProcessor( xContent
, UNO_QUERY
);
1625 aCommand
.Name
= ::rtl::OUString("setPropertyValues");
1626 aCommand
.Handle
= -1; /* unknown */
1627 aCommand
.Argument
<<= rProps
;
1628 xProcessor
->execute( aCommand
, 0, Reference
< XCommandEnvironment
>() );
1631 OpenCommandArgument2 aArgument
;
1632 aArgument
.Sink
= xSink
;
1633 aArgument
.Mode
= OpenMode::DOCUMENT
;
1636 aCommand
.Name
= ::rtl::OUString( "open" );
1637 aCommand
.Argument
<<= aArgument
;
1639 Reference
< XProgressHandler
> xProgressHdl
= new ProgressHandler_Impl( LINK( &xLockBytes
, UcbLockBytes
, DataAvailHdl
) );
1641 sal_Bool bError
= UCBOpenContentSync( xLockBytes
,
1645 xInteractionHandler
,
1649 if ( xLockBytes
->GetError() == ERRCODE_NONE
&& ( bError
|| !xLockBytes
->getInputStream().is() ) )
1651 OSL_FAIL("No InputStream, but no error set!" );
1652 xLockBytes
->SetError( ERRCODE_IO_GENERAL
);
1660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */