Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <comphelper/docpasswordhelper.hxx>
21 : #include <unotools/mediadescriptor.hxx>
22 : #include <unotools/securityoptions.hxx>
23 : #include <comphelper/namedvaluecollection.hxx>
24 : #include <comphelper/stillreadwriteinteraction.hxx>
25 :
26 : #include <com/sun/star/ucb/XContent.hpp>
27 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
28 : #include <com/sun/star/task/XInteractionHandler.hpp>
29 : #include <com/sun/star/io/XStream.hpp>
30 : #include <com/sun/star/io/XActiveDataSink.hpp>
31 : #include <com/sun/star/io/XSeekable.hpp>
32 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 : #include <com/sun/star/lang/IllegalArgumentException.hpp>
34 : #include <com/sun/star/util/XURLTransformer.hpp>
35 : #include <com/sun/star/ucb/InteractiveIOException.hpp>
36 : #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
37 : #include <com/sun/star/ucb/CommandFailedException.hpp>
38 : #include <com/sun/star/task/XInteractionAbort.hpp>
39 : #include <com/sun/star/uri/UriReferenceFactory.hpp>
40 : #include <com/sun/star/uri/XUriReference.hpp>
41 : #include <com/sun/star/ucb/PostCommandArgument2.hpp>
42 : #include <com/sun/star/container/XNameAccess.hpp>
43 : #include <officecfg/Office/Common.hxx>
44 : #include <ucbhelper/interceptedinteraction.hxx>
45 : #include <ucbhelper/content.hxx>
46 : #include <ucbhelper/commandenvironment.hxx>
47 : #include <ucbhelper/activedatasink.hxx>
48 : #include <comphelper/processfactory.hxx>
49 :
50 : namespace utl {
51 :
52 : namespace {
53 :
54 0 : OUString removeFragment(OUString const & uri) {
55 : css::uno::Reference< css::uri::XUriReference > ref(
56 : css::uri::UriReferenceFactory::create(
57 0 : comphelper::getProcessComponentContext())->
58 0 : parse(uri));
59 0 : if (ref.is()) {
60 0 : ref->clearFragment();
61 0 : return ref->getUriReference();
62 : } else {
63 : SAL_WARN("unotools.misc", "cannot parse <" << uri << ">");
64 0 : return uri;
65 0 : }
66 : }
67 :
68 : }
69 :
70 0 : const OUString& MediaDescriptor::PROP_ABORTED()
71 : {
72 0 : static const OUString sProp("Aborted");
73 0 : return sProp;
74 : }
75 :
76 0 : const OUString& MediaDescriptor::PROP_ASTEMPLATE()
77 : {
78 0 : static const OUString sProp("AsTemplate");
79 0 : return sProp;
80 : }
81 :
82 0 : const OUString& MediaDescriptor::PROP_COMPONENTDATA()
83 : {
84 0 : static const OUString sProp("ComponentData");
85 0 : return sProp;
86 : }
87 :
88 0 : const OUString& MediaDescriptor::PROP_DOCUMENTSERVICE()
89 : {
90 0 : static const OUString sProp("DocumentService");
91 0 : return sProp;
92 : }
93 :
94 0 : const OUString& MediaDescriptor::PROP_ENCRYPTIONDATA()
95 : {
96 0 : static const OUString sProp("EncryptionData");
97 0 : return sProp;
98 : }
99 :
100 0 : const OUString& MediaDescriptor::PROP_FILENAME()
101 : {
102 0 : static const OUString sProp("FileName");
103 0 : return sProp;
104 : }
105 :
106 0 : const OUString& MediaDescriptor::PROP_FILTERNAME()
107 : {
108 0 : static const OUString sProp("FilterName");
109 0 : return sProp;
110 : }
111 :
112 0 : const OUString& MediaDescriptor::PROP_FILTERPROVIDER()
113 : {
114 0 : static const OUString aProp("FilterProvider");
115 0 : return aProp;
116 : }
117 :
118 0 : const OUString& MediaDescriptor::PROP_FILTEROPTIONS()
119 : {
120 0 : static const OUString sProp("FilterOptions");
121 0 : return sProp;
122 : }
123 :
124 0 : const OUString& MediaDescriptor::PROP_FRAME()
125 : {
126 0 : static const OUString sProp("Frame");
127 0 : return sProp;
128 : }
129 :
130 0 : const OUString& MediaDescriptor::PROP_FRAMENAME()
131 : {
132 0 : static const OUString sProp("FrameName");
133 0 : return sProp;
134 : }
135 :
136 0 : const OUString& MediaDescriptor::PROP_HIDDEN()
137 : {
138 0 : static const OUString sProp("Hidden");
139 0 : return sProp;
140 : }
141 :
142 0 : const OUString& MediaDescriptor::PROP_INPUTSTREAM()
143 : {
144 0 : static const OUString sProp("InputStream");
145 0 : return sProp;
146 : }
147 :
148 0 : const OUString& MediaDescriptor::PROP_INTERACTIONHANDLER()
149 : {
150 0 : static const OUString sProp("InteractionHandler");
151 0 : return sProp;
152 : }
153 :
154 0 : const OUString& MediaDescriptor::PROP_JUMPMARK()
155 : {
156 0 : static const OUString sProp("JumpMark");
157 0 : return sProp;
158 : }
159 :
160 0 : const OUString& MediaDescriptor::PROP_MACROEXECUTIONMODE()
161 : {
162 0 : static const OUString sProp("MacroExecutionMode");
163 0 : return sProp;
164 : }
165 :
166 0 : const OUString& MediaDescriptor::PROP_MEDIATYPE()
167 : {
168 0 : static const OUString sProp("MediaType");
169 0 : return sProp;
170 : }
171 :
172 0 : const OUString& MediaDescriptor::PROP_MINIMIZED()
173 : {
174 0 : static const OUString sProp("Minimized");
175 0 : return sProp;
176 : }
177 :
178 0 : const OUString& MediaDescriptor::PROP_NOAUTOSAVE()
179 : {
180 0 : static const OUString sProp("NoAutoSave");
181 0 : return sProp;
182 : }
183 :
184 0 : const OUString& MediaDescriptor::PROP_OPENNEWVIEW()
185 : {
186 0 : static const OUString sProp("OpenNewView");
187 0 : return sProp;
188 : }
189 :
190 0 : const OUString& MediaDescriptor::PROP_OUTPUTSTREAM()
191 : {
192 0 : static const OUString sProp("OutputStream");
193 0 : return sProp;
194 : }
195 :
196 0 : const OUString& MediaDescriptor::PROP_POSTDATA()
197 : {
198 0 : static const OUString sProp("PostData");
199 0 : return sProp;
200 : }
201 :
202 0 : const OUString& MediaDescriptor::PROP_PREVIEW()
203 : {
204 0 : static const OUString sProp("Preview");
205 0 : return sProp;
206 : }
207 :
208 0 : const OUString& MediaDescriptor::PROP_READONLY()
209 : {
210 0 : static const OUString sProp("ReadOnly");
211 0 : return sProp;
212 : }
213 :
214 0 : const OUString& MediaDescriptor::PROP_REFERRER()
215 : {
216 0 : static const OUString sProp("Referer");
217 0 : return sProp;
218 : }
219 :
220 0 : const OUString& MediaDescriptor::PROP_STATUSINDICATOR()
221 : {
222 0 : static const OUString sProp("StatusIndicator");
223 0 : return sProp;
224 : }
225 :
226 0 : const OUString& MediaDescriptor::PROP_STREAM()
227 : {
228 0 : static const OUString sProp("Stream");
229 0 : return sProp;
230 : }
231 :
232 0 : const OUString& MediaDescriptor::PROP_STREAMFOROUTPUT()
233 : {
234 0 : static const OUString sProp("StreamForOutput");
235 0 : return sProp;
236 : }
237 :
238 0 : const OUString& MediaDescriptor::PROP_TEMPLATENAME()
239 : {
240 0 : static const OUString sProp("TemplateName");
241 0 : return sProp;
242 : }
243 :
244 0 : const OUString& MediaDescriptor::PROP_TYPENAME()
245 : {
246 0 : static const OUString sProp("TypeName");
247 0 : return sProp;
248 : }
249 :
250 0 : const OUString& MediaDescriptor::PROP_UCBCONTENT()
251 : {
252 0 : static const OUString sProp("UCBContent");
253 0 : return sProp;
254 : }
255 :
256 0 : const OUString& MediaDescriptor::PROP_UPDATEDOCMODE()
257 : {
258 0 : static const OUString sProp("UpdateDocMode");
259 0 : return sProp;
260 : }
261 :
262 0 : const OUString& MediaDescriptor::PROP_URL()
263 : {
264 0 : static const OUString sProp("URL");
265 0 : return sProp;
266 : }
267 :
268 0 : const OUString& MediaDescriptor::PROP_VERSION()
269 : {
270 0 : static const OUString sProp("Version");
271 0 : return sProp;
272 : }
273 :
274 0 : const OUString& MediaDescriptor::PROP_DOCUMENTTITLE()
275 : {
276 0 : static const OUString sProp("DocumentTitle");
277 0 : return sProp;
278 : }
279 :
280 0 : const OUString& MediaDescriptor::PROP_MODEL()
281 : {
282 0 : static const OUString sProp("Model");
283 0 : return sProp;
284 : }
285 :
286 0 : const OUString& MediaDescriptor::PROP_PASSWORD()
287 : {
288 0 : static const OUString sProp("Password");
289 0 : return sProp;
290 : }
291 :
292 0 : const OUString& MediaDescriptor::PROP_TITLE()
293 : {
294 0 : static const OUString sProp("Title");
295 0 : return sProp;
296 : }
297 :
298 0 : const OUString& MediaDescriptor::PROP_SALVAGEDFILE()
299 : {
300 0 : static const OUString sProp("SalvagedFile");
301 0 : return sProp;
302 : }
303 :
304 0 : const OUString& MediaDescriptor::PROP_VIEWONLY()
305 : {
306 0 : static const OUString sProp("ViewOnly");
307 0 : return sProp;
308 : }
309 :
310 0 : const OUString& MediaDescriptor::PROP_DOCUMENTBASEURL()
311 : {
312 0 : static const OUString sProp("DocumentBaseURL");
313 0 : return sProp;
314 : }
315 :
316 0 : MediaDescriptor::MediaDescriptor()
317 0 : : SequenceAsHashMap()
318 : {
319 0 : }
320 :
321 0 : MediaDescriptor::MediaDescriptor(const css::uno::Sequence< css::beans::PropertyValue >& lSource)
322 0 : : SequenceAsHashMap(lSource)
323 : {
324 0 : }
325 :
326 0 : bool MediaDescriptor::isStreamReadOnly() const
327 : {
328 0 : static OUString CONTENTSCHEME_FILE( "file" );
329 0 : static OUString CONTENTPROP_ISREADONLY( "IsReadOnly" );
330 : static bool READONLY_FALLBACK = false;
331 :
332 0 : bool bReadOnly = READONLY_FALLBACK;
333 :
334 : // check for explicit readonly state
335 0 : const_iterator pIt = find(MediaDescriptor::PROP_READONLY());
336 0 : if (pIt != end())
337 : {
338 0 : pIt->second >>= bReadOnly;
339 0 : return bReadOnly;
340 : }
341 :
342 : // streams based on post data are readonly by definition
343 0 : pIt = find(MediaDescriptor::PROP_POSTDATA());
344 0 : if (pIt != end())
345 0 : return true;
346 :
347 : // A XStream capsulate XInputStream and XOutputStream ...
348 : // If it exists - the file must be open in read/write mode!
349 0 : pIt = find(MediaDescriptor::PROP_STREAM());
350 0 : if (pIt != end())
351 0 : return false;
352 :
353 : // Only file system content provider is able to provide XStream
354 : // so for this content impossibility to create XStream triggers
355 : // switch to readonly mode.
356 : try
357 : {
358 0 : css::uno::Reference< css::ucb::XContent > xContent = getUnpackedValueOrDefault(MediaDescriptor::PROP_UCBCONTENT(), css::uno::Reference< css::ucb::XContent >());
359 0 : if (xContent.is())
360 : {
361 0 : css::uno::Reference< css::ucb::XContentIdentifier > xId(xContent->getIdentifier(), css::uno::UNO_QUERY);
362 0 : OUString aScheme;
363 0 : if (xId.is())
364 0 : aScheme = xId->getContentProviderScheme();
365 :
366 0 : if (aScheme.equalsIgnoreAsciiCase(CONTENTSCHEME_FILE))
367 0 : bReadOnly = true;
368 : else
369 : {
370 0 : ::ucbhelper::Content aContent(xContent, css::uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext());
371 0 : aContent.getPropertyValue(CONTENTPROP_ISREADONLY) >>= bReadOnly;
372 0 : }
373 0 : }
374 : }
375 0 : catch(const css::uno::RuntimeException& )
376 0 : { throw; }
377 0 : catch(const css::uno::Exception&)
378 : {}
379 :
380 0 : return bReadOnly;
381 : }
382 :
383 0 : css::uno::Any MediaDescriptor::getComponentDataEntry( const OUString& rName ) const
384 : {
385 0 : comphelper::SequenceAsHashMap::const_iterator aPropertyIter = find( PROP_COMPONENTDATA() );
386 0 : if( aPropertyIter != end() )
387 0 : return comphelper::NamedValueCollection( aPropertyIter->second ).get( rName );
388 0 : return css::uno::Any();
389 : }
390 :
391 0 : void MediaDescriptor::setComponentDataEntry( const OUString& rName, const css::uno::Any& rValue )
392 : {
393 0 : if( rValue.hasValue() )
394 : {
395 : // get or create the 'ComponentData' property entry
396 0 : css::uno::Any& rCompDataAny = operator[]( PROP_COMPONENTDATA() );
397 : // insert the value (retain sequence type, create NamedValue elements by default)
398 0 : bool bHasNamedValues = !rCompDataAny.hasValue() || rCompDataAny.has< css::uno::Sequence< css::beans::NamedValue > >();
399 0 : bool bHasPropValues = rCompDataAny.has< css::uno::Sequence< css::beans::PropertyValue > >();
400 : OSL_ENSURE( bHasNamedValues || bHasPropValues, "MediaDescriptor::setComponentDataEntry - incompatible 'ComponentData' property in media descriptor" );
401 0 : if( bHasNamedValues || bHasPropValues )
402 : {
403 : // insert or overwrite the passed value
404 0 : comphelper::SequenceAsHashMap aCompDataMap( rCompDataAny );
405 0 : aCompDataMap[ rName ] = rValue;
406 : // write back the sequence (restore sequence with correct element type)
407 0 : rCompDataAny = aCompDataMap.getAsConstAny( bHasPropValues );
408 : }
409 : }
410 : else
411 : {
412 : // if an empty Any is passed, clear the entry
413 0 : clearComponentDataEntry( rName );
414 : }
415 0 : }
416 :
417 0 : void MediaDescriptor::clearComponentDataEntry( const OUString& rName )
418 : {
419 0 : comphelper::SequenceAsHashMap::iterator aPropertyIter = find( PROP_COMPONENTDATA() );
420 0 : if( aPropertyIter != end() )
421 : {
422 0 : css::uno::Any& rCompDataAny = aPropertyIter->second;
423 0 : bool bHasNamedValues = rCompDataAny.has< css::uno::Sequence< css::beans::NamedValue > >();
424 0 : bool bHasPropValues = rCompDataAny.has< css::uno::Sequence< css::beans::PropertyValue > >();
425 : OSL_ENSURE( bHasNamedValues || bHasPropValues, "MediaDescriptor::clearComponentDataEntry - incompatible 'ComponentData' property in media descriptor" );
426 0 : if( bHasNamedValues || bHasPropValues )
427 : {
428 : // remove the value with the passed name
429 0 : comphelper::SequenceAsHashMap aCompDataMap( rCompDataAny );
430 0 : aCompDataMap.erase( rName );
431 : // write back the sequence, or remove it completely if it is empty
432 0 : if( aCompDataMap.empty() )
433 0 : erase( aPropertyIter );
434 : else
435 0 : rCompDataAny = aCompDataMap.getAsConstAny( bHasPropValues );
436 : }
437 : }
438 0 : }
439 :
440 0 : ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > MediaDescriptor::requestAndVerifyDocPassword(
441 : comphelper::IDocPasswordVerifier& rVerifier,
442 : comphelper::DocPasswordRequestType eRequestType,
443 : const ::std::vector< OUString >* pDefaultPasswords )
444 : {
445 : css::uno::Sequence< css::beans::NamedValue > aMediaEncData = getUnpackedValueOrDefault(
446 0 : PROP_ENCRYPTIONDATA(), css::uno::Sequence< css::beans::NamedValue >() );
447 : OUString aMediaPassword = getUnpackedValueOrDefault(
448 0 : PROP_PASSWORD(), OUString() );
449 : css::uno::Reference< css::task::XInteractionHandler > xInteractHandler = getUnpackedValueOrDefault(
450 0 : PROP_INTERACTIONHANDLER(), css::uno::Reference< css::task::XInteractionHandler >() );
451 : OUString aDocumentName = getUnpackedValueOrDefault(
452 0 : PROP_URL(), OUString() );
453 :
454 0 : bool bIsDefaultPassword = false;
455 : css::uno::Sequence< css::beans::NamedValue > aEncryptionData = comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
456 0 : rVerifier, aMediaEncData, aMediaPassword, xInteractHandler, aDocumentName, eRequestType, pDefaultPasswords, &bIsDefaultPassword );
457 :
458 0 : erase( PROP_PASSWORD() );
459 0 : erase( PROP_ENCRYPTIONDATA() );
460 :
461 : // insert valid password into media descriptor (but not a default password)
462 0 : if( (aEncryptionData.getLength() > 0) && !bIsDefaultPassword )
463 0 : (*this)[ PROP_ENCRYPTIONDATA() ] <<= aEncryptionData;
464 :
465 0 : return aEncryptionData;
466 : }
467 :
468 0 : bool MediaDescriptor::addInputStream()
469 : {
470 0 : return impl_addInputStream( true );
471 : }
472 :
473 : /*-----------------------------------------------*/
474 0 : bool MediaDescriptor::addInputStreamOwnLock()
475 : {
476 : return impl_addInputStream(
477 0 : officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::get());
478 : }
479 :
480 : /*-----------------------------------------------*/
481 0 : bool MediaDescriptor::impl_addInputStream( bool bLockFile )
482 : {
483 : // check for an already existing stream item first
484 0 : const_iterator pIt = find(MediaDescriptor::PROP_INPUTSTREAM());
485 0 : if (pIt != end())
486 0 : return true;
487 :
488 : try
489 : {
490 : // No stream available - create a new one
491 : // a) data comes as PostData ...
492 0 : pIt = find(MediaDescriptor::PROP_POSTDATA());
493 0 : if (pIt != end())
494 : {
495 0 : const css::uno::Any& rPostData = pIt->second;
496 0 : css::uno::Reference< css::io::XInputStream > xPostData;
497 0 : rPostData >>= xPostData;
498 :
499 0 : return impl_openStreamWithPostData( xPostData );
500 : }
501 :
502 : // b) ... or we must get it from the given URL
503 0 : OUString sURL = getUnpackedValueOrDefault(MediaDescriptor::PROP_URL(), OUString());
504 0 : if (sURL.isEmpty())
505 : throw css::uno::Exception("Found no URL.",
506 0 : css::uno::Reference< css::uno::XInterface >());
507 :
508 0 : return impl_openStreamWithURL( removeFragment(sURL), bLockFile );
509 : }
510 0 : catch(const css::uno::Exception& ex)
511 : {
512 : SAL_WARN(
513 : "unotools.misc",
514 : "invalid MediaDescriptor detected: " << ex.Message);
515 0 : return false;
516 : }
517 : }
518 :
519 0 : bool MediaDescriptor::impl_openStreamWithPostData( const css::uno::Reference< css::io::XInputStream >& _rxPostData )
520 : throw(::com::sun::star::uno::RuntimeException)
521 : {
522 0 : if ( !_rxPostData.is() )
523 : throw css::lang::IllegalArgumentException("Found invalid PostData.",
524 0 : css::uno::Reference< css::uno::XInterface >(), 1);
525 :
526 : // PostData can't be used in read/write mode!
527 0 : (*this)[MediaDescriptor::PROP_READONLY()] <<= sal_True;
528 :
529 : // prepare the environment
530 : css::uno::Reference< css::task::XInteractionHandler > xInteraction = getUnpackedValueOrDefault(
531 0 : MediaDescriptor::PROP_INTERACTIONHANDLER(),
532 0 : css::uno::Reference< css::task::XInteractionHandler >());
533 0 : css::uno::Reference< css::ucb::XProgressHandler > xProgress;
534 0 : ::ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress);
535 0 : css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv(static_cast< css::ucb::XCommandEnvironment* >(pCommandEnv), css::uno::UNO_QUERY);
536 :
537 : // media type
538 0 : OUString sMediaType = getUnpackedValueOrDefault(MediaDescriptor::PROP_MEDIATYPE(), OUString());
539 0 : if (sMediaType.isEmpty())
540 : {
541 0 : sMediaType = "application/x-www-form-urlencoded";
542 0 : (*this)[MediaDescriptor::PROP_MEDIATYPE()] <<= sMediaType;
543 : }
544 :
545 : // url
546 0 : OUString sURL( getUnpackedValueOrDefault( PROP_URL(), OUString() ) );
547 :
548 0 : css::uno::Reference< css::io::XInputStream > xResultStream;
549 : try
550 : {
551 : // seek PostData stream to the beginning
552 0 : css::uno::Reference< css::io::XSeekable > xSeek( _rxPostData, css::uno::UNO_QUERY );
553 0 : if ( xSeek.is() )
554 0 : xSeek->seek( 0 );
555 :
556 : // a content for the URL
557 0 : ::ucbhelper::Content aContent( sURL, xCommandEnv, comphelper::getProcessComponentContext() );
558 :
559 : // use post command
560 0 : css::ucb::PostCommandArgument2 aPostArgument;
561 0 : aPostArgument.Source = _rxPostData;
562 0 : css::uno::Reference< css::io::XActiveDataSink > xSink( new ucbhelper::ActiveDataSink );
563 0 : aPostArgument.Sink = xSink;
564 0 : aPostArgument.MediaType = sMediaType;
565 0 : aPostArgument.Referer = getUnpackedValueOrDefault( PROP_REFERRER(), OUString() );
566 :
567 0 : OUString sCommandName( "post" );
568 0 : aContent.executeCommand( sCommandName, css::uno::makeAny( aPostArgument ) );
569 :
570 : // get result
571 0 : xResultStream = xSink->getInputStream();
572 : }
573 0 : catch( const css::uno::Exception& )
574 : {
575 : }
576 :
577 : // success?
578 0 : if ( !xResultStream.is() )
579 : {
580 : OSL_FAIL( "no valid reply to the HTTP-Post" );
581 0 : return false;
582 : }
583 :
584 0 : (*this)[MediaDescriptor::PROP_INPUTSTREAM()] <<= xResultStream;
585 0 : return true;
586 : }
587 :
588 : /*-----------------------------------------------*/
589 0 : bool MediaDescriptor::impl_openStreamWithURL( const OUString& sURL, bool bLockFile )
590 : throw(::com::sun::star::uno::RuntimeException)
591 : {
592 0 : OUString referer(getUnpackedValueOrDefault(PROP_REFERRER(), OUString()));
593 0 : if (SvtSecurityOptions().isUntrustedReferer(referer)) {
594 0 : return false;
595 : }
596 :
597 : // prepare the environment
598 : css::uno::Reference< css::task::XInteractionHandler > xOrgInteraction = getUnpackedValueOrDefault(
599 0 : MediaDescriptor::PROP_INTERACTIONHANDLER(),
600 0 : css::uno::Reference< css::task::XInteractionHandler >());
601 :
602 0 : comphelper::StillReadWriteInteraction* pInteraction = new comphelper::StillReadWriteInteraction(xOrgInteraction);
603 0 : css::uno::Reference< css::task::XInteractionHandler > xInteraction(static_cast< css::task::XInteractionHandler* >(pInteraction), css::uno::UNO_QUERY);
604 :
605 0 : css::uno::Reference< css::ucb::XProgressHandler > xProgress;
606 0 : ::ucbhelper::CommandEnvironment* pCommandEnv = new ::ucbhelper::CommandEnvironment(xInteraction, xProgress);
607 0 : css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv(static_cast< css::ucb::XCommandEnvironment* >(pCommandEnv), css::uno::UNO_QUERY);
608 :
609 : // try to create the content
610 : // no content -> no stream => return immediately with FALSE
611 0 : ::ucbhelper::Content aContent;
612 0 : css::uno::Reference< css::ucb::XContent > xContent;
613 : try
614 : {
615 0 : aContent = ::ucbhelper::Content(sURL, xCommandEnv, comphelper::getProcessComponentContext());
616 0 : xContent = aContent.get();
617 : }
618 0 : catch(const css::uno::RuntimeException&)
619 0 : { throw; }
620 0 : catch(const css::ucb::ContentCreationException& e)
621 : {
622 : SAL_WARN(
623 : "unotools.misc",
624 : "caught ContentCreationException \"" << e.Message
625 : << "\" while opening <" << sURL << ">");
626 0 : return false; // TODO error handling
627 : }
628 0 : catch(const css::uno::Exception& e)
629 : {
630 : SAL_WARN(
631 : "unotools.misc",
632 : "caught Exception \"" << e.Message << "\" while opening <"
633 : << sURL << ">");
634 0 : return false; // TODO error handling
635 : }
636 :
637 : // try to open the file in read/write mode
638 : // (if its allowed to do so).
639 : // But handle errors in a "hidden mode". Because
640 : // we try it readonly later - if read/write isnt an option.
641 0 : css::uno::Reference< css::io::XStream > xStream;
642 0 : css::uno::Reference< css::io::XInputStream > xInputStream;
643 :
644 0 : bool bReadOnly = false;
645 0 : bool bModeRequestedExplicitly = false;
646 0 : const_iterator pIt = find(MediaDescriptor::PROP_READONLY());
647 0 : if (pIt != end())
648 : {
649 0 : pIt->second >>= bReadOnly;
650 0 : bModeRequestedExplicitly = true;
651 : }
652 :
653 0 : if ( !bReadOnly && bLockFile )
654 : {
655 : try
656 : {
657 : // TODO: use "special" still interaction to supress error messages
658 0 : xStream = aContent.openWriteableStream();
659 0 : if (xStream.is())
660 0 : xInputStream = xStream->getInputStream();
661 : }
662 0 : catch(const css::uno::RuntimeException&)
663 0 : { throw; }
664 0 : catch(const css::uno::Exception& e)
665 : {
666 : // ignore exception, if reason was problem reasoned on
667 : // open it in WRITEABLE mode! Then we try it READONLY
668 : // later a second time.
669 : // All other errors must be handled as real error an
670 : // break this method.
671 0 : if (!pInteraction->wasWriteError() || bModeRequestedExplicitly)
672 : {
673 : SAL_WARN(
674 : "unotools.misc",
675 : "caught Exception \"" << e.Message
676 : << "\" while opening <" << sURL << ">");
677 0 : return false;
678 : }
679 0 : xStream.clear();
680 0 : xInputStream.clear();
681 0 : }
682 : }
683 :
684 : // If opening of the stream in read/write mode wasnt allowed
685 : // or failed by an error - we must try it in readonly mode.
686 0 : if (!xInputStream.is())
687 : {
688 0 : OUString aScheme;
689 :
690 : try
691 : {
692 : css::uno::Reference< css::ucb::XContentIdentifier > xContId(
693 0 : aContent.get().is() ? aContent.get()->getIdentifier() : 0 );
694 :
695 0 : if ( xContId.is() )
696 0 : aScheme = xContId->getContentProviderScheme();
697 :
698 : // Only file system content provider is able to provide XStream
699 : // so for this content impossibility to create XStream triggers
700 : // switch to readonly mode in case of opening with locking on
701 0 : if( bLockFile && aScheme.equalsIgnoreAsciiCase("file") )
702 0 : bReadOnly = true;
703 : else
704 : {
705 0 : bool bRequestReadOnly = bReadOnly;
706 0 : aContent.getPropertyValue("IsReadOnly") >>= bReadOnly;
707 0 : if ( bReadOnly && !bRequestReadOnly && bModeRequestedExplicitly )
708 0 : return false; // the document is explicitly requested with WRITEABLE mode
709 0 : }
710 : }
711 0 : catch(const css::uno::RuntimeException&)
712 0 : { throw; }
713 0 : catch(const css::uno::Exception&)
714 : { /* no error handling if IsReadOnly property does not exist for UCP */ }
715 :
716 0 : if ( bReadOnly )
717 0 : (*this)[MediaDescriptor::PROP_READONLY()] <<= bReadOnly;
718 :
719 0 : pInteraction->resetInterceptions();
720 0 : pInteraction->resetErrorStates();
721 : try
722 : {
723 : // all the contents except file-URLs should be opened as usual
724 0 : if ( bLockFile || !aScheme.equalsIgnoreAsciiCase("file") )
725 0 : xInputStream = aContent.openStream();
726 : else
727 0 : xInputStream = aContent.openStreamNoLock();
728 : }
729 0 : catch(const css::uno::RuntimeException&)
730 0 : { throw; }
731 0 : catch(const css::uno::Exception& e)
732 : {
733 : SAL_WARN(
734 : "unotools.misc",
735 : "caught Exception \"" << e.Message << "\" while opening <"
736 : << sURL << ">");
737 0 : return false;
738 0 : }
739 : }
740 :
741 : // add streams to the descriptor
742 0 : if (xContent.is())
743 0 : (*this)[MediaDescriptor::PROP_UCBCONTENT()] <<= xContent;
744 0 : if (xStream.is())
745 0 : (*this)[MediaDescriptor::PROP_STREAM()] <<= xStream;
746 0 : if (xInputStream.is())
747 0 : (*this)[MediaDescriptor::PROP_INPUTSTREAM()] <<= xInputStream;
748 :
749 : // At least we need an input stream. The r/w stream is optional ...
750 0 : return xInputStream.is();
751 : }
752 :
753 : } // namespace comphelper
754 :
755 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|