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_unotools.hxx"
26 
27 #include <unotools/ucblockbytes.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <salhelper/condition.hxx>
30 #ifndef _OSL_THREAD_HXX_
31 #include <osl/thread.hxx>
32 #endif
33 #include <tools/urlobj.hxx>
34 #include <ucbhelper/interactionrequest.hxx>
35 #include <com/sun/star/task/XInteractionAbort.hpp>
36 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
37 #include <com/sun/star/ucb/CommandFailedException.hpp>
38 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
39 #ifndef _COM_SUN_STAR_UCB_INTERACTIVEIODEXCEPTION_HPP_
40 #include <com/sun/star/ucb/InteractiveIOException.hpp>
41 #endif
42 #include <com/sun/star/io/XActiveDataStreamer.hpp>
43 #include <com/sun/star/ucb/DocumentHeaderField.hpp>
44 #include <com/sun/star/ucb/XCommandInfo.hpp>
45 #include <com/sun/star/ucb/XCommandProcessor.hpp>
46 #include <com/sun/star/task/XInteractionHandler.hpp>
47 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
48 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
49 #include <com/sun/star/ucb/OpenMode.hpp>
50 #include <com/sun/star/beans/Property.hpp>
51 #include <com/sun/star/beans/PropertyValue.hpp>
52 #include <com/sun/star/beans/XPropertiesChangeNotifier.hpp>
53 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
54 #include <com/sun/star/sdbc/XRow.hpp>
55 #include <com/sun/star/io/XActiveDataSink.hpp>
56 #include <com/sun/star/io/XActiveDataControl.hpp>
57 #include <com/sun/star/io/XSeekable.hpp>
58 #include <cppuhelper/implbase1.hxx>
59 #include <cppuhelper/implbase2.hxx>
60 #include <tools/inetmsg.hxx>
61 #include <com/sun/star/io/XTruncate.hpp>
62 #include <com/sun/star/lang/IllegalArgumentException.hpp>
63 
64 #include <comphelper/storagehelper.hxx>
65 
66 #include <ucbhelper/contentbroker.hxx>
67 #include <ucbhelper/content.hxx>
68 
69 using namespace ::com::sun::star::uno;
70 using namespace ::com::sun::star::io;
71 using namespace ::com::sun::star::uno;
72 using namespace ::com::sun::star::ucb;
73 using namespace ::com::sun::star::task;
74 using namespace ::com::sun::star::lang;
75 using namespace ::com::sun::star::beans;
76 
77 
78 namespace utl
79 {
80 
81 /**
82     Helper class for getting a XInputStream when opening a content
83  */
84 class UcbDataSink_Impl : public ::cppu::WeakImplHelper2< XActiveDataControl, XActiveDataSink >
85 {
86 	UcbLockBytesRef         m_xLockBytes;
87 
88 public:
UcbDataSink_Impl(UcbLockBytes * pLockBytes)89 							UcbDataSink_Impl( UcbLockBytes* pLockBytes )
90 								: m_xLockBytes( pLockBytes )
91 							{}
92 
getLockBytes(void)93 	SvLockBytes*            getLockBytes (void)
94 							{ return m_xLockBytes; }
95 
96 	// XActiveDataControl.
addListener(const Reference<XStreamListener> &)97     virtual void SAL_CALL   addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
removeListener(const Reference<XStreamListener> &)98     virtual void SAL_CALL   removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
start(void)99     virtual void SAL_CALL   start (void) throw(RuntimeException) {}
terminate(void)100     virtual void SAL_CALL   terminate (void) throw(RuntimeException)
101                             { m_xLockBytes->terminate_Impl(); }
102 
103 	// XActiveDataSink.
setInputStream(const Reference<XInputStream> & rxInputStream)104     virtual void SAL_CALL   setInputStream ( const Reference<XInputStream> &rxInputStream) throw(RuntimeException)
105                             { m_xLockBytes->setInputStream_Impl (rxInputStream); }
getInputStream(void)106     virtual Reference<XInputStream> SAL_CALL getInputStream (void) throw(RuntimeException)
107                             { return m_xLockBytes->getInputStream_Impl(); }
108 };
109 
110 /**
111     Helper class for getting a XStream when opening a content
112  */
113 class UcbStreamer_Impl : public ::cppu::WeakImplHelper2< XActiveDataStreamer, XActiveDataControl >
114 {
115     Reference < XStream >   m_xStream;
116     UcbLockBytesRef         m_xLockBytes;
117 
118 public:
119 
UcbStreamer_Impl(UcbLockBytes * pLockBytes)120                             UcbStreamer_Impl( UcbLockBytes* pLockBytes )
121                                 : m_xLockBytes( pLockBytes )
122                             {}
123 
124 	// XActiveDataControl.
addListener(const Reference<XStreamListener> &)125     virtual void SAL_CALL   addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
removeListener(const Reference<XStreamListener> &)126     virtual void SAL_CALL   removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {}
start(void)127     virtual void SAL_CALL   start (void) throw(RuntimeException) {}
terminate(void)128     virtual void SAL_CALL   terminate (void) throw(RuntimeException)
129                             { m_xLockBytes->terminate_Impl(); }
130 
131     // XActiveDataStreamer
setStream(const Reference<XStream> & aStream)132     virtual void SAL_CALL   setStream( const Reference< XStream >& aStream ) throw(RuntimeException)
133                             { m_xStream = aStream; m_xLockBytes->setStream_Impl( aStream ); }
getStream()134     virtual Reference< XStream > SAL_CALL getStream() throw(RuntimeException)
135                             { return m_xStream; }
136 };
137 
138 /**
139     Helper class for progress handling while executing UCB commands
140  */
141 class ProgressHandler_Impl: public ::cppu::WeakImplHelper1< XProgressHandler >
142 {
143     Link                    m_aProgress;
144 
145 public:
ProgressHandler_Impl(const Link & rLink)146                             ProgressHandler_Impl( const Link& rLink )
147                                 : m_aProgress( rLink )
148                             {}
149     // XProgressHandler
push(const Any &)150     virtual void SAL_CALL   push(const Any & /*rStatus*/) throw (RuntimeException) {}
pop()151     virtual void SAL_CALL   pop() throw (RuntimeException) {}
update(const Any &)152     virtual void SAL_CALL   update(const Any & /*rStatus*/) throw (RuntimeException)
153                             { if ( m_aProgress.IsSet() ) m_aProgress.Call( 0 ); }
154 };
155 
156 /**
157     Helper class for managing interactions and progress when executing UCB commands
158  */
159 class UcbTaskEnvironment : public ::cppu::WeakImplHelper1< XCommandEnvironment >
160 {
161     Reference< XInteractionHandler >                m_xInteractionHandler;
162     Reference< XProgressHandler >                   m_xProgressHandler;
163 
164 public:
UcbTaskEnvironment(const Reference<XInteractionHandler> & rxInteractionHandler,const Reference<XProgressHandler> & rxProgressHandler)165                             UcbTaskEnvironment( const Reference< XInteractionHandler>& rxInteractionHandler,
166                                                 const Reference< XProgressHandler>& rxProgressHandler )
167                                 : m_xInteractionHandler( rxInteractionHandler )
168                                 , m_xProgressHandler( rxProgressHandler )
169                             {}
170 
171 
getInteractionHandler()172     virtual Reference<XInteractionHandler> SAL_CALL getInteractionHandler() throw (RuntimeException)
173 	{ return m_xInteractionHandler; }
174 
getProgressHandler()175     virtual Reference<XProgressHandler> SAL_CALL    getProgressHandler() throw (RuntimeException)
176 	{ return m_xProgressHandler; }
177 };
178 
179 
180 /**
181     Helper class for property change notifies when executing UCB commands
182 */
183 class UcbPropertiesChangeListener_Impl : public ::cppu::WeakImplHelper1< XPropertiesChangeListener >
184 {
185 public:
186     UcbLockBytesRef         m_xLockBytes;
187 
UcbPropertiesChangeListener_Impl(UcbLockBytesRef rRef)188                             UcbPropertiesChangeListener_Impl( UcbLockBytesRef rRef )
189                                 : m_xLockBytes( rRef )
190                             {}
191 
disposing(const EventObject &)192     virtual void SAL_CALL   disposing ( const EventObject &/*rEvent*/) throw(RuntimeException) {}
193     virtual void SAL_CALL   propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException);
194 };
195 
propertiesChange(const Sequence<PropertyChangeEvent> & rEvent)196 void SAL_CALL UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException)
197 {
198 	sal_Int32 i, n = rEvent.getLength();
199 	for (i = 0; i < n; i++)
200 	{
201 		PropertyChangeEvent evt (rEvent[i]);
202         if (evt.PropertyName == ::rtl::OUString::createFromAscii ("DocumentHeader"))
203 		{
204 			Sequence<DocumentHeaderField> aHead;
205 			if (evt.NewValue >>= aHead)
206 			{
207                 sal_Int32 k, m = aHead.getLength();
208                 for (k = 0; k < m; k++)
209                 {
210                     String aName( aHead[k].Name );
211                     String aValue( aHead[k].Value );
212 
213                     if (aName.CompareIgnoreCaseToAscii("Expires") == COMPARE_EQUAL)
214                     {
215                         DateTime aExpires (0, 0);
216                         if (INetRFC822Message::ParseDateField (aValue, aExpires))
217                         {
218                             aExpires.ConvertToLocalTime();
219                             m_xLockBytes->SetExpireDate_Impl( aExpires );
220                         }
221                     }
222                 }
223 			}
224 
225             m_xLockBytes->SetStreamValid_Impl();
226 		}
227         else if (evt.PropertyName == rtl::OUString::createFromAscii ("PresentationURL"))
228 		{
229             ::rtl::OUString aUrl;
230 			if (evt.NewValue >>= aUrl)
231 			{
232                 ::rtl::OUString aBad (::rtl::OUString::createFromAscii ("private:"));
233 				if (!(aUrl.compareTo (aBad, aBad.getLength()) == 0))
234 				{
235 					// URL changed (Redirection).
236                     m_xLockBytes->SetRealURL_Impl( aUrl );
237 				}
238 			}
239 		}
240         else if (evt.PropertyName == ::rtl::OUString::createFromAscii ("MediaType"))
241         {
242             ::rtl::OUString aContentType;
243             if (evt.NewValue >>= aContentType)
244                 m_xLockBytes->SetContentType_Impl( aContentType );
245         }
246 	}
247 }
248 
249 
250 
251 class Moderator
252 	: public osl::Thread
253 {
254 	// usage restriction:
255 	// It might be possible, that the call to the interactionhandler and/or
256 	// progresshandler is done asynchrounsly, while the 'execute' simply
257 	// returns. This would imply that these class must be refcounted !!!
258 
259 public:
260 
261 	Moderator(
262 		Reference < XContent >& xContent,
263 		Reference < XInteractionHandler >& xInteract,
264 		Reference < XProgressHandler >& xProgress,
265 		const Command& rArg
266     )
267         throw(
268             ContentCreationException,
269             RuntimeException
270         );
271 
272 	~Moderator();
273 
274 
275 	enum ResultType {
276 		NORESULT,
277 
278 		INTERACTIONREQUEST,    // reply expected
279 
280 		PROGRESSPUSH,
281 		PROGRESSUPDATE,
282 		PROGRESSPOP,
283 
284         INPUTSTREAM,
285         STREAM,
286 
287 		RESULT,
288 		TIMEDOUT,
289 		COMMANDABORTED,
290 		COMMANDFAILED,
291 		INTERACTIVEIO,
292 		UNSUPPORTED,
293 		GENERAL
294 	};
295 
296 
297 	class ConditionRes
298 		: public salhelper::Condition
299 	{
300 	public:
301 
ConditionRes(osl::Mutex & aMutex,Moderator & aModerator)302 		ConditionRes(osl::Mutex& aMutex,Moderator& aModerator)
303 			: salhelper::Condition(aMutex),
304               m_aModerator(aModerator)
305 		{
306 		}
307 
308 	protected:
309 
applies() const310 		bool applies() const {
311 			return m_aModerator.m_aResultType != NORESULT;
312 		}
313 
314 	private:
315 
316 		Moderator& m_aModerator;
317 	};
318 
319 
320 	struct Result {
321 		ResultType        type;
322 		Any               result;
323 		sal_Int32         ioErrorCode;
324 	};
325 
326 
327 	Result getResult(const sal_uInt32 milliSec);
328 
329 
330 	enum ReplyType {
331 		NOREPLY,
332 		EXIT,
333 		RETRY,
334 		REQUESTHANDLED
335 	};
336 
337 
338 	class ConditionRep
339 		: public salhelper::Condition
340 	{
341 	public:
342 
ConditionRep(osl::Mutex & aMutex,Moderator & aModerator)343 		ConditionRep(osl::Mutex& aMutex,Moderator& aModerator)
344 			: salhelper::Condition(aMutex),
345               m_aModerator(aModerator)
346 		{
347 		}
348 
349 	protected:
350 
applies() const351 		bool applies() const {
352 			return m_aModerator.m_aReplyType != NOREPLY;
353 		}
354 
355 	private:
356 
357 		Moderator& m_aModerator;
358 	};
359 
360 	void setReply(ReplyType);
361 
362 
363 	void handle( const Reference<XInteractionRequest >& Request );
364 
365 	void push( const Any& Status );
366 
367 	void update( const Any& Status );
368 
369 	void pop(  );
370 
371     void setStream(const Reference< XStream >& aStream);
372 
373     void setInputStream(const Reference<XInputStream> &rxInputStream);
374 
375 
376 protected:
377 
378 	virtual void SAL_CALL run();
379 
380 	virtual void SAL_CALL onTerminated();
381 
382 private:
383 
384     osl::Mutex        m_aMutex;
385 
386     friend class ConditionRes;
387 
388 	ConditionRes      m_aRes;
389 	ResultType        m_aResultType;
390 	sal_Int32         m_nIOErrorCode;
391 	Any               m_aResult;
392 
393     friend class ConditionRep;
394 
395 	ConditionRep      m_aRep;
396 	ReplyType         m_aReplyType;
397 
398     Command                           m_aArg;
399 	::ucbhelper::Content              m_aContent;
400 };
401 
402 
403 class ModeratorsActiveDataStreamer
404 	: public ::cppu::WeakImplHelper1<XActiveDataStreamer>
405 {
406 public:
407 
408 	ModeratorsActiveDataStreamer(Moderator &theModerator);
409 
410 	~ModeratorsActiveDataStreamer();
411 
412     // XActiveDataStreamer
413     virtual void SAL_CALL
414     setStream(
415         const Reference< XStream >& aStream
416     )
417         throw(
418             RuntimeException
419         );
420 
421     virtual Reference<XStream> SAL_CALL
getStream(void)422     getStream (
423         void
424     ) throw(
425         RuntimeException
426     )
427     {
428         osl::MutexGuard aGuard(m_aMutex);
429         return m_xStream;
430     }
431 
432 
433 private:
434 
435     Moderator& m_aModerator;
436 
437     osl::Mutex m_aMutex;
438     Reference<XStream> m_xStream;
439 };
440 
441 
442 
443 class ModeratorsActiveDataSink
444 	: public ::cppu::WeakImplHelper1<XActiveDataSink>
445 {
446 public:
447 
448 	ModeratorsActiveDataSink(Moderator &theModerator);
449 
450 	~ModeratorsActiveDataSink();
451 
452 	// XActiveDataSink.
453     virtual void SAL_CALL
454     setInputStream (
455         const Reference<XInputStream> &rxInputStream
456     )
457         throw(
458             RuntimeException
459         );
460 
461     virtual Reference<XInputStream> SAL_CALL
getInputStream(void)462     getInputStream (
463         void
464     ) throw(
465         RuntimeException
466     )
467     {
468         osl::MutexGuard aGuard(m_aMutex);
469         return m_xStream;
470     }
471 
472 
473 private:
474 
475 	Moderator& m_aModerator;
476     osl::Mutex m_aMutex;
477     Reference<XInputStream> m_xStream;
478 };
479 
480 
481 
ModeratorsActiveDataSink(Moderator & theModerator)482 ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator &theModerator)
483     : m_aModerator(theModerator)
484 {
485 }
486 
487 
~ModeratorsActiveDataSink()488 ModeratorsActiveDataSink::~ModeratorsActiveDataSink()
489 {
490 }
491 
492 // XActiveDataSink.
493 void SAL_CALL
setInputStream(const Reference<XInputStream> & rxInputStream)494 ModeratorsActiveDataSink::setInputStream (
495     const Reference<XInputStream> &rxInputStream
496 )
497     throw(
498         RuntimeException
499     )
500 {
501     m_aModerator.setInputStream(rxInputStream);
502     osl::MutexGuard aGuard(m_aMutex);
503     m_xStream = rxInputStream;
504 }
505 
506 
ModeratorsActiveDataStreamer(Moderator & theModerator)507 ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer(
508     Moderator &theModerator
509 )
510     : m_aModerator(theModerator)
511 {
512 }
513 
514 
~ModeratorsActiveDataStreamer()515 ModeratorsActiveDataStreamer::~ModeratorsActiveDataStreamer()
516 {
517 }
518 
519 // XActiveDataStreamer.
520 void SAL_CALL
setStream(const Reference<XStream> & rxStream)521 ModeratorsActiveDataStreamer::setStream (
522     const Reference<XStream> &rxStream
523 )
524     throw(
525         RuntimeException
526     )
527 {
528     m_aModerator.setStream(rxStream);
529     osl::MutexGuard aGuard(m_aMutex);
530     m_xStream = rxStream;
531 }
532 
533 
534 
535 class ModeratorsInteractionHandler
536 	: public ::cppu::WeakImplHelper1<XInteractionHandler>
537 {
538 public:
539 
540 	ModeratorsInteractionHandler(Moderator &theModerator);
541 
542 	~ModeratorsInteractionHandler();
543 
544 	virtual void SAL_CALL
545 	handle( const Reference<XInteractionRequest >& Request )
546 		throw (RuntimeException);
547 
548 private:
549 
550 	Moderator& m_aModerator;
551 };
552 
553 
554 class ModeratorsProgressHandler
555 	: public ::cppu::WeakImplHelper1<XProgressHandler>
556 {
557 public:
558 
559 	ModeratorsProgressHandler(Moderator &theModerator);
560 
561 	~ModeratorsProgressHandler();
562 
563 	virtual void SAL_CALL push( const Any& Status )
564 		throw (
565 			RuntimeException);
566 
567     virtual void SAL_CALL update( const Any& Status )
568 		throw (RuntimeException);
569 
570     virtual void SAL_CALL pop(  )
571 		throw (RuntimeException);
572 
573 
574 private:
575 
576 	Moderator& m_aModerator;
577 };
578 
579 
ModeratorsProgressHandler(Moderator & theModerator)580 ModeratorsProgressHandler::ModeratorsProgressHandler(Moderator &theModerator)
581 	: m_aModerator(theModerator)
582 {
583 }
584 
~ModeratorsProgressHandler()585 ModeratorsProgressHandler::~ModeratorsProgressHandler()
586 {
587 }
588 
589 
push(const Any & Status)590 void SAL_CALL ModeratorsProgressHandler::push( const Any& Status )
591 	throw (
592 		RuntimeException)
593 {
594 	m_aModerator.push(Status);
595 }
596 
597 
update(const Any & Status)598 void SAL_CALL ModeratorsProgressHandler::update( const Any& Status )
599 	throw (RuntimeException)
600 {
601 	m_aModerator.update(Status);
602 }
603 
604 
pop()605 void SAL_CALL ModeratorsProgressHandler::pop(  )
606 	throw (RuntimeException)
607 {
608 	m_aModerator.pop();
609 }
610 
611 
612 
613 
ModeratorsInteractionHandler(Moderator & aModerator)614 ModeratorsInteractionHandler::ModeratorsInteractionHandler(
615 	Moderator &aModerator)
616 	: m_aModerator(aModerator)
617 {
618 }
619 
620 
~ModeratorsInteractionHandler()621 ModeratorsInteractionHandler::~ModeratorsInteractionHandler()
622 {
623 }
624 
625 
626 void SAL_CALL
handle(const Reference<XInteractionRequest> & Request)627 ModeratorsInteractionHandler::handle(
628 	const Reference<XInteractionRequest >& Request
629 )
630 	throw (
631 		RuntimeException
632 	)
633 {
634 	// wakes up the mainthread
635 	m_aModerator.handle(Request);
636 }
637 
638 
639 
640 
Moderator(Reference<XContent> & xContent,Reference<XInteractionHandler> & xInteract,Reference<XProgressHandler> & xProgress,const Command & rArg)641 Moderator::Moderator(
642 	Reference < XContent >& xContent,
643 	Reference < XInteractionHandler >& xInteract,
644 	Reference < XProgressHandler >& xProgress,
645 	const Command& rArg
646 )
647     throw(
648         ::com::sun::star::ucb::ContentCreationException,
649         ::com::sun::star::uno::RuntimeException
650     )
651 	: m_aMutex(),
652 
653       m_aRes(m_aMutex,*this),
654 	  m_aResultType(NORESULT),
655 	  m_nIOErrorCode(0),
656 	  m_aResult(),
657 
658 	  m_aRep(m_aMutex,*this),
659 	  m_aReplyType(NOREPLY),
660 
661 	  m_aArg(rArg),
662       m_aContent(
663           xContent,
664           new UcbTaskEnvironment(
665               xInteract.is() ? new ModeratorsInteractionHandler(*this) : 0,
666               xProgress.is() ? new ModeratorsProgressHandler(*this) : 0
667           ))
668 {
669     // now exchange the whole data sink stuff
670     // with a thread safe version
671 
672     Reference<XInterface> *pxSink = NULL;
673 
674     PostCommandArgument2 aPostArg;
675     OpenCommandArgument2 aOpenArg;
676 
677     int dec(2);
678     if(m_aArg.Argument >>= aPostArg) {
679         pxSink = &aPostArg.Sink;
680         dec = 0;
681     }
682     else if(m_aArg.Argument >>= aOpenArg) {
683         pxSink = &aOpenArg.Sink;
684         dec = 1;
685     }
686 
687     if(dec ==2)
688         throw ContentCreationException();
689 
690     Reference < XActiveDataSink > xActiveSink(*pxSink,UNO_QUERY);
691     if(xActiveSink.is())
692         *pxSink = Reference<XInterface>(
693             (cppu::OWeakObject*)new ModeratorsActiveDataSink(*this));
694 
695     Reference<XActiveDataStreamer> xStreamer( *pxSink, UNO_QUERY );
696     if ( xStreamer.is() )
697         *pxSink = Reference<XInterface>(
698             (cppu::OWeakObject*)new ModeratorsActiveDataStreamer(*this));
699 
700     if(dec == 0)
701         m_aArg.Argument <<= aPostArg;
702     else if(dec == 1)
703         m_aArg.Argument <<= aOpenArg;
704 }
705 
706 
~Moderator()707 Moderator::~Moderator()
708 {
709 }
710 
711 
getResult(const sal_uInt32 milliSec)712 Moderator::Result Moderator::getResult(const sal_uInt32 milliSec)
713 {
714 	Result ret;
715 	try {
716         salhelper::ConditionWaiter aWaiter(m_aRes,milliSec);
717         ret.type = m_aResultType;
718         ret.result = m_aResult;
719         ret.ioErrorCode = m_nIOErrorCode;
720 
721         // reset
722         m_aResultType = NORESULT;
723 	}
724 	catch(const salhelper::ConditionWaiter::timedout&)
725 	{
726 		ret.type = TIMEDOUT;
727 	}
728 
729 	return ret;
730 }
731 
732 
setReply(ReplyType aReplyType)733 void Moderator::setReply(ReplyType aReplyType )
734 {
735 	salhelper::ConditionModifier aMod(m_aRep);
736 	m_aReplyType = aReplyType;
737 }
738 
739 
handle(const Reference<XInteractionRequest> & Request)740 void Moderator::handle( const Reference<XInteractionRequest >& Request )
741 {
742 	ReplyType aReplyType;
743 
744 	do {
745 		{
746 			salhelper::ConditionModifier aMod(m_aRes);
747 			m_aResultType = INTERACTIONREQUEST;
748 			m_aResult <<= Request;
749 		}
750 
751 		{
752 			salhelper::ConditionWaiter aWait(m_aRep);
753 			aReplyType = m_aReplyType;
754 
755 			// reset
756 			m_aReplyType = NOREPLY;
757 		}
758 
759 		if(aReplyType == EXIT) {
760 			Sequence<Reference<XInteractionContinuation> > aSeq(
761 				Request->getContinuations());
762 			for(sal_Int32 i = 0; i < aSeq.getLength(); ++i) {
763 				Reference<XInteractionAbort> aRef(aSeq[i],UNO_QUERY);
764 				if(aRef.is()) {
765 					aRef->select();
766 				}
767 			}
768 
769 			// resignal the exitcondition
770 			setReply(EXIT);
771 			break;
772 		}
773 	} while(aReplyType != REQUESTHANDLED);
774 }
775 
776 
777 
push(const Any & Status)778 void Moderator::push( const Any& Status )
779 {
780     {
781         salhelper::ConditionModifier aMod(m_aRes);
782         m_aResultType = PROGRESSPUSH;
783         m_aResult = Status;
784     }
785 	ReplyType aReplyType;
786     {
787         salhelper::ConditionWaiter aWait(m_aRep);
788 		aReplyType = m_aReplyType;
789 		m_aReplyType = NOREPLY;
790     }
791 	if(aReplyType == EXIT)
792 		setReply(EXIT);
793 }
794 
795 
update(const Any & Status)796 void Moderator::update( const Any& Status )
797 {
798 	{
799         salhelper::ConditionModifier aMod(m_aRes);
800         m_aResultType = PROGRESSUPDATE;
801         m_aResult = Status;
802     }
803 	ReplyType aReplyType;
804     {
805         salhelper::ConditionWaiter aWait(m_aRep);
806 		aReplyType = m_aReplyType;
807 		m_aReplyType = NOREPLY;
808     }
809 	if(aReplyType == EXIT)
810 		setReply(EXIT);
811 }
812 
813 
pop()814 void Moderator::pop(  )
815 {
816     {
817         salhelper::ConditionModifier aMod(m_aRes);
818         m_aResultType = PROGRESSPOP;
819     }
820 	ReplyType aReplyType;
821     {
822         salhelper::ConditionWaiter aWait(m_aRep);
823 		aReplyType = m_aReplyType;
824 		m_aReplyType = NOREPLY;
825 	}
826 	if(aReplyType == EXIT)
827 		setReply(EXIT);
828 }
829 
830 
setStream(const Reference<XStream> & aStream)831 void Moderator::setStream(const Reference< XStream >& aStream)
832 {
833     {
834         salhelper::ConditionModifier aMod(m_aRes);
835         m_aResultType = STREAM;
836         m_aResult <<= aStream;
837     }
838 	ReplyType aReplyType;
839     {
840         salhelper::ConditionWaiter aWait(m_aRep);
841 		aReplyType = m_aReplyType;
842         m_aReplyType = NOREPLY;
843     }
844 	if(aReplyType == EXIT)
845 		setReply(EXIT);
846 }
847 
848 
setInputStream(const Reference<XInputStream> & rxInputStream)849 void Moderator::setInputStream(const Reference<XInputStream> &rxInputStream)
850 {
851     {
852         salhelper::ConditionModifier aMod(m_aRes);
853         m_aResultType = INPUTSTREAM;
854         m_aResult <<= rxInputStream;
855     }
856 	ReplyType aReplyType;
857     {
858         salhelper::ConditionWaiter aWait(m_aRep);
859 		aReplyType = m_aReplyType;
860         m_aReplyType = NOREPLY;
861     }
862 	if(aReplyType == EXIT)
863 		setReply(EXIT);
864 }
865 
866 
867 
run()868 void SAL_CALL Moderator::run()
869 {
870 	ResultType aResultType;
871 	Any        aResult;
872 	sal_Int32  nIOErrorCode = 0;
873 
874     try
875     {
876 		aResult = m_aContent.executeCommand(m_aArg.Name,m_aArg.Argument);
877 		aResultType = RESULT;
878     }
879     catch ( CommandAbortedException )
880     {
881 		aResultType = COMMANDABORTED;
882     }
883     catch ( CommandFailedException )
884     {
885 		aResultType = COMMANDFAILED;
886     }
887     catch ( InteractiveIOException& r )
888     {
889 		nIOErrorCode = r.Code;
890 		aResultType = INTERACTIVEIO;
891     }
892     catch ( UnsupportedDataSinkException& )
893     {
894 		aResultType = UNSUPPORTED;
895     }
896     catch ( Exception )
897     {
898 		aResultType = GENERAL;
899     }
900 
901 	{
902 		salhelper::ConditionModifier aMod(m_aRes);
903 		m_aResultType = aResultType;
904 		m_aResult = aResult;
905 		m_nIOErrorCode = nIOErrorCode;
906 	}
907 }
908 
909 
910 
onTerminated()911 void SAL_CALL Moderator::onTerminated()
912 {
913     {
914         salhelper::ConditionWaiter aWaiter(m_aRep);
915     }
916  	delete this;
917 }
918 
919 
920 /**
921    Function for opening UCB contents synchronously,
922    but with handled timeout;
923 */
924 
925 static sal_Bool _UCBOpenContentSync(
926 	UcbLockBytesRef xLockBytes,
927 	Reference < XContent > xContent,
928 	const Command& rArg,
929 	Reference < XInterface > xSink,
930 	Reference < XInteractionHandler > xInteract,
931 	Reference < XProgressHandler > xProgress,
932 	UcbLockBytesHandlerRef xHandler );
933 
934 
UCBOpenContentSync(UcbLockBytesRef xLockBytes,Reference<XContent> xContent,const Command & rArg,Reference<XInterface> xSink,Reference<XInteractionHandler> xInteract,Reference<XProgressHandler> xProgress,UcbLockBytesHandlerRef xHandler)935 static sal_Bool UCBOpenContentSync(
936 	UcbLockBytesRef xLockBytes,
937 	Reference < XContent > xContent,
938 	const Command& rArg,
939 	Reference < XInterface > xSink,
940 	Reference < XInteractionHandler > xInteract,
941 	Reference < XProgressHandler > xProgress,
942 	UcbLockBytesHandlerRef xHandler )
943 {
944     // http protocol must be handled in a special way:
945 	//        during the opening process the input stream may change
946     //        only the last inputstream after notifying the document
947 	//        headers is valid
948 
949 	Reference<XContentIdentifier> xContId(
950 		xContent.is() ? xContent->getIdentifier() : 0 );
951 
952 	rtl::OUString aScheme;
953 	if(xContId.is())
954 		aScheme = xContId->getContentProviderScheme();
955 
956     // now determine wether we use a timeout or not;
957     if( ! aScheme.equalsIgnoreAsciiCaseAscii("http")                &&
958 		! aScheme.equalsIgnoreAsciiCaseAscii("https")                &&
959         ! aScheme.equalsIgnoreAsciiCaseAscii("vnd.sun.star.webdav") &&
960         ! aScheme.equalsIgnoreAsciiCaseAscii("ftp"))
961 		return _UCBOpenContentSync(
962 			xLockBytes,xContent,rArg,xSink,xInteract,xProgress,xHandler);
963 
964     if ( (aScheme.compareToAscii( "http" ) != COMPARE_EQUAL) ||
965 		 (aScheme.compareToAscii( "https" ) != COMPARE_EQUAL) )
966         xLockBytes->SetStreamValid_Impl();
967 
968     Reference< XPropertiesChangeListener > xListener;
969 	Reference< XPropertiesChangeNotifier > xProps(xContent,UNO_QUERY);
970     if(xProps.is()) {
971 		xListener =
972 			new UcbPropertiesChangeListener_Impl(xLockBytes);
973         xProps->addPropertiesChangeListener(
974 			Sequence< ::rtl::OUString >(),
975 			xListener);
976 	}
977 
978     Any aResult;
979     bool bException(false);
980     bool bAborted(false);
981     bool bResultAchieved(false);
982 
983     Moderator* pMod = 0;
984     try {
985         pMod = new Moderator(xContent,xInteract,xProgress,rArg);
986         pMod->create();
987     } catch(const ContentCreationException&) {
988         bResultAchieved = bException = true;
989         xLockBytes->SetError( ERRCODE_IO_GENERAL );
990     }
991 
992     sal_uInt32 nTimeout(5000); // initially 5000 milliSec
993 	while(!bResultAchieved) {
994 
995         Moderator::Result res;
996 		// try to get the result for with timeout
997 		res = pMod->getResult(nTimeout);
998 
999 		switch(res.type) {
1000         case Moderator::PROGRESSPUSH:
1001 			{
1002 				if(xProgress.is())
1003 					xProgress->push(res.result);
1004 				pMod->setReply(Moderator::REQUESTHANDLED);
1005 				break;
1006 			}
1007         case Moderator::PROGRESSUPDATE:
1008 			{
1009 				if(xProgress.is())
1010 					xProgress->update(res.result);
1011 				pMod->setReply(Moderator::REQUESTHANDLED);
1012 				break;
1013 			}
1014         case Moderator::PROGRESSPOP:
1015 			{
1016 				if(xProgress.is())
1017 					xProgress->pop();
1018 				pMod->setReply(Moderator::REQUESTHANDLED);
1019 				break;
1020 			}
1021         case Moderator::STREAM:
1022             {
1023                 Reference<XStream> result;
1024                 if(res.result >>= result) {
1025                     Reference < XActiveDataStreamer > xStreamer(
1026                         xSink, UNO_QUERY
1027                     );
1028 
1029                     if(xStreamer.is())
1030                         xStreamer->setStream(result);
1031                 }
1032 				pMod->setReply(Moderator::REQUESTHANDLED);
1033                 break;
1034             }
1035         case Moderator::INPUTSTREAM:
1036             {
1037 				Reference<XInputStream> result;
1038 				res.result >>= result;
1039                 Reference < XActiveDataSink > xActiveSink(
1040                     xSink, UNO_QUERY
1041                 );
1042 
1043                 if(xActiveSink.is())
1044                     xActiveSink->setInputStream(result);
1045 				pMod->setReply(Moderator::REQUESTHANDLED);
1046                 break;
1047             }
1048         case Moderator::TIMEDOUT:
1049 			{
1050 				Reference<XInteractionRetry> xRet;
1051 				if(xInteract.is()) {
1052 					InteractiveNetworkConnectException aExcep;
1053 					INetURLObject aURL(
1054 						xContId.is() ?
1055 						xContId->getContentIdentifier() :
1056 						rtl::OUString() );
1057 					aExcep.Server = aURL.GetHost();
1058 					aExcep.Classification = InteractionClassification_ERROR;
1059 					aExcep.Message =
1060 						rtl::OUString(
1061 							RTL_CONSTASCII_USTRINGPARAM(
1062 								"server not responding after five seconds"));
1063 					Any request;
1064 					request <<= aExcep;
1065 					ucbhelper::InteractionRequest *ir =
1066 						new ucbhelper::InteractionRequest(request);
1067 					Reference<XInteractionRequest> xIR(ir);
1068 					Sequence<Reference<XInteractionContinuation> > aSeq(2);
1069 					ucbhelper::InteractionRetry *retryP =
1070 						new ucbhelper::InteractionRetry(ir);
1071 					aSeq[0] = retryP;
1072 					ucbhelper::InteractionAbort *abortP =
1073 						new ucbhelper::InteractionAbort(ir);
1074 					aSeq[1] = abortP;
1075 
1076 					ir->setContinuations(aSeq);
1077 					xInteract->handle(xIR);
1078 					rtl::Reference< ucbhelper::InteractionContinuation > ref
1079 						= ir->getSelection();
1080 					if(ref.is()) {
1081 						Reference<XInterface> xInt(ref.get());
1082 						xRet = Reference<XInteractionRetry>(xInt,UNO_QUERY);
1083 					}
1084 				}
1085 
1086 				if(!xRet.is()) {
1087 					bAborted = true;
1088 					xLockBytes->SetError(ERRCODE_ABORT);
1089 				}
1090 
1091 				break;
1092 			}
1093         case Moderator::INTERACTIONREQUEST:
1094 			{
1095 				Reference<XInteractionRequest> Request;
1096 				res.result >>= Request;
1097 				xInteract->handle(Request);
1098 				pMod->setReply(Moderator::REQUESTHANDLED);
1099 				break;
1100 			}
1101         case Moderator::RESULT:
1102 			{
1103 				bResultAchieved = true;
1104 				aResult = res.result;
1105 				break;
1106 			}
1107         case Moderator::COMMANDABORTED:
1108 			{
1109 				bAborted = true;
1110 				xLockBytes->SetError( ERRCODE_ABORT );
1111 				break;
1112 			}
1113         case Moderator::COMMANDFAILED:
1114 			{
1115 				bAborted = true;
1116 				xLockBytes->SetError( ERRCODE_ABORT );
1117 				break;
1118 			}
1119         case Moderator::INTERACTIVEIO:
1120 			{
1121 				bException = true;
1122 				if ( res.ioErrorCode == IOErrorCode_ACCESS_DENIED ||
1123 					 res.ioErrorCode == IOErrorCode_LOCKING_VIOLATION )
1124 					xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED );
1125 				else if ( res.ioErrorCode == IOErrorCode_NOT_EXISTING )
1126 					xLockBytes->SetError( ERRCODE_IO_NOTEXISTS );
1127 				else if ( res.ioErrorCode == IOErrorCode_CANT_READ )
1128 					xLockBytes->SetError( ERRCODE_IO_CANTREAD );
1129 				else
1130 					xLockBytes->SetError( ERRCODE_IO_GENERAL );
1131 				break;
1132 			}
1133         case Moderator::UNSUPPORTED:
1134 			{
1135 				bException = true;
1136 				xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED );
1137 				break;
1138 			}
1139         default:
1140 			{
1141 				bException = true;
1142 				xLockBytes->SetError( ERRCODE_IO_GENERAL );
1143 				break;
1144 			}
1145 		}
1146 
1147 		bResultAchieved |= bException;
1148 		bResultAchieved |= bAborted;
1149         if(nTimeout == 5000) nTimeout *= 2;
1150     }
1151 
1152     if(pMod) pMod->setReply(Moderator::EXIT);
1153 
1154     if ( bAborted || bException )
1155     {
1156         if( xHandler.Is() )
1157             xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes );
1158 
1159         Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY );
1160         if ( xActiveSink.is() )
1161             xActiveSink->setInputStream( Reference < XInputStream >() );
1162 
1163         Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY );
1164         if ( xStreamer.is() )
1165             xStreamer->setStream( Reference < XStream >() );
1166     }
1167 
1168     Reference < XActiveDataControl > xControl( xSink, UNO_QUERY );
1169     if ( xControl.is() )
1170         xControl->terminate();
1171 
1172     if ( xProps.is() )
1173         xProps->removePropertiesChangeListener(
1174 			Sequence< ::rtl::OUString >(),
1175 			xListener );
1176 
1177     return ( bAborted || bException );
1178 }
1179 
1180 /**
1181     Function for opening UCB contents synchronously
1182  */
_UCBOpenContentSync(UcbLockBytesRef xLockBytes,Reference<XContent> xContent,const Command & rArg,Reference<XInterface> xSink,Reference<XInteractionHandler> xInteract,Reference<XProgressHandler> xProgress,UcbLockBytesHandlerRef xHandler)1183 static sal_Bool _UCBOpenContentSync(
1184 	UcbLockBytesRef xLockBytes,
1185 	Reference < XContent > xContent,
1186 	const Command& rArg,
1187 	Reference < XInterface > xSink,
1188 	Reference < XInteractionHandler > xInteract,
1189 	Reference < XProgressHandler > xProgress,
1190 	UcbLockBytesHandlerRef xHandler )
1191 {
1192     ::ucbhelper::Content aContent( xContent, new UcbTaskEnvironment( xInteract, xProgress ) );
1193     Reference < XContentIdentifier > xIdent = xContent->getIdentifier();
1194     ::rtl::OUString aScheme = xIdent->getContentProviderScheme();
1195 
1196     // http protocol must be handled in a special way: during the opening process the input stream may change
1197     // only the last inputstream after notifying the document headers is valid
1198     if ( aScheme.compareToAscii("http") != COMPARE_EQUAL )
1199         xLockBytes->SetStreamValid_Impl();
1200 
1201     Reference< XPropertiesChangeListener > xListener = new UcbPropertiesChangeListener_Impl( xLockBytes );
1202     Reference< XPropertiesChangeNotifier > xProps ( xContent, UNO_QUERY );
1203     if ( xProps.is() )
1204         xProps->addPropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener );
1205 
1206     Any aResult;
1207     bool bException = false;
1208     bool bAborted = false;
1209 
1210     try
1211     {
1212         aResult = aContent.executeCommand( rArg.Name, rArg.Argument );
1213     }
1214     catch ( CommandAbortedException )
1215     {
1216         bAborted = true;
1217 		xLockBytes->SetError( ERRCODE_ABORT );
1218     }
1219     catch ( CommandFailedException )
1220     {
1221         bAborted = true;
1222 		xLockBytes->SetError( ERRCODE_ABORT );
1223     }
1224     catch ( InteractiveIOException& r )
1225     {
1226 		bException = true;
1227         if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION )
1228 			xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED );
1229 		else if ( r.Code == IOErrorCode_NOT_EXISTING )
1230 			xLockBytes->SetError( ERRCODE_IO_NOTEXISTS );
1231 		else if ( r.Code == IOErrorCode_CANT_READ )
1232 			xLockBytes->SetError( ERRCODE_IO_CANTREAD );
1233 		else
1234 			xLockBytes->SetError( ERRCODE_IO_GENERAL );
1235     }
1236     catch ( UnsupportedDataSinkException& )
1237     {
1238 		bException = true;
1239         xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED );
1240     }
1241     catch ( Exception )
1242     {
1243         bException = true;
1244 		xLockBytes->SetError( ERRCODE_IO_GENERAL );
1245     }
1246 
1247     if ( bAborted || bException )
1248     {
1249         if( xHandler.Is() )
1250             xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes );
1251 
1252         Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY );
1253         if ( xActiveSink.is() )
1254             xActiveSink->setInputStream( Reference < XInputStream >() );
1255 
1256         Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY );
1257         if ( xStreamer.is() )
1258             xStreamer->setStream( Reference < XStream >() );
1259     }
1260 
1261     Reference < XActiveDataControl > xControl( xSink, UNO_QUERY );
1262     if ( xControl.is() )
1263         xControl->terminate();
1264 
1265 
1266     if ( xProps.is() )
1267         xProps->removePropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener );
1268 
1269     return ( bAborted || bException );
1270 }
1271 
1272 
1273 //----------------------------------------------------------------------------
UcbLockBytes(UcbLockBytesHandler * pHandler)1274 UcbLockBytes::UcbLockBytes( UcbLockBytesHandler* pHandler )
1275     : m_xInputStream (NULL)
1276     , m_pCommandThread( NULL )
1277     , m_xHandler( pHandler )
1278     , m_nError( ERRCODE_NONE )
1279     , m_bTerminated  (sal_False)
1280     , m_bDontClose( sal_False )
1281     , m_bStreamValid  (sal_False)
1282 {
1283     SetSynchronMode( sal_True );
1284 }
1285 
1286 //----------------------------------------------------------------------------
~UcbLockBytes()1287 UcbLockBytes::~UcbLockBytes()
1288 {
1289     if ( !m_bDontClose )
1290     {
1291         if ( m_xInputStream.is() )
1292         {
1293 			try
1294 			{
1295 				m_xInputStream->closeInput();
1296 			}
1297 			catch ( RuntimeException const & )
1298 			{}
1299 			catch ( IOException const & )
1300 			{}
1301         }
1302     }
1303 
1304     if ( !m_xInputStream.is() && m_xOutputStream.is() )
1305     {
1306         try
1307         {
1308             m_xOutputStream->closeOutput();
1309         }
1310         catch ( RuntimeException const & )
1311         {}
1312         catch ( IOException const & )
1313         {}
1314     }
1315 }
1316 
getInputStream()1317 Reference < XInputStream > UcbLockBytes::getInputStream()
1318 {
1319 	vos::OClearableGuard aGuard( m_aMutex );
1320     m_bDontClose = sal_True;
1321     return m_xInputStream;
1322 }
1323 
getStream()1324 Reference < XStream > UcbLockBytes::getStream()
1325 {
1326 	vos::OClearableGuard aGuard( m_aMutex );
1327 	Reference < XStream > xStream( m_xSeekable, UNO_QUERY );
1328 	if ( xStream.is() )
1329     	m_bDontClose = sal_True;
1330     return xStream;
1331 }
1332 
1333 //----------------------------------------------------------------------------
1334 
setStream_Impl(const Reference<XStream> & aStream)1335 sal_Bool UcbLockBytes::setStream_Impl( const Reference<XStream>& aStream )
1336 {
1337 	vos::OClearableGuard aGuard( m_aMutex );
1338     if ( aStream.is() )
1339     {
1340         m_xOutputStream = aStream->getOutputStream();
1341         setInputStream_Impl( aStream->getInputStream(), sal_False );
1342         m_xSeekable = Reference < XSeekable > ( aStream, UNO_QUERY );
1343     }
1344     else
1345     {
1346         m_xOutputStream = Reference < XOutputStream >();
1347         setInputStream_Impl( Reference < XInputStream >() );
1348     }
1349 
1350     return m_xInputStream.is();
1351 }
1352 
setInputStream_Impl(const Reference<XInputStream> & rxInputStream,sal_Bool bSetXSeekable)1353 sal_Bool UcbLockBytes::setInputStream_Impl( const Reference<XInputStream> &rxInputStream, sal_Bool bSetXSeekable )
1354 {
1355 	sal_Bool bRet = sal_False;
1356 
1357 	try
1358 	{
1359 		vos::OClearableGuard aGuard( m_aMutex );
1360 
1361 		if ( !m_bDontClose && m_xInputStream.is() )
1362 			m_xInputStream->closeInput();
1363 
1364 		m_xInputStream = rxInputStream;
1365 
1366 		if( bSetXSeekable )
1367 		{
1368     		m_xSeekable = Reference < XSeekable > ( rxInputStream, UNO_QUERY );
1369 			if( !m_xSeekable.is() && rxInputStream.is() )
1370 			{
1371             	Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
1372 				Reference< XOutputStream > rxTempOut = Reference < XOutputStream > (
1373 									xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ),
1374 									UNO_QUERY );
1375 
1376 				if( rxTempOut.is() )
1377 				{
1378 					::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream, rxTempOut );
1379 					m_xInputStream = Reference< XInputStream >( rxTempOut, UNO_QUERY );
1380         			m_xSeekable = Reference < XSeekable > ( rxTempOut, UNO_QUERY );
1381 				}
1382 			}
1383 		}
1384 
1385 		bRet = m_xInputStream.is();
1386 		// aGuard.clear();
1387 	}
1388 	catch( Exception& )
1389 	{}
1390 
1391     if ( m_bStreamValid && m_xInputStream.is() )
1392         m_aInitialized.set();
1393 
1394 	return bRet;
1395 }
1396 
SetStreamValid_Impl()1397 void UcbLockBytes::SetStreamValid_Impl()
1398 {
1399     m_bStreamValid = sal_True;
1400     if ( m_xInputStream.is() )
1401         m_aInitialized.set();
1402 }
1403 
1404 //----------------------------------------------------------------------------
terminate_Impl()1405 void UcbLockBytes::terminate_Impl()
1406 {
1407 	m_bTerminated = sal_True;
1408 	m_aInitialized.set();
1409 	m_aTerminated.set();
1410 
1411     if ( GetError() == ERRCODE_NONE && !m_xInputStream.is() )
1412 	{
1413 		DBG_ERROR("No InputStream, but no error set!" );
1414         SetError( ERRCODE_IO_NOTEXISTS );
1415 	}
1416 
1417     if ( m_xHandler.Is() )
1418         m_xHandler->Handle( UcbLockBytesHandler::DONE, this );
1419 }
1420 
1421 //----------------------------------------------------------------------------
SetSynchronMode(sal_Bool bSynchron)1422 void UcbLockBytes::SetSynchronMode (sal_Bool bSynchron)
1423 {
1424 	SvLockBytes::SetSynchronMode (bSynchron);
1425 }
1426 
1427 //----------------------------------------------------------------------------
ReadAt(sal_uLong nPos,void * pBuffer,sal_uLong nCount,sal_uLong * pRead) const1428 ErrCode UcbLockBytes::ReadAt ( sal_uLong nPos, void *pBuffer, sal_uLong nCount, sal_uLong *pRead) const
1429 {
1430 	if ( IsSynchronMode() )
1431     {
1432         UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this );
1433         pThis->m_aInitialized.wait();
1434     }
1435 
1436     Reference <XInputStream> xStream = getInputStream_Impl();
1437 	if ( !xStream.is() )
1438 	{
1439 		if ( m_bTerminated )
1440 			return ERRCODE_IO_CANTREAD;
1441 		else
1442 			return ERRCODE_IO_PENDING;
1443 	}
1444 
1445 	if ( pRead )
1446 		*pRead = 0;
1447 
1448     Reference <XSeekable> xSeekable = getSeekable_Impl();
1449     if ( !xSeekable.is() )
1450 		return ERRCODE_IO_CANTREAD;
1451 
1452 	try
1453 	{
1454         xSeekable->seek( nPos );
1455 	}
1456 	catch ( IOException )
1457 	{
1458 		return ERRCODE_IO_CANTSEEK;
1459 	}
1460 	catch (com::sun::star::lang::IllegalArgumentException)
1461 	{
1462 		return ERRCODE_IO_CANTSEEK;
1463 	}
1464 
1465 	Sequence<sal_Int8> aData;
1466 	sal_Int32          nSize;
1467 
1468 	nCount = VOS_MIN(nCount, 0x7FFFFFFF);
1469 	try
1470 	{
1471 		if ( !m_bTerminated && !IsSynchronMode() )
1472 		{
1473             sal_uInt64 nLen = xSeekable->getLength();
1474 			if ( nPos + nCount > nLen )
1475 				return ERRCODE_IO_PENDING;
1476 		}
1477 
1478 		nSize = xStream->readBytes( aData, sal_Int32(nCount) );
1479 	}
1480 	catch (IOException)
1481 	{
1482 		return ERRCODE_IO_CANTREAD;
1483 	}
1484 
1485 	rtl_copyMemory (pBuffer, aData.getConstArray(), nSize);
1486 	if (pRead)
1487 		*pRead = sal_uLong(nSize);
1488 
1489 	return ERRCODE_NONE;
1490 }
1491 
1492 //----------------------------------------------------------------------------
WriteAt(sal_uLong nPos,const void * pBuffer,sal_uLong nCount,sal_uLong * pWritten)1493 ErrCode UcbLockBytes::WriteAt ( sal_uLong nPos, const void *pBuffer, sal_uLong nCount, sal_uLong *pWritten)
1494 {
1495 	if ( pWritten )
1496 		*pWritten = 0;
1497 
1498     DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" );
1499     DBG_ASSERT( m_aInitialized.check(), "Writing bevor stream is ready!" );
1500 
1501     Reference <XSeekable> xSeekable = getSeekable_Impl();
1502     Reference <XOutputStream> xOutputStream = getOutputStream_Impl();
1503     if ( !xOutputStream.is() || !xSeekable.is() )
1504         return ERRCODE_IO_CANTWRITE;
1505 
1506 	try
1507 	{
1508         xSeekable->seek( nPos );
1509 	}
1510 	catch ( IOException )
1511 	{
1512 		return ERRCODE_IO_CANTSEEK;
1513 	}
1514 
1515     sal_Int8* pData = (sal_Int8*) pBuffer;
1516     Sequence<sal_Int8> aData( pData, nCount );
1517 	try
1518 	{
1519         xOutputStream->writeBytes( aData );
1520         if ( pWritten )
1521             *pWritten = nCount;
1522 	}
1523     catch ( Exception )
1524 	{
1525         return ERRCODE_IO_CANTWRITE;
1526 	}
1527 
1528 	return ERRCODE_NONE;
1529 }
1530 
1531 //----------------------------------------------------------------------------
Flush() const1532 ErrCode UcbLockBytes::Flush() const
1533 {
1534     Reference <XOutputStream > xOutputStream = getOutputStream_Impl();
1535     if ( !xOutputStream.is() )
1536         return ERRCODE_IO_CANTWRITE;
1537 
1538     try
1539     {
1540         xOutputStream->flush();
1541     }
1542     catch( Exception )
1543     {
1544         return ERRCODE_IO_CANTWRITE;
1545     }
1546 
1547     return ERRCODE_NONE;
1548 }
1549 
1550 //----------------------------------------------------------------------------
SetSize(sal_uLong nNewSize)1551 ErrCode UcbLockBytes::SetSize (sal_uLong nNewSize)
1552 {
1553     SvLockBytesStat aStat;
1554     Stat( &aStat, (SvLockBytesStatFlag) 0 );
1555     sal_uLong nSize = aStat.nSize;
1556 
1557     if ( nSize > nNewSize )
1558     {
1559         Reference < XTruncate > xTrunc( getOutputStream_Impl(), UNO_QUERY );
1560         if ( xTrunc.is() )
1561         {
1562             xTrunc->truncate();
1563             nSize = 0;
1564         }
1565         else {
1566             DBG_WARNING("Not truncatable!");
1567         }
1568     }
1569 
1570     if ( nSize < nNewSize )
1571     {
1572         sal_uLong nDiff = nNewSize-nSize, nCount=0;
1573         sal_uInt8* pBuffer = new sal_uInt8[ nDiff ];
1574         memset(pBuffer, 0, nDiff); // initialize for enhanced security
1575         WriteAt( nSize, pBuffer, nDiff, &nCount );
1576         delete[] pBuffer;
1577         if ( nCount != nDiff )
1578             return ERRCODE_IO_CANTWRITE;
1579     }
1580 
1581     return ERRCODE_NONE;
1582 }
1583 
1584 //----------------------------------------------------------------------------
Stat(SvLockBytesStat * pStat,SvLockBytesStatFlag) const1585 ErrCode UcbLockBytes::Stat( SvLockBytesStat *pStat, SvLockBytesStatFlag) const
1586 {
1587 	if ( IsSynchronMode() )
1588     {
1589         UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this );
1590         pThis->m_aInitialized.wait();
1591     }
1592 
1593 	if (!pStat)
1594 		return ERRCODE_IO_INVALIDPARAMETER;
1595 
1596     Reference <XInputStream> xStream = getInputStream_Impl();
1597     Reference <XSeekable> xSeekable = getSeekable_Impl();
1598 
1599     if ( !xStream.is() )
1600     {
1601 		if ( m_bTerminated )
1602             return ERRCODE_IO_INVALIDACCESS;
1603 		else
1604 			return ERRCODE_IO_PENDING;
1605     }
1606     else if( !xSeekable.is() )
1607 		return ERRCODE_IO_CANTTELL;
1608 
1609 	try
1610 	{
1611         pStat->nSize = sal_uLong(xSeekable->getLength());
1612 	}
1613 	catch (IOException)
1614 	{
1615 		return ERRCODE_IO_CANTTELL;
1616 	}
1617 
1618     return ERRCODE_NONE;
1619 }
1620 
1621 //----------------------------------------------------------------------------
Cancel()1622 void UcbLockBytes::Cancel()
1623 {
1624 	// is alive only for compatibility reasons
1625 	OSL_ENSURE( m_bTerminated, "UcbLockBytes is not thread safe so it can be used only syncronously!\n" );
1626 }
1627 
1628 //----------------------------------------------------------------------------
IMPL_LINK(UcbLockBytes,DataAvailHdl,void *,EMPTYARG)1629 IMPL_LINK( UcbLockBytes, DataAvailHdl, void*, EMPTYARG )
1630 {
1631     if ( hasInputStream_Impl() && m_xHandler.Is() )
1632         m_xHandler->Handle( UcbLockBytesHandler::DATA_AVAILABLE, this );
1633 
1634 	return 0;
1635 }
1636 
CreateInputLockBytes(const Reference<XInputStream> & xInputStream)1637 UcbLockBytesRef UcbLockBytes::CreateInputLockBytes( const Reference< XInputStream >& xInputStream )
1638 {
1639     if( !xInputStream.is() )
1640 		return NULL;;
1641 
1642     UcbLockBytesRef xLockBytes = new UcbLockBytes();
1643     xLockBytes->setDontClose_Impl();
1644     xLockBytes->setInputStream_Impl( xInputStream );
1645     xLockBytes->terminate_Impl();
1646     return xLockBytes;
1647 }
1648 
CreateLockBytes(const Reference<XStream> & xStream)1649 UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference< XStream >& xStream )
1650 {
1651     if( !xStream.is() )
1652 		return NULL;;
1653 
1654     UcbLockBytesRef xLockBytes = new UcbLockBytes();
1655     xLockBytes->setDontClose_Impl();
1656     xLockBytes->setStream_Impl( xStream );
1657     xLockBytes->terminate_Impl();
1658     return xLockBytes;
1659 }
1660 
CreateLockBytes(const Reference<XContent> & xContent,const::rtl::OUString & rReferer,const::rtl::OUString & rMediaType,const Reference<XInputStream> & xPostData,const Reference<XInteractionHandler> & xInteractionHandler,UcbLockBytesHandler * pHandler)1661 UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const ::rtl::OUString& rReferer, const ::rtl::OUString& rMediaType,
1662         const Reference < XInputStream >& xPostData, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler )
1663 {
1664 	if( !xContent.is() )
1665 		return NULL;;
1666 
1667     UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler );
1668     xLockBytes->SetSynchronMode( !pHandler );
1669     Reference< XActiveDataControl > xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes );
1670 
1671     PostCommandArgument2 aArgument;
1672 	aArgument.Source = xPostData;
1673     aArgument.Sink = xSink;
1674     aArgument.MediaType = rMediaType;
1675     aArgument.Referer = rReferer;
1676 
1677     Command aCommand;
1678     aCommand.Name = ::rtl::OUString::createFromAscii ("post");
1679     aCommand.Argument <<= aArgument;
1680 
1681     Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) );
1682 
1683 	sal_Bool bError = UCBOpenContentSync( xLockBytes,
1684 										  xContent,
1685 										  aCommand,
1686 										  xSink,
1687 										  xInteractionHandler,
1688 										  xProgressHdl,
1689 										  pHandler );
1690 
1691    	if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) )
1692 	{
1693 		DBG_ERROR("No InputStream, but no error set!" );
1694        	xLockBytes->SetError( ERRCODE_IO_GENERAL );
1695 	}
1696 
1697     return xLockBytes;
1698 }
1699 
CreateLockBytes(const Reference<XContent> & xContent,const Sequence<PropertyValue> & rProps,StreamMode eOpenMode,const Reference<XInteractionHandler> & xInteractionHandler,UcbLockBytesHandler * pHandler)1700 UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const Sequence < PropertyValue >& rProps,
1701         StreamMode eOpenMode, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler )
1702 {
1703 	if( !xContent.is() )
1704 		return NULL;;
1705 
1706     UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler );
1707     xLockBytes->SetSynchronMode( !pHandler );
1708     Reference< XActiveDataControl > xSink;
1709     if ( eOpenMode & STREAM_WRITE )
1710         xSink = (XActiveDataControl*) new UcbStreamer_Impl( xLockBytes );
1711     else
1712         xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes );
1713 
1714     if ( rProps.getLength() )
1715     {
1716         Reference < XCommandProcessor > xProcessor( xContent, UNO_QUERY );
1717         Command aCommand;
1718         aCommand.Name     = ::rtl::OUString::createFromAscii("setPropertyValues");
1719         aCommand.Handle   = -1; /* unknown */
1720         aCommand.Argument <<= rProps;
1721         xProcessor->execute( aCommand, 0, Reference < XCommandEnvironment >() );
1722     }
1723 
1724 	OpenCommandArgument2 aArgument;
1725     aArgument.Sink = xSink;
1726 	aArgument.Mode = OpenMode::DOCUMENT;
1727 
1728     Command aCommand;
1729 	aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("open") );
1730 	aCommand.Argument <<= aArgument;
1731 
1732     Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) );
1733 
1734     sal_Bool bError = UCBOpenContentSync( xLockBytes,
1735 										  xContent,
1736 										  aCommand,
1737 										  xSink,
1738 										  xInteractionHandler,
1739 										  xProgressHdl,
1740 										  pHandler );
1741 
1742     if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) )
1743 	{
1744 		DBG_ERROR("No InputStream, but no error set!" );
1745        	xLockBytes->SetError( ERRCODE_IO_GENERAL );
1746 	}
1747 
1748     return xLockBytes;
1749 }
1750 
1751 }
1752