LibreOffice Module sfx2 (master) 1
docfile.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <config_features.h>
21
22#ifdef UNX
23#include <sys/stat.h>
24#endif
25
26#include <sfx2/docfile.hxx>
28
29#include <com/sun/star/task/InteractionHandler.hpp>
30#include <com/sun/star/task/XStatusIndicator.hpp>
31#include <com/sun/star/uno/Reference.h>
32#include <com/sun/star/ucb/XContent.hpp>
33#include <com/sun/star/container/XChild.hpp>
34#include <com/sun/star/document/XDocumentRevisionListPersistence.hpp>
35#include <com/sun/star/document/LockedDocumentRequest.hpp>
36#include <com/sun/star/document/LockedOnSavingRequest.hpp>
37#include <com/sun/star/document/OwnLockOnDocumentRequest.hpp>
38#include <com/sun/star/document/LockFileIgnoreRequest.hpp>
39#include <com/sun/star/document/LockFileCorruptRequest.hpp>
40#include <com/sun/star/document/ChangedByOthersRequest.hpp>
41#include <com/sun/star/document/ReloadEditableRequest.hpp>
42#include <com/sun/star/embed/XTransactedObject.hpp>
43#include <com/sun/star/embed/ElementModes.hpp>
44#include <com/sun/star/embed/UseBackupException.hpp>
45#include <com/sun/star/embed/XOptimizedStorage.hpp>
46#include <com/sun/star/frame/Desktop.hpp>
47#include <com/sun/star/frame/XModel.hpp>
48#include <com/sun/star/frame/XTerminateListener.hpp>
49#include <com/sun/star/graphic/XGraphic.hpp>
50#include <com/sun/star/ucb/ContentCreationException.hpp>
51#include <com/sun/star/ucb/InteractiveIOException.hpp>
52#include <com/sun/star/ucb/CommandFailedException.hpp>
53#include <com/sun/star/ucb/CommandAbortedException.hpp>
54#include <com/sun/star/ucb/InteractiveLockingLockedException.hpp>
55#include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
56#include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
57#include <com/sun/star/ucb/Lock.hpp>
58#include <com/sun/star/ucb/NameClashException.hpp>
59#include <com/sun/star/ucb/XCommandEnvironment.hpp>
60#include <com/sun/star/ucb/XProgressHandler.hpp>
61#include <com/sun/star/io/XOutputStream.hpp>
62#include <com/sun/star/io/XInputStream.hpp>
63#include <com/sun/star/io/XTruncate.hpp>
64#include <com/sun/star/io/XSeekable.hpp>
65#include <com/sun/star/lang/XSingleServiceFactory.hpp>
66#include <com/sun/star/ucb/InsertCommandArgument.hpp>
67#include <com/sun/star/ucb/NameClash.hpp>
68#include <com/sun/star/beans/NamedValue.hpp>
69#include <com/sun/star/beans/PropertyValue.hpp>
70#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
71#include <com/sun/star/security/XCertificate.hpp>
72#include <tools/urlobj.hxx>
73#include <tools/fileutil.hxx>
75#include <unotools/tempfile.hxx>
82#include <comphelper/string.hxx>
84#include <utility>
85#include <svl/stritem.hxx>
86#include <svl/eitem.hxx>
87#include <svtools/sfxecode.hxx>
88#include <svl/itemset.hxx>
89#include <svl/intitem.hxx>
90#include <svtools/svparser.hxx>
91#include <sal/log.hxx>
92
94
95#include <osl/file.hxx>
96
100#include <tools/datetime.hxx>
102#include <svtools/asynclink.hxx>
105#include <unotools/ucbhelper.hxx>
107#include <ucbhelper/content.hxx>
109#include <sot/storage.hxx>
112#include <com/sun/star/document/DocumentRevisionListPersistence.hpp>
113
114#include <sfx2/app.hxx>
115#include <sfx2/frame.hxx>
116#include <sfx2/dispatch.hxx>
117#include <sfx2/fcontnr.hxx>
118#include <sfx2/docfilt.hxx>
119#include <sfx2/sfxsids.hrc>
120#include <sfx2/sfxuno.hxx>
121#include <openflag.hxx>
122#include <officecfg/Office/Common.hxx>
124#include <vcl/weld.hxx>
125#include <vcl/svapp.hxx>
127#include <unotools/fltrcfg.hxx>
129#include <sfx2/viewfrm.hxx>
131#include <o3tl/string_view.hxx>
132#include <condition_variable>
133
134#include <com/sun/star/io/WrongFormatException.hpp>
135
136#include <memory>
137
138using namespace ::com::sun::star;
139using namespace ::com::sun::star::graphic;
140using namespace ::com::sun::star::uno;
141using namespace ::com::sun::star::ucb;
142using namespace ::com::sun::star::beans;
143using namespace ::com::sun::star::io;
144using namespace ::com::sun::star::security;
145
146namespace
147{
148
149struct ReadOnlyMediumEntry
150{
151 ReadOnlyMediumEntry(std::shared_ptr<std::recursive_mutex> pMutex,
152 std::shared_ptr<bool> pIsDestructed)
153 : _pMutex(std::move(pMutex))
154 , _pIsDestructed(std::move(pIsDestructed))
155 {
156 }
157 std::shared_ptr<std::recursive_mutex> _pMutex;
158 std::shared_ptr<bool> _pIsDestructed;
159};
160
161}
162
163static std::mutex g_chkReadOnlyGlobalMutex;
164static bool g_bChkReadOnlyTaskRunning = false;
165static std::unordered_map<SfxMedium*, std::shared_ptr<ReadOnlyMediumEntry>> g_newReadOnlyDocs;
166static std::unordered_map<SfxMedium*, std::shared_ptr<ReadOnlyMediumEntry>> g_existingReadOnlyDocs;
167
168namespace {
169
170#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
171
172bool IsSystemFileLockingUsed()
173{
174#if HAVE_FEATURE_MACOSX_SANDBOX
175 return true;
176#else
177 return officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::get();
178#endif
179}
180
181
182bool IsOOoLockFileUsed()
183{
184#if HAVE_FEATURE_MACOSX_SANDBOX
185 return false;
186#else
187 return officecfg::Office::Common::Misc::UseDocumentOOoLockFile::get();
188#endif
189}
190
191bool IsLockingUsed()
192{
193 return officecfg::Office::Common::Misc::UseLocking::get();
194}
195
196#endif
197
198#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
199bool IsWebDAVLockingUsed()
200{
201 return officecfg::Office::Common::Misc::UseWebDAVFileLocking::get();
202}
203#endif
204
206sal_uInt64 GetDefaultFileAttributes(const OUString& rURL)
207{
208 sal_uInt64 nRet = 0;
209
210 if (!comphelper::isFileUrl(rURL))
211 return nRet;
212
213 // Make sure the file exists (and create it if not).
214 osl::File aFile(rURL);
215 osl::File::RC nRes = aFile.open(osl_File_OpenFlag_Create);
216 if (nRes != osl::File::E_None && nRes != osl::File::E_EXIST)
217 return nRet;
218
219 aFile.close();
220
221 osl::DirectoryItem aItem;
222 if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
223 return nRet;
224
225 osl::FileStatus aStatus(osl_FileStatus_Mask_Attributes);
226 if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
227 return nRet;
228
229 nRet = aStatus.getAttributes();
230 return nRet;
231}
232
234bool IsFileMovable(const INetURLObject& rURL)
235{
236#ifdef MACOSX
237 (void)rURL;
238 // Hide extension macOS-specific file property would be lost.
239 return false;
240#else
241
242 if (rURL.GetProtocol() != INetProtocol::File)
243 // Not a file:// URL.
244 return false;
245
246#ifdef UNX
247 OUString sPath = rURL.getFSysPath(FSysStyle::Unix);
248 if (sPath.isEmpty())
249 return false;
250
251 struct stat buf;
252 if (lstat(sPath.toUtf8().getStr(), &buf) != 0)
253 return false;
254
255 // Hardlink or symlink: osl::File::move() doesn't play with these nicely.
256 if (buf.st_nlink > 1 || S_ISLNK(buf.st_mode))
257 return false;
258#elif defined _WIN32
260 return false;
261#endif
262
263 return true;
264#endif
265}
266
267class CheckReadOnlyTaskTerminateListener
268 : public ::cppu::WeakImplHelper<css::frame::XTerminateListener>
269{
270public:
271 // XEventListener
272 void SAL_CALL disposing(const css::lang::EventObject& Source) override;
273
274 // XTerminateListener
275 void SAL_CALL queryTermination(const css::lang::EventObject& aEvent) override;
276 void SAL_CALL notifyTermination(const css::lang::EventObject& aEvent) override;
277
278 bool bIsTerminated = false;
279 std::condition_variable mCond;
280 std::mutex mMutex;
281};
282
283class CheckReadOnlyTask : public comphelper::ThreadTask
284{
285public:
286 CheckReadOnlyTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag);
287 ~CheckReadOnlyTask();
288
289 virtual void doWork() override;
290
291private:
293};
294
295} // anonymous namespace
296
297CheckReadOnlyTask::CheckReadOnlyTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag)
298 : ThreadTask(pTag)
299 , m_xListener(new CheckReadOnlyTaskTerminateListener)
300{
301 Reference<css::frame::XDesktop> xDesktop
302 = css::frame::Desktop::create(comphelper::getProcessComponentContext());
303 if (xDesktop.is() && m_xListener != nullptr)
304 {
305 xDesktop->addTerminateListener(m_xListener);
306 }
307}
308
309CheckReadOnlyTask::~CheckReadOnlyTask()
310{
311 Reference<css::frame::XDesktop> xDesktop
312 = css::frame::Desktop::create(comphelper::getProcessComponentContext());
313 if (xDesktop.is() && m_xListener != nullptr)
314 {
315 std::unique_lock<std::mutex> lock(m_xListener->mMutex);
316 if (!m_xListener->bIsTerminated)
317 {
318 lock.unlock();
319 xDesktop->removeTerminateListener(m_xListener);
320 }
321 }
322}
323
324namespace
325{
326void SAL_CALL
327CheckReadOnlyTaskTerminateListener::disposing(const css::lang::EventObject& /*Source*/)
328{
329}
330
331void SAL_CALL
332CheckReadOnlyTaskTerminateListener::queryTermination(const css::lang::EventObject& /*aEvent*/)
333{
334}
335
336void SAL_CALL
337CheckReadOnlyTaskTerminateListener::notifyTermination(const css::lang::EventObject& /*aEvent*/)
338{
339 std::unique_lock<std::mutex> lock(mMutex);
340 bIsTerminated = true;
341 lock.unlock();
342 mCond.notify_one();
343}
344}
345
347{
348public:
352
355 bool bIsTemp:1;
364 bool m_bLocked:1;
372 bool m_bRemote:1;
375 bool m_bDisableFileSync = false;
377
378 OUString m_aName;
379 OUString m_aLogicName;
380 OUString m_aLongName;
381
382 mutable std::shared_ptr<SfxItemSet> m_pSet;
383 mutable std::unique_ptr<INetURLObject> m_pURLObj;
384
385 std::shared_ptr<const SfxFilter> m_pFilter;
386 std::shared_ptr<const SfxFilter> m_pCustomFilter;
387
388 std::shared_ptr<std::recursive_mutex> m_pCheckEditableWorkerMutex;
389 std::shared_ptr<bool> m_pIsDestructed;
391
392 std::unique_ptr<SvStream> m_pInStream;
393 std::unique_ptr<SvStream> m_pOutStream;
394
395 OUString aOrigURL;
399
400 svtools::AsynchronLink aDoneLink;
401
402 uno::Sequence < util::RevisionTag > aVersions;
403
404 std::unique_ptr<::utl::TempFileNamed> pTempFile;
405
406 uno::Reference<embed::XStorage> xStorage;
407 uno::Reference<embed::XStorage> m_xZipStorage;
408 uno::Reference<io::XInputStream> m_xInputStreamToLoadFrom;
409 uno::Reference<io::XInputStream> xInputStream;
410 uno::Reference<io::XStream> xStream;
411 uno::Reference<io::XStream> m_xLockingStream;
412 uno::Reference<task::XInteractionHandler> xInteraction;
413
415
416 OUString m_aBackupURL;
417
418 // the following member is changed and makes sense only during saving
419 // TODO/LATER: in future the signature state should be controlled by the medium not by the document
420 // in this case the member will hold this information
422
424
425 util::DateTime m_aDateTime;
426
427 uno::Sequence<beans::PropertyValue> m_aArgs;
428
429 explicit SfxMedium_Impl();
433
434 OUString getFilterMimeType() const
435 { return !m_pFilter ? OUString() : m_pFilter->GetMimeType(); }
436};
437
439 m_nStorOpenMode(SFX_STREAM_READWRITE),
440 m_eError(ERRCODE_NONE),
441 m_eWarningError(ERRCODE_NONE),
442 bUpdatePickList(true),
443 bIsTemp( false ),
444 bDownloadDone( true ),
445 bIsStorage( false ),
446 bUseInteractionHandler( true ),
447 bAllowDefaultIntHdl( false ),
448 bDisposeStorage( false ),
449 bStorageBasedOnInStream( false ),
450 m_bSalvageMode( false ),
451 m_bVersionsAlreadyLoaded( false ),
452 m_bLocked( false ),
453 m_bMSOLockFileCreated( false ),
454 m_bDisableUnlockWebDAV( false ),
455 m_bGotDateTime( false ),
456 m_bRemoveBackup( false ),
457 m_bOriginallyReadOnly(false),
458 m_bOriginallyLoadedReadOnly(false),
459 m_bTriedStorage(false),
460 m_bRemote(false),
461 m_bInputStreamIsReadOnly(false),
462 m_bInCheckIn(false),
463 m_pReloadEvent(nullptr),
464 aExpireTime( DateTime( DateTime::SYSTEM ) + static_cast<sal_Int32>(10) ),
465 nLastStorageError( ERRCODE_NONE ),
466 m_nSignatureState( SignatureState::NOSIGNATURES )
467{
468}
469
470
472{
473 aDoneLink.ClearPendingCall();
474
475 pTempFile.reset();
476 m_pSet.reset();
477 std::unique_lock<std::recursive_mutex> chkEditLock;
478 if (m_pCheckEditableWorkerMutex != nullptr)
479 chkEditLock = std::unique_lock<std::recursive_mutex>(*m_pCheckEditableWorkerMutex);
480 m_pURLObj.reset();
481}
482
484{
485 pImpl->m_eError = ERRCODE_NONE;
486 if( pImpl->m_pInStream )
487 pImpl->m_pInStream->ResetError();
488 if( pImpl->m_pOutStream )
489 pImpl->m_pOutStream->ResetError();
490}
491
493{
494 return pImpl->m_eWarningError;
495}
496
498{
499 return pImpl->nLastStorageError;
500}
501
503{
504 pImpl->m_eError = nError;
505}
506
508{
509 pImpl->m_eWarningError = nWarningError;
510}
511
513{
514 ErrCode lError = pImpl->m_eError;
515 if(!lError && pImpl->m_pInStream)
516 lError = pImpl->m_pInStream->GetErrorCode();
517 if(!lError && pImpl->m_pOutStream)
518 lError = pImpl->m_pOutStream->GetErrorCode();
519 return lError;
520}
521
522void SfxMedium::CheckFileDate( const util::DateTime& aInitDate )
523{
524 GetInitFileDate( true );
525 if ( pImpl->m_aDateTime.Seconds == aInitDate.Seconds
526 && pImpl->m_aDateTime.Minutes == aInitDate.Minutes
527 && pImpl->m_aDateTime.Hours == aInitDate.Hours
528 && pImpl->m_aDateTime.Day == aInitDate.Day
529 && pImpl->m_aDateTime.Month == aInitDate.Month
530 && pImpl->m_aDateTime.Year == aInitDate.Year )
531 return;
532
533 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
534
535 if ( !xHandler.is() )
536 return;
537
538 try
539 {
540 ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::Any(
541 document::ChangedByOthersRequest() ) );
542 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations{
543 new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() ),
544 new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() )
545 };
546 xInteractionRequestImpl->setContinuations( aContinuations );
547
548 xHandler->handle( xInteractionRequestImpl );
549
550 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
551 if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() )
552 {
554 }
555 }
556 catch ( const uno::Exception& )
557 {}
558}
559
561{
562 return ( !IsReadOnly() && ( GetURLObject().GetProtocol() == INetProtocol::File ||
563 GetURLObject().isAnyKnownWebDAVScheme() ) );
564}
565
566util::DateTime const & SfxMedium::GetInitFileDate( bool bIgnoreOldValue )
567{
568 if ( ( bIgnoreOldValue || !pImpl->m_bGotDateTime ) && !pImpl->m_aLogicName.isEmpty() )
569 {
570 try
571 {
572 // add a default css::ucb::XCommandEnvironment
573 // in order to have the WebDAV UCP provider manage http/https authentication correctly
577
578 aContent.getPropertyValue("DateModified") >>= pImpl->m_aDateTime;
579 pImpl->m_bGotDateTime = true;
580 }
581 catch ( const css::uno::Exception& )
582 {
583 }
584 }
585
586 return pImpl->m_aDateTime;
587}
588
589
590Reference < XContent > SfxMedium::GetContent() const
591{
592 if ( !pImpl->aContent.get().is() )
593 {
594 Reference < css::ucb::XContent > xContent;
595
596 // tdf#95144 add a default css::ucb::XCommandEnvironment
597 // in order to have the WebDAV UCP provider manage https protocol certificates correctly
598 css:: uno::Reference< task::XInteractionHandler > xIH(
599 css::task::InteractionHandler::createWithParent( comphelper::getProcessComponentContext(), nullptr ) );
600
601 css::uno::Reference< css::ucb::XProgressHandler > xProgress;
602 rtl::Reference<::ucbhelper::CommandEnvironment> pCommandEnv = new ::ucbhelper::CommandEnvironment( new comphelper::SimpleFileAccessInteraction( xIH ), xProgress );
603
604 const SfxUnoAnyItem* pItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_CONTENT, false);
605 if ( pItem )
606 pItem->GetValue() >>= xContent;
607
608 if ( xContent.is() )
609 {
610 try
611 {
612 pImpl->aContent = ::ucbhelper::Content( xContent, pCommandEnv, comphelper::getProcessComponentContext() );
613 }
614 catch ( const Exception& )
615 {
616 }
617 }
618 else
619 {
620 // TODO: SAL_WARN( "sfx.doc", "SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why it's used.");
621 OUString aURL;
622 if ( !pImpl->m_aName.isEmpty() )
623 osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aURL );
624 else if ( !pImpl->m_aLogicName.isEmpty() )
626 if (!aURL.isEmpty() )
628 }
629 }
630
631 return pImpl->aContent.get();
632}
633
634OUString SfxMedium::GetBaseURL( bool bForSaving )
635{
636 if (bForSaving)
637 {
638 bool bIsRemote = IsRemote();
639 if ((bIsRemote && !officecfg::Office::Common::Save::URL::Internet::get())
640 || (!bIsRemote && !officecfg::Office::Common::Save::URL::FileSystem::get()))
641 return OUString();
642 }
643
644 if (const SfxStringItem* pBaseURLItem = GetItemSet()->GetItem<SfxStringItem>(SID_DOC_BASEURL))
645 return pBaseURLItem->GetValue();
646
647 OUString aBaseURL;
649 {
650 try
651 {
652 Any aAny = pImpl->aContent.getPropertyValue("BaseURI");
653 aAny >>= aBaseURL;
654 }
655 catch ( const css::uno::Exception& )
656 {
657 }
658
659 if ( aBaseURL.isEmpty() )
661 }
662 return aBaseURL;
663}
664
666{
667 const SfxStringItem* pSkipImagesItem = GetItemSet()->GetItem<SfxStringItem>(SID_FILE_FILTEROPTIONS);
668 return pSkipImagesItem && pSkipImagesItem->GetValue() == "SkipImages";
669}
670
672{
673 if ( pImpl->m_pInStream )
674 return pImpl->m_pInStream.get();
675
676 if ( pImpl->pTempFile )
677 {
678 pImpl->m_pInStream.reset( new SvFileStream(pImpl->m_aName, pImpl->m_nStorOpenMode) );
679
680 pImpl->m_eError = pImpl->m_pInStream->GetError();
681
682 if (!pImpl->m_eError && (pImpl->m_nStorOpenMode & StreamMode::WRITE)
683 && ! pImpl->m_pInStream->IsWritable() )
684 {
685 pImpl->m_eError = ERRCODE_IO_ACCESSDENIED;
686 pImpl->m_pInStream.reset();
687 }
688 else
689 return pImpl->m_pInStream.get();
690 }
691
693
694 if ( GetError() )
695 return nullptr;
696
697 return pImpl->m_pInStream.get();
698}
699
700
702{
704}
705
706void SfxMedium::CloseInStream_Impl(bool bInDestruction)
707{
708 // if there is a storage based on the InStream, we have to
709 // close the storage, too, because otherwise the storage
710 // would use an invalid ( deleted ) stream.
711 if ( pImpl->m_pInStream && pImpl->xStorage.is() )
712 {
713 if ( pImpl->bStorageBasedOnInStream )
714 CloseStorage();
715 }
716
717 if ( pImpl->m_pInStream && !GetContent().is() && !bInDestruction )
718 {
720 return;
721 }
722
723 pImpl->m_pInStream.reset();
724 if ( pImpl->m_pSet )
725 pImpl->m_pSet->ClearItem( SID_INPUTSTREAM );
726
728 pImpl->xInputStream.clear();
729
730 if ( !pImpl->m_pOutStream )
731 {
732 // output part of the stream is not used so the whole stream can be closed
733 // TODO/LATER: is it correct?
734 pImpl->xStream.clear();
735 if ( pImpl->m_pSet )
736 pImpl->m_pSet->ClearItem( SID_STREAM );
737 }
738}
739
740
742{
743 if ( !pImpl->m_pOutStream )
744 {
745 // Create a temp. file if there is none because we always
746 // need one.
747 CreateTempFile( false );
748
749 if ( pImpl->pTempFile )
750 {
751 // On windows we try to re-use XOutStream from xStream if that exists;
752 // because opening new SvFileStream in this situation may fail with ERROR_SHARING_VIOLATION
753 // TODO: this is a horrible hack that should probably be removed,
754 // somebody needs to investigate this more thoroughly...
755 if (getenv("SFX_MEDIUM_REUSE_STREAM") && pImpl->xStream.is())
756 {
757 assert(pImpl->xStream->getOutputStream().is()); // need that...
759 pImpl->xStream, false);
760 }
761 else
762 {
763 // On Unix don't try to re-use XOutStream from xStream if that exists;
764 // it causes fdo#59022 (fails opening files via SMB on Linux)
765 pImpl->m_pOutStream.reset( new SvFileStream(
766 pImpl->m_aName, StreamMode::STD_READWRITE) );
767 }
768 CloseStorage();
769 }
770 }
771
772 return pImpl->m_pOutStream.get();
773}
774
775
777{
779}
780
782{
783 if ( pImpl->m_pOutStream )
784 {
785 // if there is a storage based on the OutStream, we have to
786 // close the storage, too, because otherwise the storage
787 // would use an invalid ( deleted ) stream.
788 //TODO/MBA: how to deal with this?!
789 //maybe we need a new flag when the storage was created from the outstream
790 if ( pImpl->xStorage.is() )
791 {
792 CloseStorage();
793 }
794
795 pImpl->m_pOutStream.reset();
796 }
797
798 if ( !pImpl->m_pInStream )
799 {
800 // input part of the stream is not used so the whole stream can be closed
801 // TODO/LATER: is it correct?
802 pImpl->xStream.clear();
803 if ( pImpl->m_pSet )
804 pImpl->m_pSet->ClearItem( SID_STREAM );
805 }
806}
807
808
809const OUString& SfxMedium::GetPhysicalName() const
810{
811 if ( pImpl->m_aName.isEmpty() && !pImpl->m_aLogicName.isEmpty() )
812 const_cast<SfxMedium*>(this)->CreateFileStream();
813
814 // return the name then
815 return pImpl->m_aName;
816}
817
818
820{
821 // force synchron
822 if( pImpl->m_pInStream )
823 {
824 SvLockBytes* pBytes = pImpl->m_pInStream->GetLockBytes();
825 if( pBytes )
826 pBytes->SetSynchronMode();
827 }
828
829 GetInStream();
830 if( pImpl->m_pInStream )
831 {
832 CreateTempFile( false );
833 pImpl->bIsTemp = true;
835 }
836}
837
838
840{
841 if( pImpl->xStorage.is() )
843 else if( pImpl->m_pOutStream )
844 pImpl->m_pOutStream->FlushBuffer();
845 else if( pImpl->m_pInStream )
846 pImpl->m_pInStream->FlushBuffer();
847
848 if ( GetError() == ERRCODE_NONE )
849 {
850 // does something only in case there is a temporary file ( means aName points to different location than aLogicName )
852 }
853
854 bool bResult = ( GetError() == ERRCODE_NONE );
855
856 if ( bResult && DocNeedsFileDateCheck() )
857 GetInitFileDate( true );
858
859 // remove truncation mode from the flags
860 pImpl->m_nStorOpenMode &= ~StreamMode::TRUNC;
861 return bResult;
862}
863
864
866{
867 if ( pImpl->xStorage.is() )
868 return true;
869
870 if ( pImpl->m_bTriedStorage )
871 return pImpl->bIsStorage;
872
873 if ( pImpl->pTempFile )
874 {
875 OUString aURL;
876 if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aURL )
877 != osl::FileBase::E_None )
878 {
879 SAL_WARN( "sfx.doc", "Physical name '" << pImpl->m_aName << "' not convertible to file URL");
880 }
882 if ( !pImpl->bIsStorage )
883 pImpl->m_bTriedStorage = true;
884 }
885 else if ( GetInStream() )
886 {
887 pImpl->bIsStorage = SotStorage::IsStorageFile( pImpl->m_pInStream.get() ) && !SotStorage::IsOLEStorage( pImpl->m_pInStream.get() );
888 if ( !pImpl->m_pInStream->GetError() && !pImpl->bIsStorage )
889 pImpl->m_bTriedStorage = true;
890 }
891
892 return pImpl->bIsStorage;
893}
894
895
897{
898 bool bPreview = false;
899 const SfxBoolItem* pPreview = SfxItemSet::GetItem<SfxBoolItem>(GetItemSet(), SID_PREVIEW, false);
900 if ( pPreview )
901 bPreview = pPreview->GetValue();
902 else
903 {
904 const SfxStringItem* pFlags = SfxItemSet::GetItem<SfxStringItem>(GetItemSet(), SID_OPTIONS, false);
905 if ( pFlags )
906 {
907 OUString aFileFlags = pFlags->GetValue();
908 aFileFlags = aFileFlags.toAsciiUpperCase();
909 if ( -1 != aFileFlags.indexOf( 'B' ) )
910 bPreview = true;
911 }
912 }
913
914 return bPreview;
915}
916
917
919{
920 ::ucbhelper::Content aOriginalContent;
921 Reference< css::ucb::XCommandEnvironment > xDummyEnv;
922
923 bool bBasedOnOriginalFile =
924 !pImpl->pTempFile
925 && ( pImpl->m_aLogicName.isEmpty() || !pImpl->m_bSalvageMode )
927 && GetURLObject().GetProtocol() == INetProtocol::File
928 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
929
930 if ( bBasedOnOriginalFile && pImpl->m_aBackupURL.isEmpty()
932 {
933 DoInternalBackup_Impl( aOriginalContent );
934 if( pImpl->m_aBackupURL.isEmpty() )
936 }
937}
938
939
941{
942 if ( pImpl->m_aBackupURL.isEmpty() )
944
945 return pImpl->m_aBackupURL;
946}
947
948
949uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage()
950{
951 if ( GetError() )
952 return uno::Reference< embed::XStorage >();
953
954 // if the medium was constructed with a Storage: use this one, not a temp. storage
955 // if a temporary storage already exists: use it
956 if ( pImpl->xStorage.is() && ( pImpl->m_aLogicName.isEmpty() || pImpl->pTempFile ) )
957 return pImpl->xStorage;
958
959 // if necessary close stream that was used for reading
960 if ( pImpl->m_pInStream && !pImpl->m_pInStream->IsWritable() )
962
963 DBG_ASSERT( !pImpl->m_pOutStream, "OutStream in a readonly Medium?!" );
964
965 // TODO/LATER: The current solution is to store the document temporary and then copy it to the target location;
966 // in future it should be stored directly and then copied to the temporary location, since in this case no
967 // file attributes have to be preserved and system copying mechanics could be used instead of streaming.
969
970 return GetStorage();
971}
972
973
975{
976 // in case media-descriptor contains password it should be used on opening
977 if ( !pImpl->xStorage.is() || !pImpl->m_pSet )
978 return;
979
980 uno::Sequence< beans::NamedValue > aEncryptionData;
981 if ( !GetEncryptionData_Impl( pImpl->m_pSet.get(), aEncryptionData ) )
982 return;
983
984 // replace the password with encryption data
985 pImpl->m_pSet->ClearItem( SID_PASSWORD );
986 pImpl->m_pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ) );
987
988 try
989 {
991 }
992 catch( const uno::Exception& )
993 {
994 SAL_WARN( "sfx.doc", "It must be possible to set a common password for the storage" );
995 // TODO/LATER: set the error code in case of problem
996 // SetError(ERRCODE_IO_GENERAL);
997 }
998}
999
1000#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1001
1002// FIXME: Hmm actually lock files should be used for sftp: documents
1003// even if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT. Only the use of lock
1004// files for *local* documents is unnecessary in that case. But
1005// actually, the checks for sftp: here are just wishful thinking; I
1006// don't this there is any support for actually editing documents
1007// behind sftp: URLs anyway.
1008
1009// Sure, there could perhaps be a 3rd-party extension that brings UCB
1010// the potential to handle files behind sftp:. But there could also be
1011// an extension that handles some arbitrary foobar: scheme *and* it
1012// could be that lock files would be the correct thing to use for
1013// foobar: documents, too. But the hardcoded test below won't know
1014// that. Clearly the knowledge whether lock files should be used or
1015// not for some URL scheme belongs in UCB, not here.
1016
1017namespace
1018{
1019
1020OUString tryMSOwnerFiles(std::u16string_view sDocURL)
1021{
1022 svt::MSODocumentLockFile aMSOLockFile(sDocURL);
1024 try
1025 {
1026 aData = aMSOLockFile.GetLockData();
1027 }
1028 catch( const uno::Exception& )
1029 {
1030 return OUString();
1031 }
1032
1033 OUString sUserData = aData[LockFileComponent::OOOUSERNAME];
1034
1035 if (!sUserData.isEmpty())
1036 sUserData += " (MS Office)"; // Mention the used office suite
1037
1038 return sUserData;
1039}
1040
1041OUString tryForeignLockfiles(std::u16string_view sDocURL)
1042{
1043 OUString sUserData = tryMSOwnerFiles(sDocURL);
1044 // here we can test for empty result, and add other known applications' lockfile testing
1045 return sUserData.trim();
1046}
1047}
1048
1050 bool bIsLoading, bool bOwnLock,
1051 bool bHandleSysLocked)
1052{
1054
1055 // tdf#92817: Simple check for empty lock file that needs to be deleted, when system locking is enabled
1056 if( aData[LockFileComponent::OOOUSERNAME].isEmpty() && aData[LockFileComponent::SYSUSERNAME].isEmpty() && !bHandleSysLocked )
1057 bOwnLock=true;
1058
1059 // show the interaction regarding the document opening
1060 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
1061
1062 if ( xHandler.is() && ( bIsLoading || !bHandleSysLocked || bOwnLock ) )
1063 {
1064 OUString aDocumentURL
1066 OUString aInfo;
1068
1069 sal_Int32 nContinuations = 3;
1070
1071 if ( bOwnLock )
1072 {
1073 aInfo = aData[LockFileComponent::EDITTIME];
1074
1075 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::Any(
1076 document::OwnLockOnDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo, !bIsLoading ) ) );
1077 }
1078 else
1079 {
1080 // Use a fourth continuation in case there's no filesystem lock:
1081 // "Ignore lock file and open/replace the document"
1082 if (!bHandleSysLocked)
1083 nContinuations = 4;
1084
1085 if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
1086 aInfo = aData[LockFileComponent::OOOUSERNAME];
1087 else
1088 aInfo = aData[LockFileComponent::SYSUSERNAME];
1089
1090 if (aInfo.isEmpty() && !GetURLObject().isAnyKnownWebDAVScheme())
1091 // Try to get name of user who has locked the file using other applications
1092 aInfo = tryForeignLockfiles(
1094
1095 if ( !aInfo.isEmpty() && !aData[LockFileComponent::EDITTIME].isEmpty() )
1096 aInfo += " ( " + aData[LockFileComponent::EDITTIME] + " )";
1097
1098 if (!bIsLoading) // so, !bHandleSysLocked
1099 {
1100 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest(uno::Any(
1101 document::LockedOnSavingRequest(OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo)));
1102 // Currently, only the last "Retry" continuation (meaning ignore the lock and try overwriting) can be returned.
1103 }
1104 else /*logically therefore bIsLoading is set */
1105 {
1106 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::Any(
1107 document::LockedDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
1108 }
1109 }
1110
1111 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations(nContinuations);
1112 auto pContinuations = aContinuations.getArray();
1113 pContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
1114 pContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
1115 pContinuations[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl.get() );
1116 if (nContinuations > 3)
1117 {
1118 // We use InteractionRetry to reflect that user wants to
1119 // ignore the (stale?) alien lock file and open/overwrite the document
1120 pContinuations[3] = new ::ucbhelper::InteractionRetry(xInteractionRequestImpl.get());
1121 }
1122 xInteractionRequestImpl->setContinuations( aContinuations );
1123
1124 xHandler->handle( xInteractionRequestImpl );
1125
1126 bool bOpenReadOnly = false;
1127 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
1128 if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() )
1129 {
1130 SetError(ERRCODE_ABORT);
1131 }
1132 else if ( uno::Reference< task::XInteractionDisapprove >( xSelected.get(), uno::UNO_QUERY ).is() )
1133 {
1134 // own lock on loading, user has selected to ignore the lock
1135 // own lock on saving, user has selected to ignore the lock
1136 // alien lock on loading, user has selected to edit a copy of document
1137 // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location
1138 if ( !bOwnLock ) // bIsLoading implied from outermost condition
1139 {
1140 // means that a copy of the document should be opened
1141 GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, true ) );
1142 }
1143 else
1144 nResult = ShowLockResult::Succeeded;
1145 }
1146 else if (uno::Reference< task::XInteractionRetry >(xSelected.get(), uno::UNO_QUERY).is())
1147 {
1148 // User decided to ignore the alien (stale?) lock file without filesystem lock
1149 nResult = ShowLockResult::Succeeded;
1150 }
1151 else if (uno::Reference< task::XInteractionApprove >( xSelected.get(), uno::UNO_QUERY ).is())
1152 {
1153 bOpenReadOnly = true;
1154 }
1155 else // user selected "Notify"
1156 {
1157 pImpl->m_bNotifyWhenEditable = true;
1159 bOpenReadOnly = true;
1160 }
1161
1162 if (bOpenReadOnly)
1163 {
1164 // own lock on loading, user has selected to open readonly
1165 // own lock on saving, user has selected to open readonly
1166 // alien lock on loading, user has selected to retry saving
1167 // TODO/LATER: alien lock on saving, user has selected to retry saving
1168
1169 if (bIsLoading)
1170 GetItemSet()->Put(SfxBoolItem(SID_DOC_READONLY, true));
1171 else
1172 nResult = ShowLockResult::Try;
1173 }
1174 }
1175 else
1176 {
1177 if ( bIsLoading )
1178 {
1179 // if no interaction handler is provided the default answer is open readonly
1180 // that usually happens in case the document is loaded per API
1181 // so the document must be opened readonly for backward compatibility
1182 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1183 }
1184 else
1185 SetError(ERRCODE_IO_ACCESSDENIED);
1186
1187 }
1188
1189 return nResult;
1190}
1191
1192bool SfxMedium::ShowLockFileProblemDialog(MessageDlg nWhichDlg)
1193{
1194 // system file locking is not active, ask user whether he wants to open the document without any locking
1195 uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
1196
1197 if (xHandler.is())
1198 {
1200
1201 switch (nWhichDlg)
1202 {
1204 xIgnoreRequestImpl = new ::ucbhelper::InteractionRequest(uno::Any( document::LockFileIgnoreRequest() ));
1205 break;
1207 xIgnoreRequestImpl = new ::ucbhelper::InteractionRequest(uno::Any( document::LockFileCorruptRequest() ));
1208 break;
1209 }
1210
1211 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations{
1212 new ::ucbhelper::InteractionAbort(xIgnoreRequestImpl.get()),
1213 new ::ucbhelper::InteractionApprove(xIgnoreRequestImpl.get())
1214 };
1215 xIgnoreRequestImpl->setContinuations(aContinuations);
1216
1217 xHandler->handle(xIgnoreRequestImpl);
1218
1219 ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xIgnoreRequestImpl->getSelection();
1220 bool bReadOnly = true;
1221
1222 if (uno::Reference<task::XInteractionAbort>(xSelected.get(), uno::UNO_QUERY).is())
1223 {
1224 SetError(ERRCODE_ABORT);
1225 bReadOnly = false;
1226 }
1227 else if (!uno::Reference<task::XInteractionApprove>(xSelected.get(), uno::UNO_QUERY).is())
1228 {
1229 // user selected "Notify"
1230 pImpl->m_bNotifyWhenEditable = true;
1232 }
1233
1234 if (bReadOnly)
1235 GetItemSet()->Put(SfxBoolItem(SID_DOC_READONLY, true));
1236
1237 return bReadOnly;
1238 }
1239
1240 return false;
1241}
1242
1243namespace
1244{
1245 bool isSuitableProtocolForLocking(const OUString & rLogicName)
1246 {
1247 INetURLObject aUrl( rLogicName );
1248 INetProtocol eProt = aUrl.GetProtocol();
1249#if !HAVE_FEATURE_MACOSX_SANDBOX
1250 if (eProt == INetProtocol::File) {
1251 return true;
1252 }
1253#endif
1254 return eProt == INetProtocol::Smb || eProt == INetProtocol::Sftp;
1255 }
1256}
1257
1258namespace
1259{
1260
1261// for LOCK request, suppress dialog on 403, typically indicates read-only
1262// document and there's a 2nd dialog prompting to open a copy anyway
1263class LockInteractionHandler : public ::cppu::WeakImplHelper<task::XInteractionHandler>
1264{
1265private:
1266 uno::Reference<task::XInteractionHandler> m_xHandler;
1267
1268public:
1269 explicit LockInteractionHandler(uno::Reference<task::XInteractionHandler> const& xHandler)
1270 : m_xHandler(xHandler)
1271 {
1272 }
1273
1274 virtual void SAL_CALL handle(uno::Reference<task::XInteractionRequest> const& xRequest) override
1275 {
1276 ucb::InteractiveNetworkWriteException readException;
1277 ucb::InteractiveNetworkReadException writeException;
1278 if ((xRequest->getRequest() >>= readException)
1279 || (xRequest->getRequest() >>= writeException))
1280 {
1281 return; // 403 gets reported as one of these; ignore to avoid dialog
1282 }
1283 m_xHandler->handle(xRequest);
1284 }
1285};
1286
1287} // namespace
1288
1289#endif // HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1290
1291// sets SID_DOC_READONLY if the document cannot be opened for editing
1292// if user cancel the loading the ERROR_ABORT is set
1294 bool bTryIgnoreLockFile,
1295 LockFileEntry* pLockData)
1296{
1297#if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1298 (void) bLoading;
1299 (void) bNoUI;
1300 (void) bTryIgnoreLockFile;
1301 (void) pLockData;
1303#else
1305
1306 // check if path scheme is http:// or https://
1307 // may be this is better if used always, in Android and iOS as well?
1308 // if this code should be always there, remember to move the relevant code in UnlockFile method as well !
1309
1311 {
1312 // do nothing if WebDAV locking is disabled
1313 if (!IsWebDAVLockingUsed())
1315
1316 {
1317 bool bResult = pImpl->m_bLocked;
1318 bool bIsTemplate = false;
1319 // so, this is webdav stuff...
1320 if ( !bResult )
1321 {
1322 // no read-write access is necessary on loading if the document is explicitly opened as copy
1323 const SfxBoolItem* pTemplateItem = SfxItemSet::GetItem<SfxBoolItem>(GetItemSet(), SID_TEMPLATE, false);
1324 bIsTemplate = ( bLoading && pTemplateItem && pTemplateItem->GetValue() );
1325 }
1326
1327 if ( !bIsTemplate && !bResult && !IsReadOnly() )
1328 {
1330 do
1331 {
1332 if( !bResult )
1333 {
1334 uno::Reference< task::XInteractionHandler > xCHandler = GetInteractionHandler( true );
1335 // Dialog with error is superfluous:
1336 // on loading, will result in read-only with infobar.
1337 // bNoUI case for Reload failing, will open dialog later.
1338 if (bLoading || bNoUI)
1339 {
1340 xCHandler = new LockInteractionHandler(xCHandler);
1341 }
1342 Reference< css::ucb::XCommandEnvironment > xComEnv = new ::ucbhelper::CommandEnvironment(
1343 xCHandler, Reference< css::ucb::XProgressHandler >() );
1344
1345 ucbhelper::Content aContentToLock(
1348
1349 try
1350 {
1351 aContentToLock.lock();
1352 bResult = true;
1353 }
1354 catch ( ucb::InteractiveLockingLockedException& )
1355 {
1356 // received when the resource is already locked
1357 if (!bNoUI || pLockData)
1358 {
1359 // get the lock owner, using a special ucb.webdav property
1360 // the owner property retrieved here is what the other principal send the server
1361 // when activating the lock.
1362 // See http://tools.ietf.org/html/rfc4918#section-14.17 for details
1363 LockFileEntry aLockData;
1364 aLockData[LockFileComponent::OOOUSERNAME] = "Unknown user";
1365 // This solution works right when the LO user name and the WebDAV user
1366 // name are the same.
1367 // A better thing to do would be to obtain the 'real' WebDAV user name,
1368 // but that's not possible from a WebDAV UCP provider client.
1370 // use the current LO user name as the system name
1371 aLockData[LockFileComponent::SYSUSERNAME]
1372 = aOwnData[LockFileComponent::SYSUSERNAME];
1373
1374 uno::Sequence<css::ucb::Lock> aLocks;
1375 // getting the property, send a PROPFIND to the server over the net
1376 if ((aContentToLock.getPropertyValue("DAV:lockdiscovery") >>= aLocks) && aLocks.hasElements())
1377 {
1378 // got at least a lock, show the owner of the first lock returned
1379 css::ucb::Lock aLock = aLocks[0];
1380 OUString aOwner;
1381 if (aLock.Owner >>= aOwner)
1382 {
1383 // we need to display the WebDAV user name owning the lock, not the local one
1384 aLockData[LockFileComponent::OOOUSERNAME] = aOwner;
1385 }
1386 }
1387
1388 if (!bNoUI)
1389 {
1390 bUIStatus = ShowLockedDocumentDialog(aLockData, bLoading, false,
1391 true);
1392 }
1393
1394 if (pLockData)
1395 {
1396 std::copy(aLockData.begin(), aLockData.end(), pLockData->begin());
1397 }
1398 }
1399 }
1400 catch( ucb::InteractiveNetworkWriteException& )
1401 {
1402 // This catch it's not really needed, here just for the sake of documentation on the behaviour.
1403 // This is the most likely reason:
1404 // - the remote site is a WebDAV with special configuration: read/only for read operations
1405 // and read/write for write operations, the user is not allowed to lock/write and
1406 // she cancelled the credentials request.
1407 // this is not actually an error, but the exception is sent directly from ucb, avoiding the automatic
1408 // management that takes part in cancelCommandExecution()
1409 // Unfortunately there is no InteractiveNetwork*Exception available to signal this more correctly
1410 // since it mostly happens on read/only part of webdav, this can be the most correct
1411 // exception available
1412 }
1413 catch( uno::Exception& )
1414 {
1415 TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
1416 }
1417 }
1418 } while( !bResult && bUIStatus == ShowLockResult::Try );
1419 }
1420
1421 pImpl->m_bLocked = bResult;
1422
1423 if ( !bResult && GetError() == ERRCODE_NONE )
1424 {
1425 // the error should be set in case it is storing process
1426 // or the document has been opened for editing explicitly
1427 const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
1428
1429 if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) )
1431 else
1432 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1433 }
1434
1435 // when the file is locked, get the current file date
1436 if ( bResult && DocNeedsFileDateCheck() )
1437 GetInitFileDate( true );
1438
1439 if ( bResult )
1440 eResult = LockFileResult::Succeeded;
1441 }
1442 return eResult;
1443 }
1444
1445 if (!IsLockingUsed())
1447 if (GetURLObject().HasError())
1448 return eResult;
1449
1450 try
1451 {
1452 if ( pImpl->m_bLocked && bLoading
1453 && GetURLObject().GetProtocol() == INetProtocol::File )
1454 {
1455 // if the document is already locked the system locking might be temporarily off after storing
1456 // check whether the system file locking should be taken again
1458 }
1459
1460 bool bResult = pImpl->m_bLocked;
1461
1462 if ( !bResult )
1463 {
1464 // no read-write access is necessary on loading if the document is explicitly opened as copy
1465 const SfxBoolItem* pTemplateItem = SfxItemSet::GetItem<SfxBoolItem>(GetItemSet(), SID_TEMPLATE, false);
1466 bResult = ( bLoading && pTemplateItem && pTemplateItem->GetValue() );
1467 }
1468
1469 if ( !bResult && !IsReadOnly() )
1470 {
1471 bool bContentReadonly = false;
1472 if ( bLoading && GetURLObject().GetProtocol() == INetProtocol::File )
1473 {
1474 // let the original document be opened to check the possibility to open it for editing
1475 // and to let the writable stream stay open to hold the lock on the document
1477 }
1478
1479 // "IsReadOnly" property does not allow to detect whether the file is readonly always
1480 // so we try always to open the file for editing
1481 // the file is readonly only in case the read-write stream can not be opened
1482 if ( bLoading && !pImpl->m_xLockingStream.is() )
1483 {
1484 try
1485 {
1486 // MediaDescriptor does this check also, the duplication should be avoided in future
1487 Reference< css::ucb::XCommandEnvironment > xDummyEnv;
1489 aContent.getPropertyValue("IsReadOnly") >>= bContentReadonly;
1490 }
1491 catch( const uno::Exception& ) {}
1492 }
1493
1494 // do further checks only if the file not readonly in fs
1495 if ( !bContentReadonly )
1496 {
1497 // the special file locking should be used only for suitable URLs
1498 if ( isSuitableProtocolForLocking( pImpl->m_aLogicName ) )
1499 {
1500
1501 // in case of storing the document should request the output before locking
1502 if ( bLoading )
1503 {
1504 // let the stream be opened to check the system file locking
1506 if (GetError() != ERRCODE_NONE) {
1507 return eResult;
1508 }
1509 }
1510
1512
1513 // check whether system file locking has been used, the default value is false
1514 bool bUseSystemLock = comphelper::isFileUrl( pImpl->m_aLogicName ) && IsSystemFileLockingUsed();
1515
1516 // TODO/LATER: This implementation does not allow to detect the system lock on saving here, actually this is no big problem
1517 // if system lock is used the writeable stream should be available
1518 bool bHandleSysLocked = ( bLoading && bUseSystemLock && !pImpl->xStream.is() && !pImpl->m_pOutStream );
1519
1520 // The file is attempted to get locked for the duration of lockfile creation on save
1521 std::unique_ptr<osl::File> pFileLock;
1522 if (!bLoading && bUseSystemLock && pImpl->pTempFile)
1523 {
1524 INetURLObject aDest(GetURLObject());
1525 OUString aDestURL(aDest.GetMainURL(INetURLObject::DecodeMechanism::NONE));
1526
1527 if (comphelper::isFileUrl(aDestURL) || !aDest.removeSegment())
1528 {
1529 pFileLock = std::make_unique<osl::File>(aDestURL);
1530 auto rc = pFileLock->open(osl_File_OpenFlag_Write);
1531 if (rc == osl::FileBase::E_ACCES)
1532 bHandleSysLocked = true;
1533 }
1534 }
1535
1536 do
1537 {
1538 try
1539 {
1540 ::svt::DocumentLockFile aLockFile( pImpl->m_aLogicName );
1541
1542 std::unique_ptr<svt::MSODocumentLockFile> pMSOLockFile;
1545 {
1546 pMSOLockFile.reset(new svt::MSODocumentLockFile(pImpl->m_aLogicName));
1547 pImpl->m_bMSOLockFileCreated = true;
1548 }
1549
1550 bool bIoErr = false;
1551
1552 if (!bHandleSysLocked)
1553 {
1554 try
1555 {
1556 bResult = aLockFile.CreateOwnLockFile();
1557 if(pMSOLockFile)
1558 bResult &= pMSOLockFile->CreateOwnLockFile();
1559 }
1560 catch (const uno::Exception&)
1561 {
1562 if (tools::IsMappedWebDAVPath(GetURLObject().GetMainURL(
1564 {
1565 // This is a path that redirects to a WebDAV resource;
1566 // so failure creating lockfile is not an error here.
1567 bResult = true;
1568 }
1569 else if (bLoading && !bNoUI)
1570 {
1571 bIoErr = true;
1573 bResult = true; // always delete the defect lock-file
1574 }
1575 }
1576
1577 // in case OOo locking is turned off the lock file is still written if possible
1578 // but it is ignored while deciding whether the document should be opened for editing or not
1579 if (!bResult && !IsOOoLockFileUsed() && !bIoErr)
1580 {
1581 bResult = true;
1582 // take the ownership over the lock file
1583 aLockFile.OverwriteOwnLockFile();
1584
1585 if(pMSOLockFile)
1586 pMSOLockFile->OverwriteOwnLockFile();
1587 }
1588 }
1589
1590 if ( !bResult )
1591 {
1593 try
1594 {
1595 aData = aLockFile.GetLockData();
1596 }
1597 catch (const io::WrongFormatException&)
1598 {
1599 // we get empty or corrupt data
1600 // info to the user
1601 if (!bIoErr && bLoading && !bNoUI )
1603
1604 // not show the Lock Document Dialog
1605 bIoErr = true;
1606 }
1607 catch( const uno::Exception& )
1608 {
1609 // show the Lock Document Dialog, when locked from other app
1610 bIoErr = !bHandleSysLocked;
1611 }
1612
1613 bool bOwnLock = false;
1614
1615 if (!bHandleSysLocked)
1616 {
1618 bOwnLock = aOwnData[LockFileComponent::SYSUSERNAME] == aData[LockFileComponent::SYSUSERNAME];
1619
1620 if (bOwnLock
1621 && aOwnData[LockFileComponent::LOCALHOST] == aData[LockFileComponent::LOCALHOST]
1622 && aOwnData[LockFileComponent::USERURL] == aData[LockFileComponent::USERURL])
1623 {
1624 // this is own lock from the same installation, it could remain because of crash
1625 bResult = true;
1626 }
1627 }
1628
1629 if ( !bResult && !bIoErr)
1630 {
1631 if (!bNoUI)
1632 bUIStatus = ShowLockedDocumentDialog(
1633 aData, bLoading, bOwnLock, bHandleSysLocked);
1634 else if (bLoading && bTryIgnoreLockFile && !bHandleSysLocked)
1635 bUIStatus = ShowLockResult::Succeeded;
1636
1637 if ( bUIStatus == ShowLockResult::Succeeded )
1638 {
1639 // take the ownership over the lock file
1640 bResult = aLockFile.OverwriteOwnLockFile();
1641
1642 if(pMSOLockFile)
1643 pMSOLockFile->OverwriteOwnLockFile();
1644 }
1645 else if (bLoading && !bHandleSysLocked)
1647
1648 if (!bResult && pLockData)
1649 {
1650 std::copy(aData.begin(), aData.end(), pLockData->begin());
1651 }
1652 }
1653 }
1654 }
1655 catch( const uno::Exception& )
1656 {
1657 }
1658 } while( !bResult && bUIStatus == ShowLockResult::Try );
1659
1660 pImpl->m_bLocked = bResult;
1661 }
1662 else
1663 {
1664 // this is no file URL, check whether the file is readonly
1665 bResult = !bContentReadonly;
1666 }
1667 }
1668 else // read-only
1669 {
1671 }
1672 }
1673
1674 if ( !bResult && GetError() == ERRCODE_NONE )
1675 {
1676 // the error should be set in case it is storing process
1677 // or the document has been opened for editing explicitly
1678 const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
1679
1680 if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) )
1682 else
1683 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1684 }
1685
1686 // when the file is locked, get the current file date
1687 if ( bResult && DocNeedsFileDateCheck() )
1688 GetInitFileDate( true );
1689
1690 if ( bResult )
1691 eResult = LockFileResult::Succeeded;
1692 }
1693 catch( const uno::Exception& )
1694 {
1695 TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: high probability, that the content has not been created" );
1696 }
1697
1698 return eResult;
1699#endif
1700}
1701
1702
1703uno::Reference < embed::XStorage > SfxMedium::GetStorage( bool bCreateTempFile )
1704{
1705 if ( pImpl->xStorage.is() || pImpl->m_bTriedStorage )
1706 return pImpl->xStorage;
1707
1708 uno::Sequence< uno::Any > aArgs( 2 );
1709 auto pArgs = aArgs.getArray();
1710
1711 // the medium should be retrieved before temporary file creation
1712 // to let the MediaDescriptor be filled with the streams
1714
1715 if ( bCreateTempFile )
1716 CreateTempFile( false );
1717
1719
1720 if ( GetError() )
1721 return pImpl->xStorage;
1722
1723 const SfxBoolItem* pRepairItem = SfxItemSet::GetItem<SfxBoolItem>(GetItemSet(), SID_REPAIRPACKAGE, false);
1724 if ( pRepairItem && pRepairItem->GetValue() )
1725 {
1726 // the storage should be created for repairing mode
1727 CreateTempFile( false );
1729
1730 Reference< css::ucb::XProgressHandler > xProgressHandler;
1731 Reference< css::task::XStatusIndicator > xStatusIndicator;
1732
1733 const SfxUnoAnyItem* pxProgressItem = SfxItemSet::GetItem<SfxUnoAnyItem>(GetItemSet(), SID_PROGRESS_STATUSBAR_CONTROL, false);
1734 if( pxProgressItem && ( pxProgressItem->GetValue() >>= xStatusIndicator ) )
1735 xProgressHandler.set( new utl::ProgressHandlerWrap( xStatusIndicator ) );
1736
1737 uno::Sequence< beans::PropertyValue > aAddProps{
1738 comphelper::makePropertyValue("RepairPackage", true),
1739 comphelper::makePropertyValue("StatusIndicator", xProgressHandler)
1740 };
1741
1742 // the first arguments will be filled later
1743 aArgs.realloc( 3 );
1744 pArgs = aArgs.getArray();
1745 pArgs[2] <<= aAddProps;
1746 }
1747
1748 if ( pImpl->xStream.is() )
1749 {
1750 // since the storage is based on temporary stream we open it always read-write
1751 pArgs[0] <<= pImpl->xStream;
1752 pArgs[1] <<= embed::ElementModes::READWRITE;
1753 pImpl->bStorageBasedOnInStream = true;
1754 if (pImpl->m_bDisableFileSync)
1755 {
1756 // Forward NoFileSync to the storage factory.
1757 aArgs.realloc(3); // ??? this may re-write the data added above for pRepairItem
1758 pArgs = aArgs.getArray();
1759 uno::Sequence<beans::PropertyValue> aProperties(
1760 comphelper::InitPropertySequence({ { "NoFileSync", uno::Any(true) } }));
1761 pArgs[2] <<= aProperties;
1762 }
1763 }
1764 else if ( pImpl->xInputStream.is() )
1765 {
1766 // since the storage is based on temporary stream we open it always read-write
1767 pArgs[0] <<= pImpl->xInputStream;
1768 pArgs[1] <<= embed::ElementModes::READ;
1769 pImpl->bStorageBasedOnInStream = true;
1770 }
1771 else
1772 {
1774 pArgs[0] <<= pImpl->m_aName;
1775 pArgs[1] <<= embed::ElementModes::READ;
1776 pImpl->bStorageBasedOnInStream = false;
1777 }
1778
1779 try
1780 {
1781 pImpl->xStorage.set( ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ),
1782 uno::UNO_QUERY );
1783 }
1784 catch( const uno::Exception& )
1785 {
1786 // impossibility to create the storage is no error
1787 }
1788
1789 if( ( pImpl->nLastStorageError = GetError() ) != ERRCODE_NONE )
1790 {
1791 pImpl->xStorage = nullptr;
1792 if ( pImpl->m_pInStream )
1793 pImpl->m_pInStream->Seek(0);
1794 return uno::Reference< embed::XStorage >();
1795 }
1796
1797 pImpl->m_bTriedStorage = true;
1798
1799 // TODO/LATER: Get versionlist on demand
1800 if ( pImpl->xStorage.is() )
1801 {
1804 }
1805
1806 const SfxInt16Item* pVersion = SfxItemSet::GetItem<SfxInt16Item>(pImpl->m_pSet.get(), SID_VERSION, false);
1807
1808 bool bResetStorage = false;
1809 if ( pVersion && pVersion->GetValue() )
1810 {
1811 // Read all available versions
1812 if ( pImpl->aVersions.hasElements() )
1813 {
1814 // Search for the version fits the comment
1815 // The versions are numbered starting with 1, versions with
1816 // negative versions numbers are counted backwards from the
1817 // current version
1818 short nVersion = pVersion->GetValue();
1819 if ( nVersion<0 )
1820 nVersion = static_cast<short>(pImpl->aVersions.getLength()) + nVersion;
1821 else // nVersion > 0; pVersion->GetValue() != 0 was the condition to this block
1822 nVersion--;
1823
1824 const util::RevisionTag& rTag = pImpl->aVersions[nVersion];
1825 {
1826 // Open SubStorage for all versions
1827 uno::Reference < embed::XStorage > xSub = pImpl->xStorage->openStorageElement( "Versions",
1828 embed::ElementModes::READ );
1829
1830 DBG_ASSERT( xSub.is(), "Version list, but no Versions!" );
1831
1832 // There the version is stored as packed Stream
1833 uno::Reference < io::XStream > xStr = xSub->openStreamElement( rTag.Identifier, embed::ElementModes::READ );
1834 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( xStr ));
1835 if ( pStream && pStream->GetError() == ERRCODE_NONE )
1836 {
1837 // Unpack Stream in TempDir
1838 const OUString aTmpName = ::utl::CreateTempURL();
1839 SvFileStream aTmpStream( aTmpName, SFX_STREAM_READWRITE );
1840
1841 pStream->ReadStream( aTmpStream );
1842 pStream.reset();
1843 aTmpStream.Close();
1844
1845 // Open data as Storage
1846 pImpl->m_nStorOpenMode = SFX_STREAM_READONLY;
1847 pImpl->xStorage = comphelper::OStorageHelper::GetStorageFromURL( aTmpName, embed::ElementModes::READ );
1848 pImpl->bStorageBasedOnInStream = false;
1849 OUString aTemp;
1850 osl::FileBase::getSystemPathFromFileURL( aTmpName, aTemp );
1851 SetPhysicalName_Impl( aTemp );
1852
1853 pImpl->bIsTemp = true;
1854 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1855 // TODO/MBA
1856 pImpl->aVersions.realloc(0);
1857 }
1858 else
1859 bResetStorage = true;
1860 }
1861 }
1862 else
1863 bResetStorage = true;
1864 }
1865
1866 if ( bResetStorage )
1867 {
1868 pImpl->xStorage.clear();
1869 if ( pImpl->m_pInStream )
1870 pImpl->m_pInStream->Seek( 0 );
1871 }
1872
1873 pImpl->bIsStorage = pImpl->xStorage.is();
1874 return pImpl->xStorage;
1875}
1876
1877
1878uno::Reference< embed::XStorage > const & SfxMedium::GetZipStorageToSign_Impl( bool bReadOnly )
1879{
1880 if ( !GetError() && !pImpl->m_xZipStorage.is() )
1881 {
1883
1884 try
1885 {
1886 // we can not sign document if there is no stream
1887 // should it be possible at all?
1888 if ( !bReadOnly && pImpl->xStream.is() )
1889 {
1891 }
1892 else if ( pImpl->xInputStream.is() )
1893 {
1895 }
1896 }
1897 catch( const uno::Exception& )
1898 {
1899 SAL_WARN( "sfx.doc", "No possibility to get readonly version of storage from medium!" );
1900 }
1901
1902 if ( GetError() ) // do not remove warnings
1903 ResetError();
1904 }
1905
1906 return pImpl->m_xZipStorage;
1907}
1908
1909
1911{
1912 if ( pImpl->m_xZipStorage.is() )
1913 {
1914 try {
1915 pImpl->m_xZipStorage->dispose();
1916 } catch( const uno::Exception& )
1917 {}
1918
1919 pImpl->m_xZipStorage.clear();
1920 }
1921}
1922
1924{
1925 if ( pImpl->xStorage.is() )
1926 {
1927 uno::Reference < lang::XComponent > xComp = pImpl->xStorage;
1928 // in the salvage mode the medium does not own the storage
1929 if ( pImpl->bDisposeStorage && !pImpl->m_bSalvageMode )
1930 {
1931 try {
1932 xComp->dispose();
1933 } catch( const uno::Exception& )
1934 {
1935 SAL_WARN( "sfx.doc", "Medium's storage is already disposed!" );
1936 }
1937 }
1938
1939 pImpl->xStorage.clear();
1940 pImpl->bStorageBasedOnInStream = false;
1941 }
1942
1943 pImpl->m_bTriedStorage = false;
1944 pImpl->bIsStorage = false;
1945}
1946
1947void SfxMedium::CanDisposeStorage_Impl( bool bDisposeStorage )
1948{
1949 pImpl->bDisposeStorage = bDisposeStorage;
1950}
1951
1953{
1954 return pImpl->bDisposeStorage;
1955}
1956
1958{
1959 return pImpl->m_nStorOpenMode;
1960}
1961
1963 bool bDontClose )
1964{
1965 if ( pImpl->m_nStorOpenMode != nStorOpen )
1966 {
1967 pImpl->m_nStorOpenMode = nStorOpen;
1968
1969 if( !bDontClose )
1970 {
1971 if ( pImpl->xStorage.is() )
1972 CloseStorage();
1973
1975 }
1976 }
1977}
1978
1979
1981 const Reference< css::ucb::XCommandEnvironment >& xComEnv )
1982{
1983 try
1984 {
1985 ::ucbhelper::Content aTransactCont( pImpl->m_aBackupURL, xComEnv, comphelper::getProcessComponentContext() );
1986
1987 Reference< XInputStream > aOrigInput = aTransactCont.openStream();
1988 aOriginalContent.writeStream( aOrigInput, true );
1989 return true;
1990 }
1991 catch( const Exception& )
1992 {
1993 // in case of failure here the backup file should not be removed
1994 // TODO/LATER: a message should be used to let user know about the backup
1995 pImpl->m_bRemoveBackup = false;
1996 // TODO/LATER: needs a specific error code
1997 pImpl->m_eError = ERRCODE_IO_GENERAL;
1998 }
1999
2000 return false;
2001}
2002
2003
2005{
2006 bool bResult = false;
2007 Reference< css::ucb::XCommandEnvironment > xDummyEnv;
2008 ::ucbhelper::Content aOriginalContent;
2009
2010 if ( pImpl->xStorage.is() )
2011 {
2012 if ( !GetError() )
2013 {
2014 uno::Reference < embed::XTransactedObject > xTrans( pImpl->xStorage, uno::UNO_QUERY );
2015 if ( xTrans.is() )
2016 {
2017 try
2018 {
2019 xTrans->commit();
2021 bResult = true;
2022 }
2023 catch ( const embed::UseBackupException& aBackupExc )
2024 {
2025 // since the temporary file is created always now, the scenario is close to be impossible
2026 if ( !pImpl->pTempFile )
2027 {
2028 OSL_ENSURE( !pImpl->m_aBackupURL.isEmpty(), "No backup on storage commit!" );
2029 if ( !pImpl->m_aBackupURL.isEmpty()
2032 aOriginalContent ) )
2033 {
2034 // use backup to restore the file
2035 // the storage has already disconnected from original location
2037 if ( !UseBackupToRestore_Impl( aOriginalContent, xDummyEnv ) )
2038 {
2039 // connect the medium to the temporary file of the storage
2040 pImpl->aContent = ::ucbhelper::Content();
2041 pImpl->m_aName = aBackupExc.TemporaryFileURL;
2042 OSL_ENSURE( !pImpl->m_aName.isEmpty(), "The exception _must_ contain the temporary URL!" );
2043 }
2044 }
2045 }
2046
2047 if (!GetError())
2049 }
2050 catch ( const uno::Exception& )
2051 {
2052 //TODO/LATER: improve error handling
2054 }
2055 }
2056 }
2057 }
2058
2059 return bResult;
2060}
2061
2062
2064 const INetURLObject& aDest,
2065 const Reference< css::ucb::XCommandEnvironment >& xComEnv )
2066{
2067 Reference< css::ucb::XCommandEnvironment > xDummyEnv;
2068 ::ucbhelper::Content aOriginalContent;
2069
2070 try
2071 {
2073 }
2074 catch ( const css::ucb::CommandAbortedException& )
2075 {
2076 pImpl->m_eError = ERRCODE_ABORT;
2077 }
2078 catch ( const css::ucb::CommandFailedException& )
2079 {
2080 pImpl->m_eError = ERRCODE_ABORT;
2081 }
2082 catch (const css::ucb::ContentCreationException& ex)
2083 {
2084 pImpl->m_eError = ERRCODE_IO_GENERAL;
2085 if (
2086 (ex.eError == css::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
2087 (ex.eError == css::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
2088 )
2089 {
2090 pImpl->m_eError = ERRCODE_IO_NOTEXISTSPATH;
2091 }
2092 }
2093 catch (const css::uno::Exception&)
2094 {
2095 pImpl->m_eError = ERRCODE_IO_GENERAL;
2096 }
2097
2098 if( pImpl->m_eError && !pImpl->m_eError.IsWarning() )
2099 return;
2100
2101 if ( pImpl->xStorage.is() )
2102 CloseStorage();
2103
2105
2106 ::ucbhelper::Content aTempCont;
2108 {
2109 bool bTransactStarted = false;
2110 const SfxBoolItem* pOverWrite = SfxItemSet::GetItem<SfxBoolItem>(GetItemSet(), SID_OVERWRITE, false);
2111 bool bOverWrite = !pOverWrite || pOverWrite->GetValue();
2112 bool bResult = false;
2113
2114 try
2115 {
2116 // tdf#60237 - if the OverWrite property of the MediaDescriptor is set to false,
2117 // try to write the file before trying to rename or copy it
2118 if (!(bOverWrite
2119 && ::utl::UCBContentHelper::IsDocument(
2121 {
2122 Reference< XInputStream > aTempInput = aTempCont.openStream();
2123 aOriginalContent.writeStream( aTempInput, bOverWrite );
2124 bResult = true;
2125 } else {
2126 OUString aSourceMainURL = aSource.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2127 OUString aDestMainURL = aDest.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2128
2129 sal_uInt64 nAttributes = GetDefaultFileAttributes(aDestMainURL);
2130 if (IsFileMovable(aDest)
2131 && osl::File::replace(aSourceMainURL, aDestMainURL) == osl::FileBase::E_None)
2132 {
2133 if (nAttributes)
2134 // Adjust attributes, source might be created with
2135 // the osl_File_OpenFlag_Private flag.
2136 osl::File::setAttributes(aDestMainURL, nAttributes);
2137 bResult = true;
2138 }
2139 else
2140 {
2141 if( pImpl->m_aBackupURL.isEmpty() )
2142 DoInternalBackup_Impl( aOriginalContent );
2143
2144 if( !pImpl->m_aBackupURL.isEmpty() )
2145 {
2146 Reference< XInputStream > aTempInput = aTempCont.openStream();
2147 bTransactStarted = true;
2148 aOriginalContent.setPropertyValue( "Size", uno::Any( sal_Int64(0) ) );
2149 aOriginalContent.writeStream( aTempInput, bOverWrite );
2150 bResult = true;
2151 }
2152 else
2153 {
2155 }
2156 }
2157 }
2158 }
2159 catch ( const css::ucb::CommandAbortedException& )
2160 {
2161 pImpl->m_eError = ERRCODE_ABORT;
2162 }
2163 catch ( const css::ucb::CommandFailedException& )
2164 {
2165 pImpl->m_eError = ERRCODE_ABORT;
2166 }
2167 catch ( const css::ucb::InteractiveIOException& r )
2168 {
2169 if ( r.Code == IOErrorCode_ACCESS_DENIED )
2170 pImpl->m_eError = ERRCODE_IO_ACCESSDENIED;
2171 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2172 pImpl->m_eError = ERRCODE_IO_NOTEXISTS;
2173 else if ( r.Code == IOErrorCode_CANT_READ )
2174 pImpl->m_eError = ERRCODE_IO_CANTREAD;
2175 else
2176 pImpl->m_eError = ERRCODE_IO_GENERAL;
2177 }
2178 // tdf#60237 - if the file is already present, raise the appropriate error
2179 catch (const css::ucb::NameClashException& )
2180 {
2181 pImpl->m_eError = ERRCODE_IO_ALREADYEXISTS;
2182 }
2183 catch ( const css::uno::Exception& )
2184 {
2185 pImpl->m_eError = ERRCODE_IO_GENERAL;
2186 }
2187
2188 if ( bResult )
2189 {
2190 if ( pImpl->pTempFile )
2191 {
2192 pImpl->pTempFile->EnableKillingFile();
2193 pImpl->pTempFile.reset();
2194 }
2195 }
2196 else if ( bTransactStarted && pImpl->m_eError != ERRCODE_ABORT )
2197 {
2198 UseBackupToRestore_Impl( aOriginalContent, xDummyEnv );
2199 }
2200 }
2201 else
2202 pImpl->m_eError = ERRCODE_IO_CANTREAD;
2203}
2204
2205
2206bool SfxMedium::TryDirectTransfer( const OUString& aURL, SfxItemSet const & aTargetSet )
2207{
2208 if ( GetError() )
2209 return false;
2210
2211 // if the document had no password it should be stored without password
2212 // if the document had password it should be stored with the same password
2213 // otherwise the stream copying can not be done
2214 const SfxStringItem* pNewPassItem = aTargetSet.GetItem<SfxStringItem>(SID_PASSWORD, false);
2215 const SfxStringItem* pOldPassItem = SfxItemSet::GetItem<SfxStringItem>(GetItemSet(), SID_PASSWORD, false);
2216 if ( ( !pNewPassItem && !pOldPassItem )
2217 || ( pNewPassItem && pOldPassItem && pNewPassItem->GetValue() == pOldPassItem->GetValue() ) )
2218 {
2219 // the filter must be the same
2220 const SfxStringItem* pNewFilterItem = aTargetSet.GetItem<SfxStringItem>(SID_FILTER_NAME, false);
2221 const SfxStringItem* pOldFilterItem = SfxItemSet::GetItem<SfxStringItem>(GetItemSet(), SID_FILTER_NAME, false);
2222 if ( pNewFilterItem && pOldFilterItem && pNewFilterItem->GetValue() == pOldFilterItem->GetValue() )
2223 {
2224 // get the input stream and copy it
2225 // in case of success return true
2226 uno::Reference< io::XInputStream > xInStream = GetInputStream();
2227
2228 ResetError();
2229 if ( xInStream.is() )
2230 {
2231 try
2232 {
2233 uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
2234 sal_Int64 nPos = 0;
2235 if ( xSeek.is() )
2236 {
2237 nPos = xSeek->getPosition();
2238 xSeek->seek( 0 );
2239 }
2240
2241 uno::Reference < css::ucb::XCommandEnvironment > xEnv;
2243
2244 InsertCommandArgument aInsertArg;
2245 aInsertArg.Data = xInStream;
2246 const SfxBoolItem* pOverWrite = aTargetSet.GetItem<SfxBoolItem>(SID_OVERWRITE, false);
2247 if ( pOverWrite && !pOverWrite->GetValue() ) // argument says: never overwrite
2248 aInsertArg.ReplaceExisting = false;
2249 else
2250 aInsertArg.ReplaceExisting = true; // default is overwrite existing files
2251
2252 Any aCmdArg;
2253 aCmdArg <<= aInsertArg;
2254 aTargetContent.executeCommand( "insert",
2255 aCmdArg );
2256
2257 if ( xSeek.is() )
2258 xSeek->seek( nPos );
2259
2260 return true;
2261 }
2262 catch( const uno::Exception& )
2263 {}
2264 }
2265 }
2266 }
2267
2268 return false;
2269}
2270
2271
2273{
2274 // The transfer is required only in two cases: either if there is a temporary file or if there is a salvage item
2275 OUString aNameURL;
2276 if ( pImpl->pTempFile )
2277 aNameURL = pImpl->pTempFile->GetURL();
2278 else if ( !pImpl->m_aLogicName.isEmpty() && pImpl->m_bSalvageMode )
2279 {
2280 // makes sense only in case logic name is set
2281 if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aNameURL )
2282 != osl::FileBase::E_None )
2283 SAL_WARN( "sfx.doc", "The medium name is not convertible!" );
2284 }
2285
2286 if ( aNameURL.isEmpty() || ( pImpl->m_eError && !pImpl->m_eError.IsWarning() ) )
2287 return;
2288
2289 SAL_INFO( "sfx.doc", "SfxMedium::Transfer_Impl, copying to target" );
2290
2291 Reference < css::ucb::XCommandEnvironment > xEnv;
2292 Reference< XOutputStream > rOutStream;
2293
2294 // in case an output stream is provided from outside and the URL is correct
2295 // commit to the stream
2296 if (pImpl->m_aLogicName.startsWith("private:stream"))
2297 {
2298 // TODO/LATER: support storing to SID_STREAM
2299 const SfxUnoAnyItem* pOutStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_OUTPUTSTREAM, false);
2300 if( pOutStreamItem && ( pOutStreamItem->GetValue() >>= rOutStream ) )
2301 {
2302 if ( pImpl->xStorage.is() )
2303 CloseStorage();
2304
2306
2307 INetURLObject aSource( aNameURL );
2308 ::ucbhelper::Content aTempCont;
2310 {
2311 try
2312 {
2313 sal_Int32 nRead;
2314 sal_Int32 nBufferSize = 32767;
2315 Sequence < sal_Int8 > aSequence ( nBufferSize );
2316 Reference< XInputStream > aTempInput = aTempCont.openStream();
2317
2318 do
2319 {
2320 nRead = aTempInput->readBytes ( aSequence, nBufferSize );
2321 if ( nRead < nBufferSize )
2322 {
2323 Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead );
2324 rOutStream->writeBytes ( aTempBuf );
2325 }
2326 else
2327 rOutStream->writeBytes ( aSequence );
2328 }
2329 while ( nRead == nBufferSize );
2330
2331 // remove temporary file
2332 if ( pImpl->pTempFile )
2333 {
2334 pImpl->pTempFile->EnableKillingFile();
2335 pImpl->pTempFile.reset();
2336 }
2337 }
2338 catch( const Exception& )
2339 {}
2340 }
2341 }
2342 else
2343 {
2344 SAL_WARN( "sfx.doc", "Illegal Output stream parameter!" );
2346 }
2347
2348 // free the reference
2349 if ( pImpl->m_pSet )
2350 pImpl->m_pSet->ClearItem( SID_OUTPUTSTREAM );
2351
2352 return;
2353 }
2354
2355 GetContent();
2356 if ( !pImpl->aContent.get().is() )
2357 {
2358 pImpl->m_eError = ERRCODE_IO_NOTEXISTS;
2359 return;
2360 }
2361
2362 INetURLObject aDest( GetURLObject() );
2363
2364 // source is the temp file written so far
2365 INetURLObject aSource( aNameURL );
2366
2367 // a special case, an interaction handler should be used for
2368 // authentication in case it is available
2369 Reference< css::ucb::XCommandEnvironment > xComEnv;
2370 bool bForceInteractionHandler = GetURLObject().isAnyKnownWebDAVScheme();
2371 Reference< css::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler(bForceInteractionHandler);
2372 if (xInteractionHandler.is())
2373 xComEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler,
2374 Reference< css::ucb::XProgressHandler >() );
2375
2376 OUString aDestURL( aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
2377
2378 if ( comphelper::isFileUrl( aDestURL ) || !aDest.removeSegment() )
2379 {
2380 TransactedTransferForFS_Impl( aSource, aDest, xComEnv );
2381
2382 if (!pImpl->m_bDisableFileSync)
2383 {
2384 // Hideous - no clean way to do this, so we re-open the file just to fsync it
2385 osl::File aFile( aDestURL );
2386 if ( aFile.open( osl_File_OpenFlag_Write ) == osl::FileBase::E_None )
2387 {
2388 aFile.sync();
2389 SAL_INFO( "sfx.doc", "fsync'd saved file '" << aDestURL << "'" );
2390 aFile.close();
2391 }
2392 }
2393 }
2394 else
2395 {
2396 // create content for the parent folder and call transfer on that content with the source content
2397 // and the destination file name as parameters
2398 ::ucbhelper::Content aSourceContent;
2399 ::ucbhelper::Content aTransferContent;
2400
2401 ::ucbhelper::Content aDestContent;
2402 (void)::ucbhelper::Content::create( aDestURL, xComEnv, comphelper::getProcessComponentContext(), aDestContent );
2403 // For checkin, we need the object URL, not the parent folder:
2404 if ( !IsInCheckIn( ) )
2405 {
2406 // Get the parent URL from the XChild if possible: why would the URL necessarily have
2407 // a hierarchical path? It's not always the case for CMIS.
2408 Reference< css::container::XChild> xChild( aDestContent.get(), uno::UNO_QUERY );
2409 OUString sParentUrl;
2410 if ( xChild.is( ) )
2411 {
2412 Reference< css::ucb::XContent > xParent( xChild->getParent( ), uno::UNO_QUERY );
2413 if ( xParent.is( ) )
2414 {
2415 sParentUrl = xParent->getIdentifier( )->getContentIdentifier();
2416 }
2417 }
2418
2419 if ( sParentUrl.isEmpty() )
2421 // adjust to above aDest.removeSegment()
2422 else
2423 aDestURL = sParentUrl;
2424 }
2425
2426 // LongName wasn't defined anywhere, only used here... get the Title instead
2427 // as it's less probably empty
2428 OUString aFileName;
2429 Any aAny = aDestContent.getPropertyValue("Title");
2430 aAny >>= aFileName;
2431 aAny = aDestContent.getPropertyValue( "ObjectId" );
2432 OUString sObjectId;
2433 aAny >>= sObjectId;
2434 if ( aFileName.isEmpty() )
2436
2437 try
2438 {
2439 aTransferContent = ::ucbhelper::Content( aDestURL, xComEnv, comphelper::getProcessComponentContext() );
2440 }
2441 catch (const css::ucb::ContentCreationException& ex)
2442 {
2443 pImpl->m_eError = ERRCODE_IO_GENERAL;
2444 if (
2445 (ex.eError == css::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
2446 (ex.eError == css::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
2447 )
2448 {
2449 pImpl->m_eError = ERRCODE_IO_NOTEXISTSPATH;
2450 }
2451 }
2452 catch (const css::uno::Exception&)
2453 {
2454 pImpl->m_eError = ERRCODE_IO_GENERAL;
2455 }
2456
2457 if ( !pImpl->m_eError || pImpl->m_eError.IsWarning() )
2458 {
2459 // free resources, otherwise the transfer may fail
2460 if ( pImpl->xStorage.is() )
2461 CloseStorage();
2462
2464
2466
2467 // check for external parameters that may customize the handling of NameClash situations
2468 const SfxBoolItem* pOverWrite = SfxItemSet::GetItem<SfxBoolItem>(GetItemSet(), SID_OVERWRITE, false);
2469 sal_Int32 nNameClash;
2470 if ( pOverWrite && !pOverWrite->GetValue() )
2471 // argument says: never overwrite
2472 nNameClash = NameClash::ERROR;
2473 else
2474 // default is overwrite existing files
2475 nNameClash = NameClash::OVERWRITE;
2476
2477 try
2478 {
2479 OUString aMimeType = pImpl->getFilterMimeType();
2481 bool bMajor = false;
2482 OUString sComment;
2483 if ( IsInCheckIn( ) )
2484 {
2485 eOperation = ::ucbhelper::InsertOperation::Checkin;
2486 const SfxBoolItem* pMajor = SfxItemSet::GetItem<SfxBoolItem>(GetItemSet(), SID_DOCINFO_MAJOR, false);
2487 bMajor = pMajor && pMajor->GetValue( );
2488 const SfxStringItem* pComments = SfxItemSet::GetItem<SfxStringItem>(GetItemSet(), SID_DOCINFO_COMMENTS, false);
2489 if ( pComments )
2490 sComment = pComments->GetValue( );
2491 }
2492 OUString sResultURL;
2493 aTransferContent.transferContent(
2494 aSourceContent, eOperation,
2495 aFileName, nNameClash, aMimeType, bMajor, sComment,
2496 &sResultURL, sObjectId );
2497
2498 if ( !sResultURL.isEmpty( ) ) // Likely to happen only for checkin
2499 SwitchDocumentToFile( sResultURL );
2500 try
2501 {
2502 if ( GetURLObject().isAnyKnownWebDAVScheme() &&
2504 {
2505 // tdf#95272 try to re-issue a lock command when a new file is created.
2506 // This may be needed because some WebDAV servers fail to implement the
2507 // 'LOCK on unallocated reference', see issue comment:
2508 // <https://bugs.documentfoundation.org/show_bug.cgi?id=95792#c8>
2509 // and specification at:
2510 // <http://tools.ietf.org/html/rfc4918#section-7.3>
2511 // If the WebDAV resource is already locked by this LO instance, nothing will
2512 // happen, e.g. the LOCK method will not be sent to the server.
2514 aLockContent.lock();
2515 }
2516 }
2517 catch ( css::uno::Exception & )
2518 {
2519 TOOLS_WARN_EXCEPTION( "sfx.doc", "LOCK not working while re-issuing it" );
2520 }
2521 }
2522 catch ( const css::ucb::CommandAbortedException& )
2523 {
2524 pImpl->m_eError = ERRCODE_ABORT;
2525 }
2526 catch ( const css::ucb::CommandFailedException& )
2527 {
2528 pImpl->m_eError = ERRCODE_ABORT;
2529 }
2530 catch ( const css::ucb::InteractiveIOException& r )
2531 {
2532 if ( r.Code == IOErrorCode_ACCESS_DENIED )
2533 pImpl->m_eError = ERRCODE_IO_ACCESSDENIED;
2534 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2535 pImpl->m_eError = ERRCODE_IO_NOTEXISTS;
2536 else if ( r.Code == IOErrorCode_CANT_READ )
2537 pImpl->m_eError = ERRCODE_IO_CANTREAD;
2538 else
2539 pImpl->m_eError = ERRCODE_IO_GENERAL;
2540 }
2541 catch ( const css::uno::Exception& )
2542 {
2543 pImpl->m_eError = ERRCODE_IO_GENERAL;
2544 }
2545
2546 // do not switch from temporary file in case of nonfile protocol
2547 }
2548 }
2549
2550 if ( ( !pImpl->m_eError || pImpl->m_eError.IsWarning() ) && !pImpl->pTempFile )
2551 {
2552 // without a TempFile the physical and logical name should be the same after successful transfer
2553 if (osl::FileBase::getSystemPathFromFileURL(
2554 GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), pImpl->m_aName )
2555 != osl::FileBase::E_None)
2556 {
2557 pImpl->m_aName.clear();
2558 }
2559 pImpl->m_bSalvageMode = false;
2560 }
2561}
2562
2563
2564void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent,
2565 std::u16string_view aPrefix,
2566 std::u16string_view aExtension,
2567 const OUString& aDestDir )
2568{
2569 if ( !pImpl->m_aBackupURL.isEmpty() )
2570 return; // the backup was done already
2571
2572 ::utl::TempFileNamed aTransactTemp( aPrefix, true, aExtension, &aDestDir );
2573
2574 INetURLObject aBackObj( aTransactTemp.GetURL() );
2576
2577 Reference < css::ucb::XCommandEnvironment > xDummyEnv;
2578 ::ucbhelper::Content aBackupCont;
2579 if( ::ucbhelper::Content::create( aDestDir, xDummyEnv, comphelper::getProcessComponentContext(), aBackupCont ) )
2580 {
2581 try
2582 {
2583 OUString sMimeType = pImpl->getFilterMimeType();
2584 aBackupCont.transferContent( aOriginalContent,
2586 aBackupName,
2587 NameClash::OVERWRITE,
2588 sMimeType );
2589 pImpl->m_aBackupURL = aBackObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
2590 pImpl->m_bRemoveBackup = true;
2591 }
2592 catch( const Exception& )
2593 {}
2594 }
2595
2596 if ( pImpl->m_aBackupURL.isEmpty() )
2597 aTransactTemp.EnableKillingFile();
2598}
2599
2600
2601void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent )
2602{
2603 if ( !pImpl->m_aBackupURL.isEmpty() )
2604 return; // the backup was done already
2605
2606 OUString aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT,
2607 true,
2609
2610 sal_Int32 nPrefixLen = aFileName.lastIndexOf( '.' );
2611 OUString aPrefix = ( nPrefixLen == -1 ) ? aFileName : aFileName.copy( 0, nPrefixLen );
2612 OUString aExtension = ( nPrefixLen == -1 ) ? OUString() : aFileName.copy( nPrefixLen );
2613 OUString aBakDir = SvtPathOptions().GetBackupPath();
2614
2615 // create content for the parent folder ( = backup folder )
2616 ::ucbhelper::Content aContent;
2617 Reference < css::ucb::XCommandEnvironment > xEnv;
2618 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
2619 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aBakDir );
2620
2621 if ( !pImpl->m_aBackupURL.isEmpty() )
2622 return;
2623
2624 // the copying to the backup catalog failed ( for example because
2625 // of using an encrypted partition as target catalog )
2626 // since the user did not specify to make backup explicitly
2627 // office should try to make backup in another place,
2628 // target catalog does not look bad for this case ( and looks
2629 // to be the only way for encrypted partitions )
2630
2631 INetURLObject aDest = GetURLObject();
2632 if ( aDest.removeSegment() )
2633 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
2634}
2635
2636
2638{
2639 // source file name is the logical name of this medium
2640 INetURLObject aSource( GetURLObject() );
2641
2642 // there is nothing to backup in case source file does not exist
2643 if ( !::utl::UCBContentHelper::IsDocument( aSource.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
2644 return;
2645
2646 bool bSuccess = false;
2647
2648 // get path for backups
2649 OUString aBakDir = SvtPathOptions().GetBackupPath();
2650 if( !aBakDir.isEmpty() )
2651 {
2652 // create content for the parent folder ( = backup folder )
2653 ::ucbhelper::Content aContent;
2654 Reference < css::ucb::XCommandEnvironment > xEnv;
2655 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
2656 {
2657 // save as ".bak" file
2658 INetURLObject aDest( aBakDir );
2659 aDest.insertName( aSource.getName() );
2660 aDest.setExtension( u"bak" );
2662
2663 // create a content for the source file
2664 ::ucbhelper::Content aSourceContent;
2666 {
2667 try
2668 {
2669 // do the transfer ( copy source file to backup dir )
2670 OUString sMimeType = pImpl->getFilterMimeType();
2671 aContent.transferContent( aSourceContent,
2673 aFileName,
2674 NameClash::OVERWRITE,
2675 sMimeType );
2676 pImpl->m_aBackupURL = aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE );
2677 pImpl->m_bRemoveBackup = false;
2678 bSuccess = true;
2679 }
2680 catch ( const css::uno::Exception& )
2681 {
2682 }
2683 }
2684 }
2685 }
2686
2687 if ( !bSuccess )
2688 {
2690 }
2691}
2692
2693
2695{
2696 if( pImpl->m_bRemoveBackup )
2697 {
2698 // currently a document is always stored in a new medium,
2699 // thus if a backup can not be removed the backup URL should not be cleaned
2700 if ( !pImpl->m_aBackupURL.isEmpty() )
2701 {
2702 if ( ::utl::UCBContentHelper::Kill( pImpl->m_aBackupURL ) )
2703 {
2704 pImpl->m_bRemoveBackup = false;
2705 pImpl->m_aBackupURL.clear();
2706 }
2707 else
2708 {
2709
2710 SAL_WARN( "sfx.doc", "Couldn't remove backup file!");
2711 }
2712 }
2713 }
2714 else
2715 pImpl->m_aBackupURL.clear();
2716}
2717
2718
2720{
2721 if ( GetURLObject().GetProtocol() != INetProtocol::File
2722 || pImpl->m_xLockingStream.is() )
2723 return;
2724
2725 const SfxUnoAnyItem* pWriteStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_STREAM, false);
2726 if ( pWriteStreamItem )
2727 pWriteStreamItem->GetValue() >>= pImpl->m_xLockingStream;
2728
2729 if ( pImpl->m_xLockingStream.is() )
2730 return;
2731
2732 // open the original document
2733 uno::Sequence< beans::PropertyValue > xProps;
2734 TransformItems( SID_OPENDOC, *GetItemSet(), xProps );
2735 utl::MediaDescriptor aMedium( xProps );
2736
2737 aMedium.addInputStreamOwnLock();
2738
2739 uno::Reference< io::XInputStream > xInputStream;
2740 aMedium[utl::MediaDescriptor::PROP_STREAM] >>= pImpl->m_xLockingStream;
2741 aMedium[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream;
2742
2743 if ( !pImpl->pTempFile && pImpl->m_aName.isEmpty() )
2744 {
2745 // the medium is still based on the original file, it makes sense to initialize the streams
2746 if ( pImpl->m_xLockingStream.is() )
2747 pImpl->xStream = pImpl->m_xLockingStream;
2748
2749 if ( xInputStream.is() )
2750 pImpl->xInputStream = xInputStream;
2751
2752 if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
2753 pImpl->xInputStream = pImpl->xStream->getInputStream();
2754 }
2755}
2756
2757
2759{
2760 if ( pImpl->m_pInStream
2761 && (!pImpl->bIsTemp || pImpl->xInputStream.is() || pImpl->m_xInputStreamToLoadFrom.is() || pImpl->xStream.is() || pImpl->m_xLockingStream.is() ) )
2762 return;
2763
2764 pImpl->bDownloadDone = false;
2765 Reference< css::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
2766
2767 //TODO/MBA: need support for SID_STREAM
2768 const SfxUnoAnyItem* pWriteStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_STREAM, false);
2769 const SfxUnoAnyItem* pInStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_INPUTSTREAM, false);
2770 if ( pWriteStreamItem )
2771 {
2772 pWriteStreamItem->GetValue() >>= pImpl->xStream;
2773
2774 if ( pInStreamItem )
2775 pInStreamItem->GetValue() >>= pImpl->xInputStream;
2776
2777 if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
2778 pImpl->xInputStream = pImpl->xStream->getInputStream();
2779 }
2780 else if ( pInStreamItem )
2781 {
2782 pInStreamItem->GetValue() >>= pImpl->xInputStream;
2783 }
2784 else
2785 {
2786 uno::Sequence < beans::PropertyValue > xProps;
2787 OUString aFileName;
2788 if (!pImpl->m_aName.isEmpty())
2789 {
2790 if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aFileName )
2791 != osl::FileBase::E_None )
2792 {
2793 SAL_WARN( "sfx.doc", "Physical name not convertible!");
2794 }
2795 }
2796 else
2797 aFileName = GetName();
2798
2799 // in case the temporary file exists the streams should be initialized from it,
2800 // but the original MediaDescriptor should not be changed
2801 bool bFromTempFile = ( pImpl->pTempFile != nullptr );
2802
2803 if ( !bFromTempFile )
2804 {
2805 GetItemSet()->Put( SfxStringItem( SID_FILE_NAME, aFileName ) );
2806 if( !(pImpl->m_nStorOpenMode & StreamMode::WRITE) )
2807 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
2808 if (xInteractionHandler.is())
2809 GetItemSet()->Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, Any(xInteractionHandler) ) );
2810 }
2811
2812 if ( pImpl->m_xInputStreamToLoadFrom.is() )
2813 {
2814 pImpl->xInputStream = pImpl->m_xInputStreamToLoadFrom;
2815 if (pImpl->m_bInputStreamIsReadOnly)
2816 GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
2817 }
2818 else
2819 {
2820 TransformItems( SID_OPENDOC, *GetItemSet(), xProps );
2821 utl::MediaDescriptor aMedium( xProps );
2822
2823 if ( pImpl->m_xLockingStream.is() && !bFromTempFile )
2824 {
2825 // the medium is not based on the temporary file, so the original stream can be used
2826 pImpl->xStream = pImpl->m_xLockingStream;
2827 }
2828 else
2829 {
2830 if ( bFromTempFile )
2831 {
2832 aMedium[utl::MediaDescriptor::PROP_URL] <<= aFileName;
2833 aMedium.erase( utl::MediaDescriptor::PROP_READONLY );
2834 aMedium.addInputStream();
2835 }
2836 else if ( GetURLObject().GetProtocol() == INetProtocol::File )
2837 {
2838 // use the special locking approach only for file URLs
2839 aMedium.addInputStreamOwnLock();
2840 }
2841 else
2842 {
2843 // add a check for protocol, if it's http or https or provide webdav then add
2844 // the interaction handler to be used by the authentication dialog
2845 if ( GetURLObject().isAnyKnownWebDAVScheme() )
2846 {
2848 }
2849 aMedium.addInputStream();
2850 }
2851 // the ReadOnly property set in aMedium is ignored
2852 // the check is done in LockOrigFileOnDemand() for file and non-file URLs
2853
2854 //TODO/MBA: what happens if property is not there?!
2855 aMedium[utl::MediaDescriptor::PROP_STREAM] >>= pImpl->xStream;
2856 aMedium[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= pImpl->xInputStream;
2857 }
2858
2859 GetContent();
2860 if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
2861 pImpl->xInputStream = pImpl->xStream->getInputStream();
2862 }
2863
2864 if ( !bFromTempFile )
2865 {
2866 //TODO/MBA: need support for SID_STREAM
2867 if ( pImpl->xStream.is() )
2868 GetItemSet()->Put( SfxUnoAnyItem( SID_STREAM, Any( pImpl->xStream ) ) );
2869
2870 GetItemSet()->Put( SfxUnoAnyItem( SID_INPUTSTREAM, Any( pImpl->xInputStream ) ) );
2871 }
2872 }
2873
2874 //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor
2875 if ( !GetError() && !pImpl->xStream.is() && !pImpl->xInputStream.is() )
2877
2878 if ( !GetError() && !pImpl->m_pInStream )
2879 {
2880 if ( pImpl->xStream.is() )
2881 pImpl->m_pInStream = utl::UcbStreamHelper::CreateStream( pImpl->xStream );
2882 else if ( pImpl->xInputStream.is() )
2883 pImpl->m_pInStream = utl::UcbStreamHelper::CreateStream( pImpl->xInputStream );
2884 }
2885
2886 pImpl->bDownloadDone = true;
2887 pImpl->aDoneLink.ClearPendingCall();
2888 ErrCode nError = GetError();
2889 pImpl->aDoneLink.Call( reinterpret_cast<void*>(sal_uInt32(nError)) );
2890}
2891
2893{
2894 return pImpl->m_bRemote;
2895}
2896
2898{
2899 pImpl->bUpdatePickList = bVal;
2900}
2901
2903{
2904 return pImpl->bUpdatePickList;
2905}
2906
2907void SfxMedium::SetLongName(const OUString &rName)
2908{
2909 pImpl->m_aLongName = rName;
2910}
2911
2912const OUString& SfxMedium::GetLongName() const
2913{
2914 return pImpl->m_aLongName;
2915}
2916
2918{
2919 pImpl->aDoneLink = rLink;
2920}
2921
2923{
2924 SetDoneLink( aLink );
2925 GetInStream();
2926 if ( pImpl->m_pInStream && !aLink.IsSet() )
2927 {
2928 while( !pImpl->bDownloadDone && !Application::IsQuit())
2930 }
2931}
2932
2933
2935/* [Description]
2936 Includes a valid:: sun:: com:: star:: util:: URL (If a file name was
2937 previously in there) in the logical name and if available sets the
2938 physical name as the file name.
2939 */
2940
2941{
2942 Reference< XOutputStream > rOutStream;
2943
2944 // TODO/LATER: handle lifetime of storages
2945 pImpl->bDisposeStorage = false;
2946
2947 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_DOC_SALVAGE, false);
2948 if ( pSalvageItem && pSalvageItem->GetValue().isEmpty() )
2949 {
2950 pSalvageItem = nullptr;
2951 pImpl->m_pSet->ClearItem( SID_DOC_SALVAGE );
2952 }
2953
2954 if (!pImpl->m_aLogicName.isEmpty())
2955 {
2956 INetURLObject aUrl( pImpl->m_aLogicName );
2957 INetProtocol eProt = aUrl.GetProtocol();
2958 if ( eProt == INetProtocol::NotValid )
2959 {
2960 SAL_WARN( "sfx.doc", "URL <" << pImpl->m_aLogicName << "> with unknown protocol" );
2961 }
2962 else
2963 {
2964 if ( aUrl.HasMark() )
2965 {
2966 std::unique_lock<std::recursive_mutex> chkEditLock;
2967 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
2968 chkEditLock = std::unique_lock<std::recursive_mutex>(
2969 *(pImpl->m_pCheckEditableWorkerMutex));
2971 if (chkEditLock.owns_lock())
2972 chkEditLock.unlock();
2973 GetItemSet()->Put( SfxStringItem( SID_JUMPMARK, aUrl.GetMark() ) );
2974 }
2975
2976 // try to convert the URL into a physical name - but never change a physical name
2977 // physical name may be set if the logical name is changed after construction
2978 if ( pImpl->m_aName.isEmpty() )
2979 osl::FileBase::getSystemPathFromFileURL( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), pImpl->m_aName );
2980 else
2981 {
2982 DBG_ASSERT( pSalvageItem, "Suspicious change of logical name!" );
2983 }
2984 }
2985 }
2986
2987 if ( pSalvageItem )
2988 {
2989 std::unique_lock<std::recursive_mutex> chkEditLock;
2990 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
2991 chkEditLock
2992 = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
2993 pImpl->m_aLogicName = pSalvageItem->GetValue();
2994 pImpl->m_pURLObj.reset();
2995 if (chkEditLock.owns_lock())
2996 chkEditLock.unlock();
2997 pImpl->m_bSalvageMode = true;
2998 }
2999
3000 // in case output stream is by mistake here
3001 // clear the reference
3002 const SfxUnoAnyItem* pOutStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_OUTPUTSTREAM, false);
3003 if( pOutStreamItem
3004 && ( !( pOutStreamItem->GetValue() >>= rOutStream )
3005 || !pImpl->m_aLogicName.startsWith("private:stream")) )
3006 {
3007 pImpl->m_pSet->ClearItem( SID_OUTPUTSTREAM );
3008 SAL_WARN( "sfx.doc", "Unexpected Output stream parameter!" );
3009 }
3010
3011 if (!pImpl->m_aLogicName.isEmpty())
3012 {
3013 // if the logic name is set it should be set in MediaDescriptor as well
3014 const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3015 if ( !pFileNameItem )
3016 {
3017 // let the ItemSet be created if necessary
3018 GetItemSet()->Put(
3020 SID_FILE_NAME, INetURLObject( pImpl->m_aLogicName ).GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
3021 }
3022 }
3023
3025
3026 osl::DirectoryItem item;
3027 if (osl::DirectoryItem::get(GetName(), item) == osl::FileBase::E_None) {
3028 osl::FileStatus stat(osl_FileStatus_Mask_Attributes);
3029 if (item.getFileStatus(stat) == osl::FileBase::E_None
3030 && stat.isValid(osl_FileStatus_Mask_Attributes))
3031 {
3032 if ((stat.getAttributes() & osl_File_Attribute_ReadOnly) != 0)
3033 {
3034 pImpl->m_bOriginallyReadOnly = true;
3035 }
3036 }
3037 }
3038}
3039
3040
3042{
3043 Init_Impl();
3044}
3045
3046
3048{
3049 pImpl->bAllowDefaultIntHdl = bUse;
3050}
3051
3052
3053css::uno::Reference< css::task::XInteractionHandler >
3055{
3056 // if interaction isn't allowed explicitly ... return empty reference!
3057 if ( !bGetAlways && !pImpl->bUseInteractionHandler )
3058 return css::uno::Reference< css::task::XInteractionHandler >();
3059
3060 // search a possible existing handler inside cached item set
3061 if ( pImpl->m_pSet )
3062 {
3063 css::uno::Reference< css::task::XInteractionHandler > xHandler;
3064 const SfxUnoAnyItem* pHandler = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_INTERACTIONHANDLER, false);
3065 if ( pHandler && (pHandler->GetValue() >>= xHandler) && xHandler.is() )
3066 return xHandler;
3067 }
3068
3069 // if default interaction isn't allowed explicitly ... return empty reference!
3070 if ( !bGetAlways && !pImpl->bAllowDefaultIntHdl )
3071 return css::uno::Reference< css::task::XInteractionHandler >();
3072
3073 // otherwise return cached default handler ... if it exist.
3074 if ( pImpl->xInteraction.is() )
3075 return pImpl->xInteraction;
3076
3077 // create default handler and cache it!
3078 Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
3079 pImpl->xInteraction.set(
3080 task::InteractionHandler::createWithParent(xContext, nullptr), UNO_QUERY_THROW );
3081 return pImpl->xInteraction;
3082}
3083
3084void SfxMedium::SetFilter( const std::shared_ptr<const SfxFilter>& pFilter )
3085{
3086 pImpl->m_pFilter = pFilter;
3087}
3088
3089const std::shared_ptr<const SfxFilter>& SfxMedium::GetFilter() const
3090{
3091 return pImpl->m_pFilter;
3092}
3093
3094sal_uInt32 SfxMedium::CreatePasswordToModifyHash( std::u16string_view aPasswd, bool bWriter )
3095{
3096 sal_uInt32 nHash = 0;
3097
3098 if ( !aPasswd.empty() )
3099 {
3100 if ( bWriter )
3101 {
3103 }
3104 else
3105 {
3106 rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
3107 nHash = ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd, nEncoding );
3108 }
3109 }
3110
3111 return nHash;
3112}
3113
3114
3115void SfxMedium::Close(bool bInDestruction)
3116{
3117 if ( pImpl->xStorage.is() )
3118 {
3119 CloseStorage();
3120 }
3121
3122 CloseStreams_Impl(bInDestruction);
3123
3124 UnlockFile( false );
3125}
3126
3128{
3129 if ( pImpl->xStorage.is() )
3130 {
3131 CloseStorage();
3132 }
3133
3135
3136 UnlockFile( true );
3137}
3138
3139void SfxMedium::DisableUnlockWebDAV( bool bDisableUnlockWebDAV )
3140{
3141 pImpl->m_bDisableUnlockWebDAV = bDisableUnlockWebDAV;
3142}
3143
3144void SfxMedium::DisableFileSync(bool bDisableFileSync)
3145{
3146 pImpl->m_bDisableFileSync = bDisableFileSync;
3147}
3148
3149void SfxMedium::UnlockFile( bool bReleaseLockStream )
3150{
3151#if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
3152 (void) bReleaseLockStream;
3153#else
3154 // check if webdav
3156 {
3157 // do nothing if WebDAV locking if disabled
3158 // (shouldn't happen because we already skipped locking,
3159 // see LockOrigFileOnDemand, but just in case ...)
3160 if (!IsWebDAVLockingUsed())
3161 return;
3162
3163 if ( pImpl->m_bLocked )
3164 {
3165 // an interaction handler should be used for authentication, if needed
3166 try {
3167 uno::Reference< css::task::XInteractionHandler > xHandler = GetInteractionHandler( true );
3168 uno::Reference< css::ucb::XCommandEnvironment > xComEnv = new ::ucbhelper::CommandEnvironment( xHandler,
3169 Reference< css::ucb::XProgressHandler >() );
3171 pImpl->m_bLocked = false;
3172 //check if WebDAV unlock was explicitly disabled
3173 if ( !pImpl->m_bDisableUnlockWebDAV )
3174 aContentToUnlock.unlock();
3175 }
3176 catch ( uno::Exception& )
3177 {
3178 TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
3179 }
3180 }
3181 return;
3182 }
3183
3184 if ( pImpl->m_xLockingStream.is() )
3185 {
3186 if ( bReleaseLockStream )
3187 {
3188 try
3189 {
3190 uno::Reference< io::XInputStream > xInStream = pImpl->m_xLockingStream->getInputStream();
3191 uno::Reference< io::XOutputStream > xOutStream = pImpl->m_xLockingStream->getOutputStream();
3192 if ( xInStream.is() )
3193 xInStream->closeInput();
3194 if ( xOutStream.is() )
3195 xOutStream->closeOutput();
3196 }
3197 catch( const uno::Exception& )
3198 {}
3199 }
3200
3201 pImpl->m_xLockingStream.clear();
3202 }
3203
3204 if ( !pImpl->m_bLocked )
3205 return;
3206
3207 ::svt::DocumentLockFile aLockFile( pImpl->m_aLogicName );
3208
3209 try
3210 {
3211 pImpl->m_bLocked = false;
3212 // TODO/LATER: A warning could be shown in case the file is not the own one
3213 aLockFile.RemoveFile();
3214 }
3215 catch( const io::WrongFormatException& )
3216 {
3217 try
3218 {
3219 // erase the empty or corrupt file
3220 aLockFile.RemoveFileDirectly();
3221 }
3222 catch( const uno::Exception& )
3223 {}
3224 }
3225 catch( const uno::Exception& )
3226 {}
3227
3228 if(!pImpl->m_bMSOLockFileCreated)
3229 return;
3230
3231 ::svt::MSODocumentLockFile aMSOLockFile( pImpl->m_aLogicName );
3232
3233 try
3234 {
3235 pImpl->m_bLocked = false;
3236 // TODO/LATER: A warning could be shown in case the file is not the own one
3237 aMSOLockFile.RemoveFile();
3238 }
3239 catch( const io::WrongFormatException& )
3240 {
3241 try
3242 {
3243 // erase the empty or corrupt file
3244 aMSOLockFile.RemoveFileDirectly();
3245 }
3246 catch( const uno::Exception& )
3247 {}
3248 }
3249 catch( const uno::Exception& )
3250 {}
3251 pImpl->m_bMSOLockFileCreated = false;
3252#endif
3253}
3254
3256{
3258
3259 uno::Reference< io::XInputStream > xInToClose = pImpl->xInputStream;
3260 uno::Reference< io::XOutputStream > xOutToClose;
3261 if ( pImpl->xStream.is() )
3262 {
3263 xOutToClose = pImpl->xStream->getOutputStream();
3264
3265 // if the locking stream is closed here the related member should be cleaned
3266 if ( pImpl->xStream == pImpl->m_xLockingStream )
3267 pImpl->m_xLockingStream.clear();
3268 }
3269
3270 // The probably existing SvStream wrappers should be closed first
3272
3273 // in case of salvage mode the storage is based on the streams
3274 if ( pImpl->m_bSalvageMode )
3275 return;
3276
3277 try
3278 {
3279 if ( xInToClose.is() )
3280 xInToClose->closeInput();
3281 if ( xOutToClose.is() )
3282 xOutToClose->closeOutput();
3283 }
3284 catch ( const uno::Exception& )
3285 {
3286 }
3287}
3288
3289
3290void SfxMedium::CloseStreams_Impl(bool bInDestruction)
3291{
3292 CloseInStream_Impl(bInDestruction);
3294
3295 if ( pImpl->m_pSet )
3296 pImpl->m_pSet->ClearItem( SID_CONTENT );
3297
3298 pImpl->aContent = ::ucbhelper::Content();
3299}
3300
3301
3303{
3304 INetURLObject aObj( GetName() );
3305 switch( aObj.GetProtocol() )
3306 {
3307 case INetProtocol::Ftp:
3308 case INetProtocol::Http:
3309 case INetProtocol::Https:
3310 pImpl->m_bRemote = true;
3311 break;
3312 default:
3313 pImpl->m_bRemote = GetName().startsWith("private:msgid");
3314 break;
3315 }
3316
3317 // As files that are written to the remote transmission must also be able
3318 // to be read.
3319 if (pImpl->m_bRemote)
3320 pImpl->m_nStorOpenMode |= StreamMode::READ;
3321}
3322
3323
3324void SfxMedium::SetName( const OUString& aNameP, bool bSetOrigURL )
3325{
3326 if (pImpl->aOrigURL.isEmpty())
3327 pImpl->aOrigURL = pImpl->m_aLogicName;
3328 if( bSetOrigURL )
3329 pImpl->aOrigURL = aNameP;
3330 std::unique_lock<std::recursive_mutex> chkEditLock;
3331 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
3332 chkEditLock = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
3333 pImpl->m_aLogicName = aNameP;
3334 pImpl->m_pURLObj.reset();
3335 if (chkEditLock.owns_lock())
3336 chkEditLock.unlock();
3337 pImpl->aContent = ::ucbhelper::Content();
3338 Init_Impl();
3339}
3340
3341
3342const OUString& SfxMedium::GetOrigURL() const
3343{
3344 return pImpl->aOrigURL.isEmpty() ? pImpl->m_aLogicName : pImpl->aOrigURL;
3345}
3346
3347
3348void SfxMedium::SetPhysicalName_Impl( const OUString& rNameP )
3349{
3350 if ( rNameP != pImpl->m_aName )
3351 {
3352 pImpl->pTempFile.reset();
3353
3354 if ( !pImpl->m_aName.isEmpty() || !rNameP.isEmpty() )
3355 pImpl->aContent = ::ucbhelper::Content();
3356
3357 pImpl->m_aName = rNameP;
3358 pImpl->m_bTriedStorage = false;
3359 pImpl->bIsStorage = false;
3360 }
3361}
3362
3364{
3365 bool bUseInteractionHandler = pImpl->bUseInteractionHandler;
3366 pImpl->bUseInteractionHandler = false;
3368 pImpl->bUseInteractionHandler = bUseInteractionHandler;
3369}
3370
3372{
3373 // do not use temporary file for reopen and in case of success throw the temporary file away
3374 bool bUseInteractionHandler = pImpl->bUseInteractionHandler;
3375 pImpl->bUseInteractionHandler = false;
3376
3377 std::unique_ptr<::utl::TempFileNamed> pTmpFile;
3378 if ( pImpl->pTempFile )
3379 {
3380 pTmpFile = std::move(pImpl->pTempFile);
3381 pImpl->m_aName.clear();
3382 }
3383
3385
3386 if ( GetError() )
3387 {
3388 if ( pImpl->pTempFile )
3389 {
3390 pImpl->pTempFile->EnableKillingFile();
3391 pImpl->pTempFile.reset();
3392 }
3393 pImpl->pTempFile = std::move( pTmpFile );
3394 if ( pImpl->pTempFile )
3395 pImpl->m_aName = pImpl->pTempFile->GetFileName();
3396 }
3397 else if (pTmpFile)
3398 {
3399 pTmpFile->EnableKillingFile();
3400 pTmpFile.reset();
3401 }
3402
3403 pImpl->bUseInteractionHandler = bUseInteractionHandler;
3404}
3405
3406SfxMedium::SfxMedium(const OUString &rName, StreamMode nOpenMode, std::shared_ptr<const SfxFilter> pFilter, const std::shared_ptr<SfxItemSet>& pInSet) :
3407 pImpl(new SfxMedium_Impl)
3408{
3409 pImpl->m_pSet = pInSet;
3410 pImpl->m_pFilter = std::move(pFilter);
3411 pImpl->m_aLogicName = rName;
3412 pImpl->m_nStorOpenMode = nOpenMode;
3413 Init_Impl();
3414}
3415
3416SfxMedium::SfxMedium(const OUString &rName, const OUString &rReferer, StreamMode nOpenMode, std::shared_ptr<const SfxFilter> pFilter, const std::shared_ptr<SfxItemSet>& pInSet) :
3417 pImpl(new SfxMedium_Impl)
3418{
3419 pImpl->m_pSet = pInSet;
3420 SfxItemSet * s = GetItemSet();
3421 if (s->GetItem(SID_REFERER) == nullptr) {
3422 s->Put(SfxStringItem(SID_REFERER, rReferer));
3423 }
3424 pImpl->m_pFilter = std::move(pFilter);
3425 pImpl->m_aLogicName = rName;
3426 pImpl->m_nStorOpenMode = nOpenMode;
3427 Init_Impl();
3428}
3429
3430SfxMedium::SfxMedium( const uno::Sequence<beans::PropertyValue>& aArgs ) :
3431 pImpl(new SfxMedium_Impl)
3432{
3433 SfxAllItemSet *pParams = new SfxAllItemSet( SfxGetpApp()->GetPool() );
3434 pImpl->m_pSet.reset( pParams );
3435 TransformParameters( SID_OPENDOC, aArgs, *pParams );
3436 SetArgs(aArgs);
3437
3438 OUString aFilterProvider, aFilterName;
3439 {
3440 const SfxStringItem* pItem = nullptr;
3441 if ((pItem = pImpl->m_pSet->GetItemIfSet(SID_FILTER_PROVIDER)))
3442 aFilterProvider = pItem->GetValue();
3443
3444 if ((pItem = pImpl->m_pSet->GetItemIfSet(SID_FILTER_NAME)))
3445 aFilterName = pItem->GetValue();
3446 }
3447
3448 if (aFilterProvider.isEmpty())
3449 {
3450 // This is a conventional filter type.
3451 pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName( aFilterName );
3452 }
3453 else
3454 {
3455 // This filter is from an external provider such as orcus.
3456 pImpl->m_pCustomFilter = std::make_shared<SfxFilter>(aFilterProvider, aFilterName);
3457 pImpl->m_pFilter = pImpl->m_pCustomFilter;
3458 }
3459
3460 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_DOC_SALVAGE, false);
3461 if( pSalvageItem )
3462 {
3463 // QUESTION: there is some treatment of Salvage in Init_Impl; align!
3464 if ( !pSalvageItem->GetValue().isEmpty() )
3465 {
3466 // if a URL is provided in SalvageItem that means that the FileName refers to a temporary file
3467 // that must be copied here
3468
3469 const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3470 if (!pFileNameItem) throw uno::RuntimeException();
3471 OUString aNewTempFileURL = SfxMedium::CreateTempCopyWithExt( pFileNameItem->GetValue() );
3472 if ( !aNewTempFileURL.isEmpty() )
3473 {
3474 pImpl->m_pSet->Put( SfxStringItem( SID_FILE_NAME, aNewTempFileURL ) );
3475 pImpl->m_pSet->ClearItem( SID_INPUTSTREAM );
3476 pImpl->m_pSet->ClearItem( SID_STREAM );
3477 pImpl->m_pSet->ClearItem( SID_CONTENT );
3478 }
3479 else
3480 {
3481 SAL_WARN( "sfx.doc", "Can not create a new temporary file for crash recovery!" );
3482 }
3483 }
3484 }
3485
3486 const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
3487 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
3488 pImpl->m_bOriginallyLoadedReadOnly = true;
3489
3490 const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3491 if (!pFileNameItem) throw uno::RuntimeException();
3492 pImpl->m_aLogicName = pFileNameItem->GetValue();
3493 pImpl->m_nStorOpenMode = pImpl->m_bOriginallyLoadedReadOnly
3495 Init_Impl();
3496}
3497
3498void SfxMedium::SetArgs(const uno::Sequence<beans::PropertyValue>& rArgs)
3499{
3500 static constexpr OUStringLiteral sStream(u"Stream");
3501 static constexpr OUStringLiteral sInputStream(u"InputStream");
3502 comphelper::SequenceAsHashMap aArgsMap(rArgs);
3503 aArgsMap.erase(sStream);
3504 aArgsMap.erase(sInputStream);
3505 pImpl->m_aArgs = aArgsMap.getAsConstPropertyValueList();
3506}
3507
3508const uno::Sequence<beans::PropertyValue> & SfxMedium::GetArgs() const { return pImpl->m_aArgs; }
3509
3510SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const OUString& rBaseURL, const std::shared_ptr<SfxItemSet>& p ) :
3511 pImpl(new SfxMedium_Impl)
3512{
3513 OUString aType = SfxFilter::GetTypeFromStorage(rStor);
3514 pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4EA( aType );
3515 DBG_ASSERT( pImpl->m_pFilter, "No Filter for storage found!" );
3516
3517 Init_Impl();
3518 pImpl->xStorage = rStor;
3519 pImpl->bDisposeStorage = false;
3520
3521 // always take BaseURL first, could be overwritten by ItemSet
3522 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
3523 if ( p )
3524 GetItemSet()->Put( *p );
3525}
3526
3527
3528SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const OUString& rBaseURL, const OUString &rTypeName, const std::shared_ptr<SfxItemSet>& p ) :
3529 pImpl(new SfxMedium_Impl)
3530{
3531 pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4EA( rTypeName );
3532 DBG_ASSERT( pImpl->m_pFilter, "No Filter for storage found!" );
3533
3534 Init_Impl();
3535 pImpl->xStorage = rStor;
3536 pImpl->bDisposeStorage = false;
3537
3538 // always take BaseURL first, could be overwritten by ItemSet
3539 GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
3540 if ( p )
3541 GetItemSet()->Put( *p );
3542}
3543
3544// NOTE: should only be called on main thread
3546{
3548
3549 // if there is a requirement to clean the backup this is the last possibility to do it
3551
3552 Close(/*bInDestruction*/true);
3553
3554 if( !pImpl->bIsTemp || pImpl->m_aName.isEmpty() )
3555 return;
3556
3557 OUString aTemp;
3558 if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aTemp )
3559 != osl::FileBase::E_None )
3560 {
3561 SAL_WARN( "sfx.doc", "Physical name not convertible!");
3562 }
3563
3564 if ( !::utl::UCBContentHelper::Kill( aTemp ) )
3565 {
3566 SAL_WARN( "sfx.doc", "Couldn't remove temporary file!");
3567 }
3568}
3569
3570const OUString& SfxMedium::GetName() const
3571{
3572 return pImpl->m_aLogicName;
3573}
3574
3576{
3577 std::unique_lock<std::recursive_mutex> chkEditLock;
3578 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
3579 chkEditLock = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
3580
3581 if (!pImpl->m_pURLObj)
3582 {
3583 pImpl->m_pURLObj.reset( new INetURLObject( pImpl->m_aLogicName ) );
3584 pImpl->m_pURLObj->SetMark(u"");
3585 }
3586
3587 return *pImpl->m_pURLObj;
3588}
3589
3590void SfxMedium::SetExpired_Impl( const DateTime& rDateTime )
3591{
3592 pImpl->aExpireTime = rDateTime;
3593}
3594
3595
3597{
3598 return pImpl->aExpireTime.IsValidAndGregorian() && pImpl->aExpireTime < DateTime( DateTime::SYSTEM );
3599}
3600
3601
3603{
3604 return pImpl->wLoadTargetFrame;
3605}
3606
3607void SfxMedium::setStreamToLoadFrom(const css::uno::Reference<css::io::XInputStream>& xInputStream, bool bIsReadOnly )
3608{
3609 pImpl->m_xInputStreamToLoadFrom = xInputStream;
3610 pImpl->m_bInputStreamIsReadOnly = bIsReadOnly;
3611}
3612
3614{
3615 pImpl->wLoadTargetFrame = pFrame;
3616}
3617
3618
3619void SfxMedium::SetStorage_Impl( const uno::Reference < embed::XStorage >& rStor )
3620{
3621 pImpl->xStorage = rStor;
3622}
3623
3624
3626{
3627 // this method *must* return an ItemSet, returning NULL can cause crashes
3628 if (!pImpl->m_pSet)
3629 pImpl->m_pSet = std::make_shared<SfxAllItemSet>( SfxGetpApp()->GetPool() );
3630 return pImpl->m_pSet.get();
3631}
3632
3633
3635{
3636 if( !pImpl->xAttributes.is() )
3637 {
3638 pImpl->xAttributes = SvKeyValueIteratorRef( new SvKeyValueIterator );
3639
3640 if ( GetContent().is() )
3641 {
3642 try
3643 {
3644 Any aAny = pImpl->aContent.getPropertyValue("MediaType");
3645 OUString aContentType;
3646 aAny >>= aContentType;
3647
3648 pImpl->xAttributes->Append( SvKeyValue( "content-type", aContentType ) );
3649 }
3650 catch ( const css::uno::Exception& )
3651 {
3652 }
3653 }
3654 }
3655
3656 return pImpl->xAttributes.get();
3657}
3658
3659css::uno::Reference< css::io::XInputStream > const & SfxMedium::GetInputStream()
3660{
3661 if ( !pImpl->xInputStream.is() )
3663 return pImpl->xInputStream;
3664}
3665
3666const uno::Sequence < util::RevisionTag >& SfxMedium::GetVersionList( bool _bNoReload )
3667{
3668 // if the medium has no name, then this medium should represent a new document and can have no version info
3669 if ( ( !_bNoReload || !pImpl->m_bVersionsAlreadyLoaded ) && !pImpl->aVersions.hasElements() &&
3670 ( !pImpl->m_aName.isEmpty() || !pImpl->m_aLogicName.isEmpty() ) && GetStorage().is() )
3671 {
3672 uno::Reference < document::XDocumentRevisionListPersistence > xReader =
3673 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3674 try
3675 {
3676 pImpl->aVersions = xReader->load( GetStorage() );
3677 }
3678 catch ( const uno::Exception& )
3679 {
3680 }
3681 }
3682
3683 if ( !pImpl->m_bVersionsAlreadyLoaded )
3684 pImpl->m_bVersionsAlreadyLoaded = true;
3685
3686 return pImpl->aVersions;
3687}
3688
3689uno::Sequence < util::RevisionTag > SfxMedium::GetVersionList( const uno::Reference < embed::XStorage >& xStorage )
3690{
3691 uno::Reference < document::XDocumentRevisionListPersistence > xReader =
3692 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3693 try
3694 {
3695 return xReader->load( xStorage );
3696 }
3697 catch ( const uno::Exception& )
3698 {
3699 }
3700
3701 return uno::Sequence < util::RevisionTag >();
3702}
3703
3704void SfxMedium::AddVersion_Impl( util::RevisionTag& rRevision )
3705{
3706 if ( !GetStorage().is() )
3707 return;
3708
3709 // To determine a unique name for the stream
3710 std::vector<sal_uInt32> aLongs;
3711 sal_Int32 nLength = pImpl->aVersions.getLength();
3712 for ( const auto& rVersion : std::as_const(pImpl->aVersions) )
3713 {
3714 sal_uInt32 nVer = static_cast<sal_uInt32>( o3tl::toInt32(rVersion.Identifier.subView(7)));
3715 size_t n;
3716 for ( n=0; n<aLongs.size(); ++n )
3717 if ( nVer<aLongs[n] )
3718 break;
3719
3720 aLongs.insert( aLongs.begin()+n, nVer );
3721 }
3722
3723 std::vector<sal_uInt32>::size_type nKey;
3724 for ( nKey=0; nKey<aLongs.size(); ++nKey )
3725 if ( aLongs[nKey] > nKey+1 )
3726 break;
3727
3728 OUString aRevName = "Version" + OUString::number( nKey + 1 );
3729 pImpl->aVersions.realloc( nLength+1 );
3730 rRevision.Identifier = aRevName;
3731 pImpl->aVersions.getArray()[nLength] = rRevision;
3732}
3733
3734void SfxMedium::RemoveVersion_Impl( const OUString& rName )
3735{
3736 if ( !pImpl->aVersions.hasElements() )
3737 return;
3738
3739 auto pVersion = std::find_if(std::cbegin(pImpl->aVersions), std::cend(pImpl->aVersions),
3740 [&rName](const auto& rVersion) { return rVersion.Identifier == rName; });
3741 if (pVersion != std::cend(pImpl->aVersions))
3742 {
3743 auto nIndex = static_cast<sal_Int32>(std::distance(std::cbegin(pImpl->aVersions), pVersion));
3745 }
3746}
3747
3749{
3750 if ( rMedium.pImpl->aVersions.hasElements() )
3751 {
3752 pImpl->aVersions = rMedium.pImpl->aVersions;
3753 return true;
3754 }
3755
3756 return false;
3757}
3758
3760{
3761 if ( !GetStorage().is() )
3762 return;
3763
3764 if ( !pImpl->aVersions.hasElements() )
3765 return;
3766
3767 uno::Reference < document::XDocumentRevisionListPersistence > xWriter =
3768 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3769 try
3770 {
3771 xWriter->store( GetStorage(), pImpl->aVersions );
3772 }
3773 catch ( const uno::Exception& )
3774 {
3775 }
3776}
3777
3779{
3780 // a) ReadOnly filter can't produce read/write contents!
3781 bool bReadOnly = pImpl->m_pFilter && (pImpl->m_pFilter->GetFilterFlags() & SfxFilterFlags::OPENREADONLY);
3782
3783 // b) if filter allow read/write contents .. check open mode of the storage
3784 if (!bReadOnly)
3785 bReadOnly = !( GetOpenMode() & StreamMode::WRITE );
3786
3787 // c) the API can force the readonly state!
3788 if (!bReadOnly)
3789 {
3790 const SfxBoolItem* pItem = SfxItemSet::GetItem<SfxBoolItem>(GetItemSet(), SID_DOC_READONLY, false);
3791 if (pItem)
3792 bReadOnly = pItem->GetValue();
3793 }
3794
3795 return bReadOnly;
3796}
3797
3799{
3800 return pImpl->m_bOriginallyReadOnly;
3801}
3802
3804{
3805 pImpl->m_bOriginallyReadOnly = val;
3806}
3807
3809{
3810 return pImpl->m_bOriginallyLoadedReadOnly;
3811}
3812
3813bool SfxMedium::SetWritableForUserOnly( const OUString& aURL )
3814{
3815 // UCB does not allow to allow write access only for the user,
3816 // use osl API
3817 bool bResult = false;
3818
3819 ::osl::DirectoryItem aDirItem;
3820 if ( ::osl::DirectoryItem::get( aURL, aDirItem ) == ::osl::FileBase::E_None )
3821 {
3822 ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_Attributes );
3823 if ( aDirItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None
3824 && aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
3825 {
3826 sal_uInt64 nAttributes = aFileStatus.getAttributes();
3827
3828 nAttributes &= ~(osl_File_Attribute_OwnWrite |
3829 osl_File_Attribute_GrpWrite |
3830 osl_File_Attribute_OthWrite |
3831 osl_File_Attribute_ReadOnly);
3832 nAttributes |= (osl_File_Attribute_OwnWrite |
3833 osl_File_Attribute_OwnRead);
3834
3835 bResult = ( osl::File::setAttributes( aURL, nAttributes ) == ::osl::FileBase::E_None );
3836 }
3837 }
3838
3839 return bResult;
3840}
3841
3842namespace
3843{
3845OUString GetLogicBase(const INetURLObject& rURL, std::unique_ptr<SfxMedium_Impl> const & pImpl)
3846{
3847 OUString aLogicBase;
3848
3849#if HAVE_FEATURE_MACOSX_SANDBOX
3850 // In a sandboxed environment we don't want to attempt to create temporary files in the same
3851 // directory where the user has selected an output file to be stored. The sandboxed process has
3852 // permission only to create the specifically named output file in that directory.
3853 (void) rURL;
3854 (void) pImpl;
3855#else
3856
3857 if (!pImpl->m_bHasEmbeddedObjects // Embedded objects would mean a special base, ignore that.
3858 && rURL.GetProtocol() == INetProtocol::File && !pImpl->m_pInStream)
3859 {
3860 // Try to create the temp file in the same directory when storing.
3861 INetURLObject aURL(rURL);
3862 aURL.removeSegment();
3863 aLogicBase = aURL.GetMainURL(INetURLObject::DecodeMechanism::WithCharset);
3864 }
3865
3866#endif // !HAVE_FEATURE_MACOSX_SANDBOX
3867
3868 return aLogicBase;
3869}
3870}
3871
3872void SfxMedium::CreateTempFile( bool bReplace )
3873{
3874 if ( pImpl->pTempFile )
3875 {
3876 if ( !bReplace )
3877 return;
3878
3879 pImpl->pTempFile.reset();
3880 pImpl->m_aName.clear();
3881 }
3882
3883 OUString aLogicBase = GetLogicBase(GetURLObject(), pImpl);
3884 pImpl->pTempFile.reset(new ::utl::TempFileNamed(&aLogicBase));
3885 pImpl->pTempFile->EnableKillingFile();
3886 pImpl->m_aName = pImpl->pTempFile->GetFileName();
3887 OUString aTmpURL = pImpl->pTempFile->GetURL();
3888 if ( pImpl->m_aName.isEmpty() || aTmpURL.isEmpty() )
3889 {
3891 return;
3892 }
3893
3894 if ( !(pImpl->m_nStorOpenMode & StreamMode::TRUNC) )
3895 {
3896 bool bTransferSuccess = false;
3897
3898 if ( GetContent().is()
3899 && GetURLObject().GetProtocol() == INetProtocol::File
3900 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
3901 {
3902 // if there is already such a document, we should copy it
3903 // if it is a file system use OS copy process
3904 try
3905 {
3906 uno::Reference< css::ucb::XCommandEnvironment > xComEnv;
3907 INetURLObject aTmpURLObj( aTmpURL );
3908 OUString aFileName = aTmpURLObj.getName( INetURLObject::LAST_SEGMENT,
3909 true,
3911 if ( !aFileName.isEmpty() && aTmpURLObj.removeSegment() )
3912 {
3914 OUString sMimeType = pImpl->getFilterMimeType();
3915 aTargetContent.transferContent( pImpl->aContent, ::ucbhelper::InsertOperation::Copy, aFileName, NameClash::OVERWRITE, sMimeType );
3916 SetWritableForUserOnly( aTmpURL );
3917 bTransferSuccess = true;
3918 }
3919 }
3920 catch( const uno::Exception& )
3921 {}
3922
3923 if ( bTransferSuccess )
3924 {
3926 CloseInStream();
3927 }
3928 }
3929
3930 if ( !bTransferSuccess && pImpl->m_pInStream )
3931 {
3932 // the case when there is no URL-access available or this is a remote protocol
3933 // but there is an input stream
3934 GetOutStream();
3935 if ( pImpl->m_pOutStream )
3936 {
3937 std::unique_ptr<char[]> pBuf(new char [8192]);
3938 ErrCode nErr = ERRCODE_NONE;
3939
3940 pImpl->m_pInStream->Seek(0);
3941 pImpl->m_pOutStream->Seek(0);
3942
3943 while( !pImpl->m_pInStream->eof() && nErr == ERRCODE_NONE )
3944 {
3945 sal_uInt32 nRead = pImpl->m_pInStream->ReadBytes(pBuf.get(), 8192);
3946 nErr = pImpl->m_pInStream->GetError();
3947 pImpl->m_pOutStream->WriteBytes( pBuf.get(), nRead );
3948 }
3949
3950 bTransferSuccess = true;
3951 CloseInStream();
3952 }
3954 }
3955 else
3956 {
3957 // Quite strange design, but currently it is expected that in this case no transfer happens
3958 // TODO/LATER: get rid of this inconsistent part of the call design
3959 bTransferSuccess = true;
3960 CloseInStream();
3961 }
3962
3963 if ( !bTransferSuccess )
3964 {
3966 return;
3967 }
3968 }
3969
3970 CloseStorage();
3971}
3972
3973
3975{
3976 // this call always replaces the existing temporary file
3977 pImpl->pTempFile.reset();
3978
3979 OUString aLogicBase = GetLogicBase(GetURLObject(), pImpl);
3980 pImpl->pTempFile.reset(new ::utl::TempFileNamed(&aLogicBase));
3981 pImpl->pTempFile->EnableKillingFile();
3982 pImpl->m_aName = pImpl->pTempFile->GetFileName();
3983 if ( pImpl->m_aName.isEmpty() )
3984 {
3986 return;
3987 }
3988
3990 CloseStorage();
3991}
3992
3994 const css::uno::Reference<css::frame::XModel>& xModel, bool bHasValidDocumentSignature,
3995 const Reference<XCertificate>& xCertificate)
3996{
3997 bool bChanges = false;
3998
3999 if (IsOpen() || GetError())
4000 {
4001 SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
4002 return bChanges;
4003 }
4004
4005 // The component should know if there was a valid document signature, since
4006 // it should show a warning in this case
4008 uno::Reference< security::XDocumentDigitalSignatures > xSigner(
4009 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
4010 comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
4011 auto xModelSigner = dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get());
4012 if (!xModelSigner)
4013 {
4014 return bChanges;
4015 }
4016
4017 uno::Reference< embed::XStorage > xWriteableZipStor;
4018
4019 // we can reuse the temporary file if there is one already
4020 CreateTempFile( false );
4022
4023 try
4024 {
4025 if ( !pImpl->xStream.is() )
4026 throw uno::RuntimeException();
4027
4028 bool bODF = GetFilter()->IsOwnFormat();
4029 try
4030 {
4032 }
4033 catch (const io::IOException&)
4034 {
4035 if (bODF)
4036 {
4037 TOOLS_WARN_EXCEPTION("sfx.doc", "ODF stream is not a zip storage");
4038 }
4039 }
4040
4041 if ( !xWriteableZipStor.is() && bODF )
4042 throw uno::RuntimeException();
4043
4044 uno::Reference< embed::XStorage > xMetaInf;
4045 if (xWriteableZipStor.is() && xWriteableZipStor->hasByName("META-INF"))
4046 {
4047 xMetaInf = xWriteableZipStor->openStorageElement(
4048 "META-INF",
4049 embed::ElementModes::READWRITE );
4050 if ( !xMetaInf.is() )
4051 throw uno::RuntimeException();
4052 }
4053
4054 {
4055 if (xMetaInf.is())
4056 {
4057 // ODF.
4058 uno::Reference< io::XStream > xStream;
4059 if (GetFilter() && GetFilter()->IsOwnFormat())
4060 xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW);
4061
4062 bool bSuccess = xModelSigner->SignModelWithCertificate(
4063 xModel, xCertificate, GetZipStorageToSign_Impl(), xStream);
4064
4065 if (bSuccess)
4066 {
4067 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
4068 xTransact->commit();
4069 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
4070 xTransact->commit();
4071
4072 // the temporary file has been written, commit it to the original file
4073 Commit();
4074 bChanges = true;
4075 }
4076 }
4077 else if (xWriteableZipStor.is())
4078 {
4079 // OOXML.
4080 uno::Reference<io::XStream> xStream;
4081
4082 // We need read-write to be able to add the signature relation.
4083 bool bSuccess = xModelSigner->SignModelWithCertificate(
4084 xModel, xCertificate, GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream);
4085
4086 if (bSuccess)
4087 {
4088 uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
4089 xTransact->commit();
4090
4091 // the temporary file has been written, commit it to the original file
4092 Commit();
4093 bChanges = true;
4094 }
4095 }
4096 else
4097 {
4098 // Something not ZIP based: e.g. PDF.
4099 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | StreamMode::WRITE));
4100 uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream));
4101 if (xModelSigner->SignModelWithCertificate(
4102 xModel, xCertificate, uno::Reference<embed::XStorage>(), xStream))
4103 bChanges = true;
4104 }
4105 }
4106 }
4107 catch ( const uno::Exception& )
4108 {
4109 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!" );
4110 }
4111
4113
4114 ResetError();
4115
4116 return bChanges;
4117}
4118
4120 bool bSignScriptingContent,
4121 bool bHasValidDocumentSignature,
4122 const OUString& aSignatureLineId,
4123 const Reference<XCertificate>& xCert,
4124 const Reference<XGraphic>& xValidGraphic,
4125 const Reference<XGraphic>& xInvalidGraphic,
4126 const OUString& aComment)
4127{
4128 bool bChanges = false;
4129
4130 if (IsOpen() || GetError())
4131 {
4132 SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
4133 return bChanges;
4134 }
4135
4136 // The component should know if there was a valid document signature, since
4137 // it should show a warning in this case
4139 uno::Reference< security::XDocumentDigitalSignatures > xSigner(
4140 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
4141 comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
4142 if (pDialogParent)
4143 xSigner->setParentWindow(pDialogParent->GetXWindow());
4144
4145 uno::Reference< embed::XStorage > xWriteableZipStor;
4146
4147 // we can reuse the temporary file if there is one already
4148 CreateTempFile( false );
4150
4151 try
4152 {
4153 if ( !pImpl->xStream.is() )
4154 throw uno::RuntimeException();
4155
4156 bool bODF = GetFilter()->IsOwnFormat();
4157 try
4158 {
4160 }
4161 catch (const io::IOException&)
4162 {
4163 if (bODF)
4164 {
4165 TOOLS_WARN_EXCEPTION("sfx.doc", "ODF stream is not a zip storage");
4166 }
4167 }
4168
4169 if ( !xWriteableZipStor.is() && bODF )
4170 throw uno::RuntimeException();
4171
4172 uno::Reference< embed::XStorage > xMetaInf;
4173 if (xWriteableZipStor.is() && xWriteableZipStor->hasByName("META-INF"))
4174 {
4175 xMetaInf = xWriteableZipStor->openStorageElement(
4176 "META-INF",
4177 embed::ElementModes::READWRITE );
4178 if ( !xMetaInf.is() )
4179 throw uno::RuntimeException();
4180 }
4181
4182 if ( bSignScriptingContent )
4183 {
4184 // If the signature has already the document signature it will be removed
4185 // after the scripting signature is inserted.
4186 uno::Reference< io::XStream > xStream(
4187 xMetaInf->openStreamElement( xSigner->getScriptingContentSignatureDefaultStreamName(),
4188 embed::ElementModes::READWRITE ),
4189 uno::UNO_SET_THROW );
4190
4191 if ( xSigner->signScriptingContent( GetZipStorageToSign_Impl(), xStream ) )
4192 {
4193 // remove the document signature if any
4194 OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName();
4195 if ( !aDocSigName.isEmpty() && xMetaInf->hasByName( aDocSigName ) )
4196 xMetaInf->removeElement( aDocSigName );
4197
4198 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
4199 xTransact->commit();
4200 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
4201 xTransact->commit();
4202
4203 // the temporary file has been written, commit it to the original file
4204 Commit();
4205 bChanges = true;
4206 }
4207 }
4208 else
4209 {
4210 if (xMetaInf.is())
4211 {
4212 // ODF.
4213 uno::Reference< io::XStream > xStream;
4214 if (GetFilter() && GetFilter()->IsOwnFormat())
4215 xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW);
4216
4217 bool bSuccess = false;
4218 if (xCert.is())
4219 bSuccess = xSigner->signSignatureLine(
4220 GetZipStorageToSign_Impl(), xStream, aSignatureLineId, xCert,
4221 xValidGraphic, xInvalidGraphic, aComment);
4222 else
4223 bSuccess = xSigner->signDocumentContent(GetZipStorageToSign_Impl(),
4224 xStream);
4225
4226 if (bSuccess)
4227 {
4228 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
4229 xTransact->commit();
4230 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
4231 xTransact->commit();
4232
4233 // the temporary file has been written, commit it to the original file
4234 Commit();
4235 bChanges = true;
4236 }
4237 }
4238 else if (xWriteableZipStor.is())
4239 {
4240 // OOXML.
4241 uno::Reference<io::XStream> xStream;
4242
4243 bool bSuccess = false;
4244 if (xCert.is())
4245 {
4246 bSuccess = xSigner->signSignatureLine(
4247 GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream, aSignatureLineId,
4248 xCert, xValidGraphic, xInvalidGraphic, aComment);
4249 }
4250 else
4251 {
4252 // We need read-write to be able to add the signature relation.
4253 bSuccess =xSigner->signDocumentContent(
4254 GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream);
4255 }
4256
4257 if (bSuccess)
4258 {
4259 uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
4260 xTransact->commit();
4261
4262 // the temporary file has been written, commit it to the original file
4263 Commit();
4264 bChanges = true;
4265 }
4266 }
4267 else
4268 {
4269 // Something not ZIP based: e.g. PDF.
4270 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | StreamMode::WRITE));
4271 uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream));
4272 if (xSigner->signDocumentContent(uno::Reference<embed::XStorage>(), xStream))
4273 bChanges = true;
4274 }
4275 }
4276 }
4277 catch ( const uno::Exception& )
4278 {
4279 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!" );
4280 }
4281
4283
4284 ResetError();
4285
4286 return bChanges;
4287}
4288
4289
4291{
4292 return pImpl->m_nSignatureState;
4293}
4294
4295
4297{
4298 pImpl->m_nSignatureState = nState;
4299}
4300
4301void SfxMedium::SetHasEmbeddedObjects(bool bHasEmbeddedObjects)
4302{
4303 pImpl->m_bHasEmbeddedObjects = bHasEmbeddedObjects;
4304}
4305
4307{
4308 return pImpl->xStorage.is();
4309}
4310
4312{
4313 return pImpl->m_pInStream || pImpl->m_pOutStream || pImpl->xStorage.is();
4314}
4315
4316OUString SfxMedium::CreateTempCopyWithExt( std::u16string_view aURL )
4317{
4318 OUString aResult;
4319
4320 if ( !aURL.empty() )
4321 {
4322 size_t nPrefixLen = aURL.rfind( '.' );
4323 std::u16string_view aExt = ( nPrefixLen == std::u16string_view::npos ) ? std::u16string_view() : aURL.substr( nPrefixLen );
4324
4325 OUString aNewTempFileURL = ::utl::CreateTempURL( u"", true, aExt );
4326 if ( !aNewTempFileURL.isEmpty() )
4327 {
4328 INetURLObject aSource( aURL );
4329 INetURLObject aDest( aNewTempFileURL );
4330 OUString aFileName = aDest.getName( INetURLObject::LAST_SEGMENT,
4331 true,
4333 if ( !aFileName.isEmpty() && aDest.removeSegment() )
4334 {
4335 try
4336 {
4337 uno::Reference< css::ucb::XCommandEnvironment > xComEnv;
4340 aTargetContent.transferContent( aSourceContent,
4342 aFileName,
4343 NameClash::OVERWRITE );
4344 aResult = aNewTempFileURL;
4345 }
4346 catch( const uno::Exception& )
4347 {}
4348 }
4349 }
4350 }
4351
4352 return aResult;
4353}
4354
4355bool SfxMedium::CallApproveHandler(const uno::Reference< task::XInteractionHandler >& xHandler, const uno::Any& rRequest, bool bAllowAbort)
4356{
4357 bool bResult = false;
4358
4359 if ( xHandler.is() )
4360 {
4361 try
4362 {
4363 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( bAllowAbort ? 2 : 1 );
4364 auto pContinuations = aContinuations.getArray();
4365
4366 ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( new ::comphelper::OInteractionApprove );
4367 pContinuations[ 0 ] = pApprove.get();
4368
4369 if ( bAllowAbort )
4370 {
4371 ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( new ::comphelper::OInteractionAbort );
4372 pContinuations[ 1 ] = pAbort.get();
4373 }
4374
4375 xHandler->handle(::framework::InteractionRequest::CreateRequest(rRequest, aContinuations));
4376 bResult = pApprove->wasSelected();
4377 }
4378 catch( const Exception& )
4379 {
4380 }
4381 }
4382
4383 return bResult;
4384}
4385
4387{
4388 // the method returns empty string in case of failure
4389 OUString aResult;
4390 OUString aOrigURL = pImpl->m_aLogicName;
4391
4392 if ( !aOrigURL.isEmpty() )
4393 {
4394 sal_Int32 nPrefixLen = aOrigURL.lastIndexOf( '.' );
4395 std::u16string_view aExt = (nPrefixLen == -1)
4396 ? std::u16string_view()
4397 : aOrigURL.subView(nPrefixLen);
4398 OUString aNewURL = ::utl::CreateTempURL( u"", true, aExt );
4399
4400 // TODO/LATER: In future the aLogicName should be set to shared folder URL
4401 // and a temporary file should be created. Transport_Impl should be impossible then.
4402 if ( !aNewURL.isEmpty() )
4403 {
4404 uno::Reference< embed::XStorage > xStorage = GetStorage();
4405 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
4406
4407 if ( xOptStorage.is() )
4408 {
4409 // TODO/LATER: reuse the pImpl->pTempFile if it already exists
4410 CanDisposeStorage_Impl( false );
4411 Close();
4412 SetPhysicalName_Impl( OUString() );
4413 SetName( aNewURL );
4414
4415 // remove the readonly state
4416 bool bWasReadonly = false;
4417 pImpl->m_nStorOpenMode = SFX_STREAM_READWRITE;
4418 const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
4419 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
4420 bWasReadonly = true;
4421 GetItemSet()->ClearItem( SID_DOC_READONLY );
4422
4424 LockOrigFileOnDemand( false, false );
4427
4428 if ( pImpl->xStream.is() )
4429 {
4430 try
4431 {
4432 xOptStorage->writeAndAttachToStream( pImpl->xStream );
4433 pImpl->xStorage = xStorage;
4434 aResult = aNewURL;
4435 }
4436 catch( const uno::Exception& )
4437 {}
4438 }
4439
4440 if (bWasReadonly)
4441 {
4442 // set the readonly state back
4443 pImpl->m_nStorOpenMode = SFX_STREAM_READONLY;
4444 GetItemSet()->Put(SfxBoolItem(SID_DOC_READONLY, true));
4445 }
4446
4447 if ( aResult.isEmpty() )
4448 {
4449 Close();
4450 SetPhysicalName_Impl( OUString() );
4451 SetName( aOrigURL );
4453 pImpl->xStorage = xStorage;
4454 }
4455 }
4456 }
4457 }
4458
4459 return aResult;
4460}
4461
4462bool SfxMedium::SwitchDocumentToFile( const OUString& aURL )
4463{
4464 // the method is only for storage based documents
4465 bool bResult = false;
4466 OUString aOrigURL = pImpl->m_aLogicName;
4467
4468 if ( !aURL.isEmpty() && !aOrigURL.isEmpty() )
4469 {
4470 uno::Reference< embed::XStorage > xStorage = GetStorage();
4471 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
4472
4473 // TODO/LATER: reuse the pImpl->pTempFile if it already exists
4474 CanDisposeStorage_Impl( false );
4475 Close();
4476 SetPhysicalName_Impl( OUString() );
4477 SetName( aURL );
4478
4479 // open the temporary file based document
4481 LockOrigFileOnDemand( false, false );
4484
4485 if ( pImpl->xStream.is() )
4486 {
4487 try
4488 {
4489 uno::Reference< io::XTruncate > xTruncate( pImpl->xStream, uno::UNO_QUERY_THROW );
4490 xTruncate->truncate();
4491 if ( xOptStorage.is() )
4492 xOptStorage->writeAndAttachToStream( pImpl->xStream );
4493 pImpl->xStorage = xStorage;
4494 bResult = true;
4495 }
4496 catch( const uno::Exception& )
4497 {}
4498 }
4499
4500 if ( !bResult )
4501 {
4502 Close();
4503 SetPhysicalName_Impl( OUString() );
4504 SetName( aOrigURL );
4506 pImpl->xStorage = xStorage;
4507 }
4508 }
4509
4510 return bResult;
4511}
4512
4513void SfxMedium::SetInCheckIn( bool bInCheckIn )
4514{
4515 pImpl->m_bInCheckIn = bInCheckIn;
4516}
4517
4519{
4520 return pImpl->m_bInCheckIn;
4521}
4522
4523// should only be called on main thread
4524const std::shared_ptr<std::recursive_mutex>& SfxMedium::GetCheckEditableMutex() const
4525{
4526 return pImpl->m_pCheckEditableWorkerMutex;
4527}
4528
4529// should only be called while holding pImpl->m_pCheckEditableWorkerMutex
4531{
4532 pImpl->m_pReloadEvent = pEvent;
4533}
4534
4535// should only be called while holding pImpl->m_pCheckEditableWorkerMutex
4537{
4538 return pImpl->m_pReloadEvent;
4539}
4540
4541// should only be called on main thread
4543{
4544 if (!pImpl->m_bNotifyWhenEditable)
4545 return;
4546
4548
4549 if (pImpl->m_pCheckEditableWorkerMutex == nullptr)
4550 {
4551 pImpl->m_pCheckEditableWorkerMutex = std::make_shared<std::recursive_mutex>();
4552 if (pImpl->m_pCheckEditableWorkerMutex == nullptr)
4553 return;
4554 }
4555
4556 pImpl->m_pIsDestructed = std::make_shared<bool>(false);
4557 if (pImpl->m_pIsDestructed == nullptr)
4558 return;
4559
4560 std::unique_lock<std::mutex> globalLock(g_chkReadOnlyGlobalMutex);
4561 if (g_newReadOnlyDocs.find(this) == g_newReadOnlyDocs.end())
4562 {
4563 bool bAddNewEntry = false;
4565 {
4566 std::shared_ptr<comphelper::ThreadTaskTag> pTag
4568 if (pTag != nullptr)
4569 {
4571 bAddNewEntry = true;
4573 std::make_unique<CheckReadOnlyTask>(pTag));
4574 }
4575 }
4576 else
4577 bAddNewEntry = true;
4578
4579 if (bAddNewEntry)
4580 {
4581 std::shared_ptr<ReadOnlyMediumEntry> newEntry = std::make_shared<ReadOnlyMediumEntry>(
4582 pImpl->m_pCheckEditableWorkerMutex, pImpl->m_pIsDestructed);
4583
4584 if (newEntry != nullptr)
4585 {
4586 g_newReadOnlyDocs[this] = newEntry;
4587 }
4588 }
4589 }
4590}
4591
4592// should only be called on main thread
4594{
4595 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
4596 {
4597 std::unique_lock<std::recursive_mutex> lock(*(pImpl->m_pCheckEditableWorkerMutex));
4598
4599 if (pImpl->m_pReloadEvent != nullptr)
4600 {
4601 if (bRemoveEvent)
4602 Application::RemoveUserEvent(pImpl->m_pReloadEvent);
4603 // make sure destructor doesn't use a freed reference
4604 // and reset the event so we can check again
4605 pImpl->m_pReloadEvent = nullptr;
4606 }
4607
4608 if (pImpl->m_pIsDestructed != nullptr)
4609 {
4610 *(pImpl->m_pIsDestructed) = true;
4611 pImpl->m_pIsDestructed = nullptr;
4612 }
4613 }
4614}
4615
4620IMPL_STATIC_LINK(SfxMedium, ShowReloadEditableDialog, void*, p, void)
4621{
4622 SfxMedium* pMed = static_cast<SfxMedium*>(p);
4623 if (pMed == nullptr)
4624 return;
4625
4626 pMed->CancelCheckEditableEntry(false);
4627
4628 uno::Reference<task::XInteractionHandler> xHandler = pMed->GetInteractionHandler();
4629 if (xHandler.is())
4630 {
4631 OUString aDocumentURL
4634 = new ::ucbhelper::InteractionRequest(uno::Any(document::ReloadEditableRequest(
4635 OUString(), uno::Reference<uno::XInterface>(), aDocumentURL)));
4636 if (xInteractionRequestImpl != nullptr)
4637 {
4638 uno::Sequence<uno::Reference<task::XInteractionContinuation>> aContinuations{
4639 new ::ucbhelper::InteractionAbort(xInteractionRequestImpl.get()),
4640 new ::ucbhelper::InteractionApprove(xInteractionRequestImpl.get())
4641 };
4642 xInteractionRequestImpl->setContinuations(aContinuations);
4643 xHandler->handle(xInteractionRequestImpl);
4645 = xInteractionRequestImpl->getSelection();
4646 if (uno::Reference<task::XInteractionApprove>(xSelected.get(), uno::UNO_QUERY).is())
4647 {
4648 for (SfxViewFrame* pFrame = SfxViewFrame::GetFirst(); pFrame;
4649 pFrame = SfxViewFrame::GetNext(*pFrame))
4650 {
4651 if (pFrame->GetObjectShell()->GetMedium() == pMed)
4652 {
4653 // special case to ensure view isn't set to read-only in
4654 // SfxViewFrame::ExecReload_Impl after reloading
4655 pMed->SetOriginallyReadOnly(false);
4656 pFrame->GetDispatcher()->Execute(SID_RELOAD);
4657 break;
4658 }
4659 }
4660 }
4661 }
4662 }
4663}
4664
4666{
4667#if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
4668 bool bCanReload = true;
4669#else
4670 bool bCanReload = false;
4671 ::svt::DocumentLockFile aLockFile(GetName());
4673 osl::DirectoryItem rItem;
4674 auto nError1 = osl::DirectoryItem::get(aLockFile.GetURL(), rItem);
4675 if (nError1 == osl::FileBase::E_None)
4676 {
4677 try
4678 {
4679 aData = aLockFile.GetLockData();
4680 }
4681 catch (const io::WrongFormatException&)
4682 {
4683 // we get empty or corrupt data
4684 return false;
4685 }
4686 catch (const uno::Exception&)
4687 {
4688 // locked from other app
4689 return false;
4690 }
4692 bool bOwnLock
4693 = aOwnData[LockFileComponent::SYSUSERNAME] == aData[LockFileComponent::SYSUSERNAME];
4694 if (bOwnLock
4695 && aOwnData[LockFileComponent::LOCALHOST] == aData[LockFileComponent::LOCALHOST]
4696 && aOwnData[LockFileComponent::USERURL] == aData[LockFileComponent::USERURL])
4697 {
4698 // this is own lock from the same installation, it could remain because of crash
4699 bCanReload = true;
4700 }
4701 }
4702 else if (nError1 == osl::FileBase::E_NOENT) // file doesn't exist
4703 {
4704 try
4705 {
4706 aLockFile.CreateOwnLockFile();
4707 try
4708 {
4709 // TODO/LATER: A warning could be shown in case the file is not the own one
4710 aLockFile.RemoveFile();
4711 }
4712 catch (const io::WrongFormatException&)
4713 {
4714 try
4715 {
4716 // erase the empty or corrupt file
4717 aLockFile.RemoveFileDirectly();
4718 }
4719 catch (const uno::Exception&)
4720 {
4721 }
4722 }
4723 bCanReload = true;
4724 }
4725 catch (const uno::Exception&)
4726 {
4727 }
4728 }
4729#endif
4730 return bCanReload;
4731}
4732
4733// worker thread method, should only be one thread globally
4734void CheckReadOnlyTask::doWork()
4735{
4736 if (m_xListener == nullptr)
4737 return;
4738
4739 while (true)
4740 {
4741 std::unique_lock<std::mutex> termLock(m_xListener->mMutex);
4742 if (m_xListener->mCond.wait_for(termLock, std::chrono::seconds(60),
4743 [this] { return m_xListener->bIsTerminated; }))
4744 // signalled, spurious wakeups should not be possible
4745 return;
4746
4747 // must have timed-out
4748 termLock.unlock();
4749 std::unique_lock<std::mutex> globalLock(g_chkReadOnlyGlobalMutex);
4750 for (auto it = g_newReadOnlyDocs.begin(); it != g_newReadOnlyDocs.end(); )
4751 {
4752 auto [pMed, roEntry] = *it;
4753 g_existingReadOnlyDocs[pMed] = roEntry;
4754 it = g_newReadOnlyDocs.erase(it);
4755 }
4756 if (g_existingReadOnlyDocs.size() == 0)
4757 {
4759 return;
4760 }
4761 globalLock.unlock();
4762
4763 auto checkForErase = [](SfxMedium* pMed, const std::shared_ptr<ReadOnlyMediumEntry>& roEntry) -> bool
4764 {
4765 if (pMed == nullptr || roEntry == nullptr || roEntry->_pMutex == nullptr
4766 || roEntry->_pIsDestructed == nullptr)
4767 return true;
4768
4769 std::unique_lock<std::recursive_mutex> medLock(*(roEntry->_pMutex));
4770 if (*(roEntry->_pIsDestructed) || pMed->GetWorkerReloadEvent() != nullptr)
4771 return true;
4772
4773 osl::File aFile(
4775 if (aFile.open(osl_File_OpenFlag_Write) != osl::FileBase::E_None)
4776 return false;
4777
4778 if (!pMed->CheckCanGetLockfile())
4779 return false;
4780
4781 if (aFile.close() != osl::FileBase::E_None)
4782 return true;
4783
4784 // we can load, ask user
4786 LINK(nullptr, SfxMedium, ShowReloadEditableDialog), pMed);
4787 pMed->SetWorkerReloadEvent(pEvent);
4788 return true;
4789 };
4790
4791 for (auto it = g_existingReadOnlyDocs.begin(); it != g_existingReadOnlyDocs.end(); )
4792 {
4793 if (checkForErase(it->first, it->second))
4794 it = g_existingReadOnlyDocs.erase(it);
4795 else
4796 ++it;
4797 }
4798 }
4799}
4800
4801/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PropertiesInfo aProperties
Reference< XInputStream > xStream
SfxApplication * SfxGetpApp()
Definition: app.hxx:232
constexpr OUStringLiteral sInputStream
Definition: appuno.cxx:111
void TransformItems(sal_uInt16 nSlotId, const SfxItemSet &rSet, uno::Sequence< beans::PropertyValue > &rArgs, const SfxSlot *pSlot)
Definition: appuno.cxx:908
constexpr OUStringLiteral sStream
Definition: appuno.cxx:112
void TransformParameters(sal_uInt16 nSlotId, const uno::Sequence< beans::PropertyValue > &rArgs, SfxAllItemSet &rSet, const SfxSlot *pSlot)
Definition: appuno.cxx:170
AnyEventRef aEvent
const sal_uInt16 nVersion
Definition: childwin.cxx:43
static void Yield()
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
static bool IsQuit()
const OUString & GetValue() const
OUString getName(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool isAnyKnownWebDAVScheme() const
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool removeSegment(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true)
OUString GetMark(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString GetURLNoMark(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString GetLastName(DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool HasMark() const
bool insertName(std::u16string_view rTheName, bool bAppendFinalSlash=false, sal_Int32 nIndex=LAST_SEGMENT, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
INetProtocol GetProtocol() const
bool setExtension(std::u16string_view rTheExtension, sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
OUString getFSysPath(FSysStyle eStyle, sal_Unicode *pDelimiter=nullptr) const
SfxFilterMatcher & GetFilterMatcher()
Definition: appmain.cxx:27
bool GetValue() const
std::shared_ptr< const SfxFilter > GetFilter4FilterName(const OUString &rName, SfxFilterFlags nMust=SfxFilterFlags::NONE, SfxFilterFlags nDont=SFX_FILTER_NOTINSTALLED) const
Definition: fltfnc.cxx:728
std::shared_ptr< const SfxFilter > GetFilter4EA(const OUString &rEA, SfxFilterFlags nMust=SfxFilterFlags::IMPORT, SfxFilterFlags nDont=SFX_FILTER_NOTINSTALLED) const
Definition: fltfnc.cxx:637
static OUString GetTypeFromStorage(const SotStorage &rStg)
Definition: docfilt.cxx:121
sal_Int16 GetValue() const
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
uno::Reference< task::XInteractionHandler > xInteraction
Definition: docfile.cxx:412
bool m_bDisableFileSync
Definition: docfile.cxx:375
ErrCode m_eWarningError
Definition: docfile.cxx:351
SignatureState m_nSignatureState
Definition: docfile.cxx:421
ErrCode nLastStorageError
Definition: docfile.cxx:414
StreamMode m_nStorOpenMode
Definition: docfile.cxx:349
std::shared_ptr< std::recursive_mutex > m_pCheckEditableWorkerMutex
Definition: docfile.cxx:388
uno::Reference< io::XStream > xStream
Definition: docfile.cxx:410
::ucbhelper::Content aContent
Definition: docfile.cxx:353
bool bAllowDefaultIntHdl
Definition: docfile.cxx:359
SfxMedium_Impl & operator=(const SfxMedium_Impl &)=delete
bool m_bMSOLockFileCreated
Definition: docfile.cxx:365
bool m_bNotifyWhenEditable
Definition: docfile.cxx:376
std::shared_ptr< bool > m_pIsDestructed
Definition: docfile.cxx:389
SvKeyValueIteratorRef xAttributes
Definition: docfile.cxx:398
OUString m_aLogicName
Definition: docfile.cxx:379
bool m_bInputStreamIsReadOnly
Definition: docfile.cxx:373
bool m_bRemoveBackup
Definition: docfile.cxx:368
uno::Reference< io::XInputStream > xInputStream
Definition: docfile.cxx:409
SfxFrameWeakRef wLoadTargetFrame
Definition: docfile.cxx:397
bool m_bHasEmbeddedObjects
Definition: docfile.cxx:423
OUString m_aLongName
Definition: docfile.cxx:380
uno::Reference< embed::XStorage > xStorage
Definition: docfile.cxx:406
util::DateTime m_aDateTime
Definition: docfile.cxx:425
uno::Reference< io::XStream > m_xLockingStream
Definition: docfile.cxx:411
std::shared_ptr< const SfxFilter > m_pFilter
Definition: docfile.cxx:385
std::unique_ptr<::utl::TempFileNamed > pTempFile
Definition: docfile.cxx:404
ImplSVEvent * m_pReloadEvent
Definition: docfile.cxx:390
bool m_bVersionsAlreadyLoaded
Definition: docfile.cxx:363
bool bUpdatePickList
Definition: docfile.cxx:354
bool m_bGotDateTime
Definition: docfile.cxx:367
std::unique_ptr< INetURLObject > m_pURLObj
Definition: docfile.cxx:383
bool bDownloadDone
Definition: docfile.cxx:356
svtools::AsynchronLink aDoneLink
Definition: docfile.cxx:400
bool bUseInteractionHandler
Definition: docfile.cxx:358
bool m_bInCheckIn
Definition: docfile.cxx:374
DateTime aExpireTime
Definition: docfile.cxx:396
bool m_bOriginallyReadOnly
Definition: docfile.cxx:369
bool m_bSalvageMode
Definition: docfile.cxx:362
std::shared_ptr< SfxItemSet > m_pSet
Definition: docfile.cxx:382
OUString m_aBackupURL
Definition: docfile.cxx:416
uno::Sequence< util::RevisionTag > aVersions
Definition: docfile.cxx:402
uno::Reference< io::XInputStream > m_xInputStreamToLoadFrom
Definition: docfile.cxx:408
OUString aOrigURL
Definition: docfile.cxx:395
bool bStorageBasedOnInStream
Definition: docfile.cxx:361
bool bDisposeStorage
Definition: docfile.cxx:360
bool m_bOriginallyLoadedReadOnly
Definition: docfile.cxx:370
OUString getFilterMimeType() const
Definition: docfile.cxx:434
ErrCode m_eError
Definition: docfile.cxx:350
OUString m_aName
Definition: docfile.cxx:378
std::shared_ptr< const SfxFilter > m_pCustomFilter
Definition: docfile.cxx:386
std::unique_ptr< SvStream > m_pInStream
Definition: docfile.cxx:392
uno::Sequence< beans::PropertyValue > m_aArgs
Definition: docfile.cxx:427
bool m_bDisableUnlockWebDAV
Definition: docfile.cxx:366
bool m_bTriedStorage
Definition: docfile.cxx:371
uno::Reference< embed::XStorage > m_xZipStorage
Definition: docfile.cxx:407
SfxMedium_Impl(const SfxMedium_Impl &)=delete
std::unique_ptr< SvStream > m_pOutStream
Definition: docfile.cxx:393
bool CheckCanGetLockfile() const
Definition: docfile.cxx:4665
SAL_DLLPRIVATE void GetLockingStream_Impl()
Definition: docfile.cxx:2719
SfxFrame * GetLoadTargetFrame() const
Definition: docfile.cxx:3602
void CloseStorage()
Definition: docfile.cxx:1923
ErrCode const & GetLastStorageCreationState() const
Definition: docfile.cxx:497
bool IsOpen() const
Definition: docfile.cxx:4311
void CreateTempFileNoCopy()
Definition: docfile.cxx:3974
bool IsExpired() const
Definition: docfile.cxx:3596
SAL_DLLPRIVATE void CreateFileStream()
Definition: docfile.cxx:819
void SetOpenMode(StreamMode nStorOpen, bool bDontClose=false)
Definition: docfile.cxx:1962
const std::shared_ptr< const SfxFilter > & GetFilter() const
Definition: docfile.cxx:3089
void DisableFileSync(bool bDisableFileSync)
Lets Transfer_Impl() not fsync the output file.
Definition: docfile.cxx:3144
SAL_DLLPRIVATE void CloseAndReleaseStreams_Impl()
Definition: docfile.cxx:3255
void SetError(ErrCode nError)
Definition: docfile.cxx:502
void Close(bool bInDestruction=false)
Definition: docfile.cxx:3115
void CloseInStream()
Definition: docfile.cxx:701
SAL_DLLPRIVATE void CloseInStream_Impl(bool bInDestruction=false)
Definition: docfile.cxx:706
void ResetError()
Definition: docfile.cxx:483
void setStreamToLoadFrom(const css::uno::Reference< css::io::XInputStream > &xInputStream, bool bIsReadOnly)
Definition: docfile.cxx:3607
OUString GetBaseURL(bool bForSaving=false)
Definition: docfile.cxx:634
SAL_DLLPRIVATE void SetEncryptionDataToStorage_Impl()
Definition: docfile.cxx:974
SAL_DLLPRIVATE bool TryDirectTransfer(const OUString &aURL, SfxItemSet const &aTargetSet)
Definition: docfile.cxx:2206
void SetHasEmbeddedObjects(bool bHasEmbeddedObjects)
Definition: docfile.cxx:4301
SAL_DLLPRIVATE void DoBackup_Impl()
Definition: docfile.cxx:2637
bool IsOriginallyLoadedReadOnly() const
Definition: docfile.cxx:3808
const INetURLObject & GetURLObject() const
Definition: docfile.cxx:3575
void UseInteractionHandler(bool)
Definition: docfile.cxx:3047
SAL_DLLPRIVATE bool IsUpdatePickList() const
Definition: docfile.cxx:2902
css::util::DateTime const & GetInitFileDate(bool bIgnoreOldValue)
Definition: docfile.cxx:566
SAL_DLLPRIVATE void SetStorage_Impl(const css::uno::Reference< css::embed::XStorage > &xNewStorage)
Definition: docfile.cxx:3619
void CloseAndRelease()
Definition: docfile.cxx:3127
void Download(const Link< void *, void > &aLink=Link< void *, void >())
Definition: docfile.cxx:2922
LockFileResult LockOrigFileOnDemand(bool bLoading, bool bNoUI, bool bTryIgnoreLockFile=false, LockFileEntry *pLockData=nullptr)
Definition: docfile.cxx:1293
SAL_DLLPRIVATE void DoInternalBackup_Impl(const ::ucbhelper::Content &aOriginalContent)
Definition: docfile.cxx:2601
SAL_DLLPRIVATE void SetPhysicalName_Impl(const OUString &rName)
Definition: docfile.cxx:3348
SAL_DLLPRIVATE SignatureState GetCachedSignatureState_Impl() const
Definition: docfile.cxx:4290
bool IsSkipImages() const
Definition: docfile.cxx:665
ErrCode GetErrorCode() const
Definition: docfile.cxx:512
SAL_DLLPRIVATE void SetUpdatePickList(bool)
Definition: docfile.cxx:2897
void SetDoneLink(const Link< void *, void > &rLink)
Definition: docfile.cxx:2917
SAL_DLLPRIVATE void CanDisposeStorage_Impl(bool bDisposeStorage)
Definition: docfile.cxx:1947
void SetInCheckIn(bool bInCheckIn)
Definition: docfile.cxx:4513
SfxItemSet * GetItemSet() const
Definition: docfile.cxx:3625
SAL_DLLPRIVATE void SaveVersionList_Impl()
Definition: docfile.cxx:3759
SAL_DLLPRIVATE bool UseBackupToRestore_Impl(::ucbhelper::Content &aOriginalContent, const css::uno::Reference< css::ucb::XCommandEnvironment > &xComEnv)
Definition: docfile.cxx:1980
bool IsOriginallyReadOnly() const
Definition: docfile.cxx:3798
bool ShowLockFileProblemDialog(MessageDlg nWhichDlg)
ErrCode GetError() const
Definition: docfile.hxx:147
SAL_DLLPRIVATE OUString const & GetBackup_Impl()
Definition: docfile.cxx:940
SAL_DLLPRIVATE bool TransferVersionList_Impl(SfxMedium const &rMedium)
Definition: docfile.cxx:3748
StreamMode GetOpenMode() const
Definition: docfile.cxx:1957
static sal_uInt32 CreatePasswordToModifyHash(std::u16string_view aPasswd, bool bWriter)
Definition: docfile.cxx:3094
std::unique_ptr< SfxMedium_Impl > pImpl
Definition: docfile.hxx:66
bool IsInCheckIn() const
Definition: docfile.cxx:4518
const OUString & GetOrigURL() const
Definition: docfile.cxx:3342
SAL_DLLPRIVATE void SetLongName(const OUString &rName)
Definition: docfile.cxx:2907
void CloseOutStream()
Definition: docfile.cxx:776
void SetName(const OUString &rName, bool bSetOrigURL=false)
Definition: docfile.cxx:3324
const css::uno::Sequence< css::util::RevisionTag > & GetVersionList(bool _bNoReload=false)
Definition: docfile.cxx:3666
const OUString & GetName() const
Definition: docfile.cxx:3570
SAL_DLLPRIVATE bool SignDocumentContentUsingCertificate(const css::uno::Reference< css::frame::XModel > &xModel, bool bHasValidDocumentSignature, const css::uno::Reference< css::security::XCertificate > &xCertificate)
Definition: docfile.cxx:3993
void DisableUnlockWebDAV(bool bDisableUnlockWebDAV=true)
Definition: docfile.cxx:3139
const std::shared_ptr< std::recursive_mutex > & GetCheckEditableMutex() const
Definition: docfile.cxx:4524
SAL_DLLPRIVATE void StorageBackup_Impl()
Definition: docfile.cxx:918
void CancelCheckEditableEntry(bool bRemoveEvent=true)
Definition: docfile.cxx:4593
void SetWarningError(ErrCode nWarningError)
Definition: docfile.cxx:507
bool IsRemote() const
Definition: docfile.cxx:2892
bool SwitchDocumentToFile(const OUString &aURL)
Definition: docfile.cxx:4462
static bool SetWritableForUserOnly(const OUString &aURL)
Definition: docfile.cxx:3813
SAL_DLLPRIVATE bool HasStorage_Impl() const
Definition: docfile.cxx:4306
static OUString CreateTempCopyWithExt(std::u16string_view aURL)
Definition: docfile.cxx:4316
void ReOpen()
Definition: docfile.cxx:3363
SAL_DLLPRIVATE SvKeyValueIterator * GetHeaderAttributes_Impl()
Definition: docfile.cxx:3634
void UnlockFile(bool bReleaseLockStream)
Definition: docfile.cxx:3149
SAL_DLLPRIVATE void TransactedTransferForFS_Impl(const INetURLObject &aSource, const INetURLObject &aDest, const css::uno::Reference< css::ucb::XCommandEnvironment > &xComEnv)
Definition: docfile.cxx:2063
SAL_DLLPRIVATE bool WillDisposeStorageOnClose_Impl()
Definition: docfile.cxx:1952
void CreateTempFile(bool bReplace=true)
Definition: docfile.cxx:3872
void CompleteReOpen()
Definition: docfile.cxx:3371
SAL_DLLPRIVATE void SetCachedSignatureState_Impl(SignatureState nState)
Definition: docfile.cxx:4296
virtual ~SfxMedium() override
Definition: docfile.cxx:3545
static bool CallApproveHandler(const css::uno::Reference< css::task::XInteractionHandler > &xHandler, const css::uno::Any &rRequest, bool bAllowAbort)
Definition: docfile.cxx:4355
void SetOriginallyReadOnly(bool val)
Definition: docfile.cxx:3803
const css::uno::Sequence< css::beans::PropertyValue > & GetArgs() const
Definition: docfile.cxx:3508
SAL_DLLPRIVATE void SetIsRemote_Impl()
Definition: docfile.cxx:3302
SAL_DLLPRIVATE void GetMedium_Impl()
Definition: docfile.cxx:2758
SAL_DLLPRIVATE void RemoveVersion_Impl(const OUString &rVersion)
Definition: docfile.cxx:3734
SAL_DLLPRIVATE const OUString & GetLongName() const
Definition: docfile.cxx:2912
void SetFilter(const std::shared_ptr< const SfxFilter > &pFilter)
Does not take ownership of pFlt but pFlt needs to be around as long as the SfxMedium instance.
Definition: docfile.cxx:3084
ShowLockResult ShowLockedDocumentDialog(const LockFileEntry &aData, bool bIsLoading, bool bOwnLock, bool bHandleSysLocked)
SAL_DLLPRIVATE void CloseStreams_Impl(bool bInDestruction=false)
Definition: docfile.cxx:3290
void SetLoadTargetFrame(SfxFrame *pFrame)
Definition: docfile.cxx:3613
bool IsReadOnly() const
Definition: docfile.cxx:3778
css::uno::Reference< css::ucb::XContent > GetContent() const
Definition: docfile.cxx:590
css::uno::Reference< css::embed::XStorage > GetStorage(bool bCreateTempFile=true)
Definition: docfile.cxx:1703
SAL_DLLPRIVATE void SetExpired_Impl(const DateTime &rDateTime)
Definition: docfile.cxx:3590
SAL_DLLPRIVATE bool IsPreview_Impl() const
Definition: docfile.cxx:896
SvStream * GetOutStream()
Definition: docfile.cxx:741
ImplSVEvent * GetWorkerReloadEvent() const
Definition: docfile.cxx:4536
SAL_DLLPRIVATE void Transfer_Impl()
Definition: docfile.cxx:2272
SAL_DLLPRIVATE void CloseOutStream_Impl()
Definition: docfile.cxx:781
css::uno::Reference< css::io::XInputStream > const & GetInputStream()
Definition: docfile.cxx:3659
SAL_DLLPRIVATE void ClearBackup_Impl()
Definition: docfile.cxx:2694
void SetWorkerReloadEvent(ImplSVEvent *pEvent)
Definition: docfile.cxx:4530
void AddToCheckEditableWorkerList()
Definition: docfile.cxx:4542
OUString SwitchDocumentToTempFile()
Definition: docfile.cxx:4386
bool IsStorage()
Definition: docfile.cxx:865
SAL_DLLPRIVATE void AddVersion_Impl(css::util::RevisionTag &rVersion)
Definition: docfile.cxx:3704
SvStream * GetInStream()
Definition: docfile.cxx:671
void CheckFileDate(const css::util::DateTime &aInitDate)
Definition: docfile.cxx:522
SAL_DLLPRIVATE css::uno::Reference< css::embed::XStorage > const & GetZipStorageToSign_Impl(bool bReadOnly=true)
Definition: docfile.cxx:1878
bool DocNeedsFileDateCheck() const
Definition: docfile.cxx:560
SAL_DLLPRIVATE bool StorageCommit_Impl()
Definition: docfile.cxx:2004
SAL_DLLPRIVATE bool SignContents_Impl(weld::Window *pDialogParent, bool bSignScriptingContent, bool bHasValidDocumentSignature, const OUString &aSignatureLineId=OUString(), const css::uno::Reference< css::security::XCertificate > &xCert=css::uno::Reference< css::security::XCertificate >(), const css::uno::Reference< css::graphic::XGraphic > &xValidGraphic=css::uno::Reference< css::graphic::XGraphic >(), const css::uno::Reference< css::graphic::XGraphic > &xInvalidGraphic=css::uno::Reference< css::graphic::XGraphic >(), const OUString &aComment=OUString())
Definition: docfile.cxx:4119
SAL_DLLPRIVATE void Init_Impl()
Definition: docfile.cxx:2934
void SetArgs(const css::uno::Sequence< css::beans::PropertyValue > &rArgs)
Definition: docfile.cxx:3498
SAL_DLLPRIVATE void CloseZipStorage_Impl()
Definition: docfile.cxx:1910
bool Commit()
Definition: docfile.cxx:839
ErrCode GetWarningError() const
Definition: docfile.cxx:492
const OUString & GetPhysicalName() const
Definition: docfile.cxx:809
css::uno::Reference< css::embed::XStorage > GetOutputStorage()
Definition: docfile.cxx:949
css::uno::Reference< css::task::XInteractionHandler > GetInteractionHandler(bool bGetAlways=false)
Definition: docfile.cxx:3054
const css::uno::Any & GetValue() const
Definition: frame.hxx:175
static SAL_WARN_UNUSED_RESULT SfxViewFrame * GetNext(const SfxViewFrame &rPrev, const SfxObjectShell *pDoc=nullptr, bool bOnlyVisible=true)
Definition: viewfrm.cxx:1989
static SAL_WARN_UNUSED_RESULT SfxViewFrame * GetFirst(const SfxObjectShell *pDoc=nullptr, bool bOnlyVisible=true)
Definition: viewfrm.cxx:1966
static bool IsStorageFile(OUString const &rFileName)
bool IsOLEStorage() const
void SetSynchronMode(bool bTheSync=true)
static SvtFilterOptions & Get()
bool IsMSOLockFileCreationIsEnabled() const
const OUString & GetBackupPath() const
static sal_uInt16 GetXLHashAsUINT16(std::u16string_view aString, rtl_TextEncoding nEnc=RTL_TEXTENCODING_UTF8)
static sal_uInt32 GetWordHashAsUINT32(std::u16string_view aString)
static OUString GetODFVersionFromStorage(const css::uno::Reference< css::embed::XStorage > &xStorage)
static void SetCommonStorageEncryptionData(const css::uno::Reference< css::embed::XStorage > &xStorage, const css::uno::Sequence< css::beans::NamedValue > &aEncryptionData)
static css::uno::Reference< css::embed::XStorage > GetStorageFromURL(const OUString &aURL, sal_Int32 nStorageMode, const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >())
static css::uno::Reference< css::embed::XStorage > GetStorageOfFormatFromInputStream(const OUString &aFormat, const css::uno::Reference< css::io::XInputStream > &xStream, const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >(), bool bRepairStorage=false)
static css::uno::Reference< css::lang::XSingleServiceFactory > GetStorageFactory(const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >())
static css::uno::Reference< css::embed::XStorage > GetStorageOfFormatFromStream(const OUString &aFormat, const css::uno::Reference< css::io::XStream > &xStream, sal_Int32 nStorageMode=css::embed::ElementModes::READWRITE, const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >(), bool bRepairStorage=false)
iterator erase(iterator it)
css::uno::Sequence< css::beans::PropertyValue > getAsConstPropertyValueList() const
static ThreadPool & getSharedOptimalPool()
static std::shared_ptr< ThreadTaskTag > createThreadTaskTag()
void pushTask(std::unique_ptr< ThreadTask > pTask)
virtual void doWork()=0
static css::uno::Reference< css::task::XInteractionRequest > CreateRequest(const css::uno::Any &aRequest, const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > &lContinuations)
rtl::Reference< comphelper::ConfigurationListener > m_xListener
iterator end()
iterator begin()
LockFileEntry GetLockData()
virtual void RemoveFile()
static LockFileEntry GenerateOwnEntry()
const OUString & GetURL() const
virtual void RemoveFile() override
static bool IsMSOSupportedFileFormat(std::u16string_view aURL)
css::uno::Any setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue)
void transferContent(const Content &rSourceContent, InsertOperation eOperation, const OUString &rTitle, const sal_Int32 nNameClashAction, const OUString &rMimeType=OUString(), bool bMajorVersion=false, const OUString &rCommentVersion=OUString(), OUString *pResultURL=nullptr, const OUString &rDocumentId=OUString()) const
css::uno::Any getPropertyValue(const OUString &rPropertyName)
static bool create(const OUString &rURL, const css::uno::Reference< css::ucb::XCommandEnvironment > &rEnv, const css::uno::Reference< css::uno::XComponentContext > &rCtx, Content &rContent)
css::uno::Any executeCommand(const OUString &rCommandName, const css::uno::Any &rCommandArgument)
css::uno::Reference< css::ucb::XContent > get() const
css::uno::Reference< css::io::XInputStream > openStream()
void writeStream(const css::uno::Reference< css::io::XInputStream > &rStream, bool bReplaceExisting)
static bool IsFuzzing()
static constexpr OUStringLiteral PROP_INPUTSTREAM
static constexpr OUStringLiteral PROP_STREAM
static constexpr OUStringLiteral PROP_URL
static constexpr OUStringLiteral PROP_AUTHENTICATIONHANDLER
static constexpr OUStringLiteral PROP_READONLY
void EnableKillingFile(bool bEnable=true)
OUString const & GetURL() const
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
virtual css::uno::Reference< css::awt::XWindow > GetXWindow()=0
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
URL aURL
static std::mutex g_chkReadOnlyGlobalMutex
Definition: docfile.cxx:163
static std::unordered_map< SfxMedium *, std::shared_ptr< ReadOnlyMediumEntry > > g_newReadOnlyDocs
Definition: docfile.cxx:165
IMPL_STATIC_LINK(SfxMedium, ShowReloadEditableDialog, void *, p, void)
callback function, which is triggered by worker thread after successfully checking if the file is edi...
Definition: docfile.cxx:4620
static bool g_bChkReadOnlyTaskRunning
Definition: docfile.cxx:164
static std::unordered_map< SfxMedium *, std::shared_ptr< ReadOnlyMediumEntry > > g_existingReadOnlyDocs
Definition: docfile.cxx:166
uno::Reference< task::XInteractionHandler2 > m_xHandler
float u
sal_Int32 nState
#define ERRCODE_IO_ACCESSDENIED
#define ERRCODE_IO_CANTREAD
#define ERRCODE_IO_GENERAL
#define ERRCODE_IO_NOTEXISTSPATH
#define ERRCODE_IO_CANTWRITE
#define ERRCODE_IO_NOTEXISTS
#define ERRCODE_ABORT
#define ERRCODE_IO_ALREADYEXISTS
#define ERRCODE_NONE
bool bReadOnly
sal_Int32 nIndex
void * p
sal_Int64 n
sal_uInt16 nPos
Definition: linksrc.cxx:118
DdeData aData
Definition: lnkbase2.cxx:82
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
@ Exception
COMPHELPER_DLLPUBLIC bool isFileUrl(std::u16string_view url)
Reference< XComponentContext > getProcessComponentContext()
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
void removeElementAt(css::uno::Sequence< T > &_rSeq, sal_Int32 _nPos)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
std::shared_ptr< osl::Mutex > const & lock()
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
bool IsMappedWebDAVPath(const OUString &rURL, OUString *pRealURL)
UNOTOOLS_DLLPUBLIC css::uno::Reference< css::ucb::XCommandEnvironment > getDefaultCommandEnvironment()
bool GetEncryptionData_Impl(const SfxItemSet *pSet, uno::Sequence< beans::NamedValue > &o_rEncryptionData)
Definition: objstor.cxx:170
#define SFX_STREAM_READONLY
Definition: openflag.hxx:26
#define SFX_STREAM_READWRITE
Definition: openflag.hxx:23
sal_Int16 nAttributes
#define ERRCODE_SFX_CANTCREATEBACKUP
SignatureState