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 = GetItemSet().GetItem(SID_PREVIEW, false);
900 if ( pPreview )
901 bPreview = pPreview->GetValue();
902 else
903 {
904 const SfxStringItem* pFlags = GetItemSet().GetItem(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 = GetItemSet().GetItem(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 = GetItemSet().GetItem(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 = GetItemSet().GetItem(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 = GetItemSet().GetItem(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 = GetItemSet().GetItem<SfxBoolItem>(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(SID_PASSWORD, false);
2215 const SfxStringItem* pOldPassItem = GetItemSet().GetItem(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(SID_FILTER_NAME, false);
2221 const SfxStringItem* pOldFilterItem = GetItemSet().GetItem(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 OUString sObjectId;
2430 try
2431 {
2432 Any aAny = aDestContent.getPropertyValue("Title");
2433 aAny >>= aFileName;
2434 aAny = aDestContent.getPropertyValue("ObjectId");
2435 aAny >>= sObjectId;
2436 }
2437 catch (uno::Exception const&)
2438 {
2439 SAL_INFO("sfx.doc", "exception while getting Title or ObjectId");
2440 }
2441 if ( aFileName.isEmpty() )
2443
2444 try
2445 {
2446 aTransferContent = ::ucbhelper::Content( aDestURL, xComEnv, comphelper::getProcessComponentContext() );
2447 }
2448 catch (const css::ucb::ContentCreationException& ex)
2449 {
2450 pImpl->m_eError = ERRCODE_IO_GENERAL;
2451 if (
2452 (ex.eError == css::ucb::ContentCreationError_NO_CONTENT_PROVIDER ) ||
2453 (ex.eError == css::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
2454 )
2455 {
2456 pImpl->m_eError = ERRCODE_IO_NOTEXISTSPATH;
2457 }
2458 }
2459 catch (const css::uno::Exception&)
2460 {
2461 pImpl->m_eError = ERRCODE_IO_GENERAL;
2462 }
2463
2464 if ( !pImpl->m_eError || pImpl->m_eError.IsWarning() )
2465 {
2466 // free resources, otherwise the transfer may fail
2467 if ( pImpl->xStorage.is() )
2468 CloseStorage();
2469
2471
2473
2474 // check for external parameters that may customize the handling of NameClash situations
2475 const SfxBoolItem* pOverWrite = GetItemSet().GetItem<SfxBoolItem>(SID_OVERWRITE, false);
2476 sal_Int32 nNameClash;
2477 if ( pOverWrite && !pOverWrite->GetValue() )
2478 // argument says: never overwrite
2479 nNameClash = NameClash::ERROR;
2480 else
2481 // default is overwrite existing files
2482 nNameClash = NameClash::OVERWRITE;
2483
2484 try
2485 {
2486 OUString aMimeType = pImpl->getFilterMimeType();
2488 bool bMajor = false;
2489 OUString sComment;
2490 if ( IsInCheckIn( ) )
2491 {
2492 eOperation = ::ucbhelper::InsertOperation::Checkin;
2493 const SfxBoolItem* pMajor = GetItemSet().GetItem<SfxBoolItem>(SID_DOCINFO_MAJOR, false);
2494 bMajor = pMajor && pMajor->GetValue( );
2495 const SfxStringItem* pComments = GetItemSet().GetItem(SID_DOCINFO_COMMENTS, false);
2496 if ( pComments )
2497 sComment = pComments->GetValue( );
2498 }
2499 OUString sResultURL;
2500 aTransferContent.transferContent(
2501 aSourceContent, eOperation,
2502 aFileName, nNameClash, aMimeType, bMajor, sComment,
2503 &sResultURL, sObjectId );
2504
2505 if ( !sResultURL.isEmpty( ) ) // Likely to happen only for checkin
2506 SwitchDocumentToFile( sResultURL );
2507 try
2508 {
2509 if ( GetURLObject().isAnyKnownWebDAVScheme() &&
2511 {
2512 // tdf#95272 try to re-issue a lock command when a new file is created.
2513 // This may be needed because some WebDAV servers fail to implement the
2514 // 'LOCK on unallocated reference', see issue comment:
2515 // <https://bugs.documentfoundation.org/show_bug.cgi?id=95792#c8>
2516 // and specification at:
2517 // <http://tools.ietf.org/html/rfc4918#section-7.3>
2518 // If the WebDAV resource is already locked by this LO instance, nothing will
2519 // happen, e.g. the LOCK method will not be sent to the server.
2521 aLockContent.lock();
2522 }
2523 }
2524 catch ( css::uno::Exception & )
2525 {
2526 TOOLS_WARN_EXCEPTION( "sfx.doc", "LOCK not working while re-issuing it" );
2527 }
2528 }
2529 catch ( const css::ucb::CommandAbortedException& )
2530 {
2531 pImpl->m_eError = ERRCODE_ABORT;
2532 }
2533 catch ( const css::ucb::CommandFailedException& )
2534 {
2535 pImpl->m_eError = ERRCODE_ABORT;
2536 }
2537 catch ( const css::ucb::InteractiveIOException& r )
2538 {
2539 if ( r.Code == IOErrorCode_ACCESS_DENIED )
2540 pImpl->m_eError = ERRCODE_IO_ACCESSDENIED;
2541 else if ( r.Code == IOErrorCode_NOT_EXISTING )
2542 pImpl->m_eError = ERRCODE_IO_NOTEXISTS;
2543 else if ( r.Code == IOErrorCode_CANT_READ )
2544 pImpl->m_eError = ERRCODE_IO_CANTREAD;
2545 else
2546 pImpl->m_eError = ERRCODE_IO_GENERAL;
2547 }
2548 catch ( const css::uno::Exception& )
2549 {
2550 pImpl->m_eError = ERRCODE_IO_GENERAL;
2551 }
2552
2553 // do not switch from temporary file in case of nonfile protocol
2554 }
2555 }
2556
2557 if ( ( !pImpl->m_eError || pImpl->m_eError.IsWarning() ) && !pImpl->pTempFile )
2558 {
2559 // without a TempFile the physical and logical name should be the same after successful transfer
2560 if (osl::FileBase::getSystemPathFromFileURL(
2561 GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), pImpl->m_aName )
2562 != osl::FileBase::E_None)
2563 {
2564 pImpl->m_aName.clear();
2565 }
2566 pImpl->m_bSalvageMode = false;
2567 }
2568}
2569
2570
2571void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent,
2572 std::u16string_view aPrefix,
2573 std::u16string_view aExtension,
2574 const OUString& aDestDir )
2575{
2576 if ( !pImpl->m_aBackupURL.isEmpty() )
2577 return; // the backup was done already
2578
2579 ::utl::TempFileNamed aTransactTemp( aPrefix, true, aExtension, &aDestDir );
2580
2581 INetURLObject aBackObj( aTransactTemp.GetURL() );
2583
2584 Reference < css::ucb::XCommandEnvironment > xDummyEnv;
2585 ::ucbhelper::Content aBackupCont;
2586 if( ::ucbhelper::Content::create( aDestDir, xDummyEnv, comphelper::getProcessComponentContext(), aBackupCont ) )
2587 {
2588 try
2589 {
2590 OUString sMimeType = pImpl->getFilterMimeType();
2591 aBackupCont.transferContent( aOriginalContent,
2593 aBackupName,
2594 NameClash::OVERWRITE,
2595 sMimeType );
2596 pImpl->m_aBackupURL = aBackObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
2597 pImpl->m_bRemoveBackup = true;
2598 }
2599 catch( const Exception& )
2600 {}
2601 }
2602
2603 if ( pImpl->m_aBackupURL.isEmpty() )
2604 aTransactTemp.EnableKillingFile();
2605}
2606
2607
2608void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent )
2609{
2610 if ( !pImpl->m_aBackupURL.isEmpty() )
2611 return; // the backup was done already
2612
2613 OUString aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT,
2614 true,
2616
2617 sal_Int32 nPrefixLen = aFileName.lastIndexOf( '.' );
2618 OUString aPrefix = ( nPrefixLen == -1 ) ? aFileName : aFileName.copy( 0, nPrefixLen );
2619 OUString aExtension = ( nPrefixLen == -1 ) ? OUString() : aFileName.copy( nPrefixLen );
2620 OUString aBakDir = SvtPathOptions().GetBackupPath();
2621
2622 // create content for the parent folder ( = backup folder )
2623 ::ucbhelper::Content aContent;
2624 Reference < css::ucb::XCommandEnvironment > xEnv;
2625 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
2626 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aBakDir );
2627
2628 if ( !pImpl->m_aBackupURL.isEmpty() )
2629 return;
2630
2631 // the copying to the backup catalog failed ( for example because
2632 // of using an encrypted partition as target catalog )
2633 // since the user did not specify to make backup explicitly
2634 // office should try to make backup in another place,
2635 // target catalog does not look bad for this case ( and looks
2636 // to be the only way for encrypted partitions )
2637
2638 INetURLObject aDest = GetURLObject();
2639 if ( aDest.removeSegment() )
2640 DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
2641}
2642
2643
2644void SfxMedium::DoBackup_Impl(bool bForceUsingBackupPath)
2645{
2646 // source file name is the logical name of this medium
2647 INetURLObject aSource( GetURLObject() );
2648
2649 // there is nothing to backup in case source file does not exist
2650 if ( !::utl::UCBContentHelper::IsDocument( aSource.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
2651 return;
2652
2653 bool bSuccess = false;
2654 bool bOnErrorRetryUsingBackupPath = false;
2655
2656 // get path for backups
2657 OUString aBakDir;
2658 if (!bForceUsingBackupPath
2659 && officecfg::Office::Common::Save::Document::BackupIntoDocumentFolder::get())
2660 {
2661 aBakDir = aSource.GetPartBeforeLastName();
2662 bOnErrorRetryUsingBackupPath = true;
2663 }
2664 else
2665 aBakDir = SvtPathOptions().GetBackupPath();
2666 if( !aBakDir.isEmpty() )
2667 {
2668 // create content for the parent folder ( = backup folder )
2669 ::ucbhelper::Content aContent;
2670 Reference < css::ucb::XCommandEnvironment > xEnv;
2671 if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
2672 {
2673 // save as ".bak" file
2674 INetURLObject aDest( aBakDir );
2675 aDest.insertName( aSource.getName() );
2676 const OUString sExt
2677 = aSource.hasExtension() ? aSource.getExtension() + ".bak" : OUString("bak");
2678 aDest.setExtension(sExt);
2680
2681 // create a content for the source file
2682 ::ucbhelper::Content aSourceContent;
2684 {
2685 try
2686 {
2687 // do the transfer ( copy source file to backup dir )
2688 OUString sMimeType = pImpl->getFilterMimeType();
2689 aContent.transferContent( aSourceContent,
2691 aFileName,
2692 NameClash::OVERWRITE,
2693 sMimeType );
2694 pImpl->m_aBackupURL = aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE );
2695 pImpl->m_bRemoveBackup = false;
2696 bSuccess = true;
2697 }
2698 catch ( const css::uno::Exception& )
2699 {
2700 }
2701 }
2702 }
2703 }
2704
2705 if ( !bSuccess )
2706 {
2707 // in case a webdav server prevents file creation, or a partition is full, or whatever...
2708 if (bOnErrorRetryUsingBackupPath)
2709 return DoBackup_Impl(/*bForceUsingBackupPath=*/true);
2710
2712 }
2713}
2714
2715
2717{
2718 if( pImpl->m_bRemoveBackup )
2719 {
2720 // currently a document is always stored in a new medium,
2721 // thus if a backup can not be removed the backup URL should not be cleaned
2722 if ( !pImpl->m_aBackupURL.isEmpty() )
2723 {
2724 if ( ::utl::UCBContentHelper::Kill( pImpl->m_aBackupURL ) )
2725 {
2726 pImpl->m_bRemoveBackup = false;
2727 pImpl->m_aBackupURL.clear();
2728 }
2729 else
2730 {
2731
2732 SAL_WARN( "sfx.doc", "Couldn't remove backup file!");
2733 }
2734 }
2735 }
2736 else
2737 pImpl->m_aBackupURL.clear();
2738}
2739
2740
2742{
2743 if ( GetURLObject().GetProtocol() != INetProtocol::File
2744 || pImpl->m_xLockingStream.is() )
2745 return;
2746
2747 const SfxUnoAnyItem* pWriteStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_STREAM, false);
2748 if ( pWriteStreamItem )
2749 pWriteStreamItem->GetValue() >>= pImpl->m_xLockingStream;
2750
2751 if ( pImpl->m_xLockingStream.is() )
2752 return;
2753
2754 // open the original document
2755 uno::Sequence< beans::PropertyValue > xProps;
2756 TransformItems( SID_OPENDOC, GetItemSet(), xProps );
2757 utl::MediaDescriptor aMedium( xProps );
2758
2759 aMedium.addInputStreamOwnLock();
2760
2761 uno::Reference< io::XInputStream > xInputStream;
2762 aMedium[utl::MediaDescriptor::PROP_STREAM] >>= pImpl->m_xLockingStream;
2763 aMedium[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream;
2764
2765 if ( !pImpl->pTempFile && pImpl->m_aName.isEmpty() )
2766 {
2767 // the medium is still based on the original file, it makes sense to initialize the streams
2768 if ( pImpl->m_xLockingStream.is() )
2769 pImpl->xStream = pImpl->m_xLockingStream;
2770
2771 if ( xInputStream.is() )
2772 pImpl->xInputStream = xInputStream;
2773
2774 if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
2775 pImpl->xInputStream = pImpl->xStream->getInputStream();
2776 }
2777}
2778
2779
2781{
2782 if ( pImpl->m_pInStream
2783 && (!pImpl->bIsTemp || pImpl->xInputStream.is() || pImpl->m_xInputStreamToLoadFrom.is() || pImpl->xStream.is() || pImpl->m_xLockingStream.is() ) )
2784 return;
2785
2786 pImpl->bDownloadDone = false;
2787 Reference< css::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
2788
2789 //TODO/MBA: need support for SID_STREAM
2790 const SfxUnoAnyItem* pWriteStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_STREAM, false);
2791 const SfxUnoAnyItem* pInStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_INPUTSTREAM, false);
2792 if ( pWriteStreamItem )
2793 {
2794 pWriteStreamItem->GetValue() >>= pImpl->xStream;
2795
2796 if ( pInStreamItem )
2797 pInStreamItem->GetValue() >>= pImpl->xInputStream;
2798
2799 if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
2800 pImpl->xInputStream = pImpl->xStream->getInputStream();
2801 }
2802 else if ( pInStreamItem )
2803 {
2804 pInStreamItem->GetValue() >>= pImpl->xInputStream;
2805 }
2806 else
2807 {
2808 uno::Sequence < beans::PropertyValue > xProps;
2809 OUString aFileName;
2810 if (!pImpl->m_aName.isEmpty())
2811 {
2812 if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aFileName )
2813 != osl::FileBase::E_None )
2814 {
2815 SAL_WARN( "sfx.doc", "Physical name not convertible!");
2816 }
2817 }
2818 else
2819 aFileName = GetName();
2820
2821 // in case the temporary file exists the streams should be initialized from it,
2822 // but the original MediaDescriptor should not be changed
2823 bool bFromTempFile = ( pImpl->pTempFile != nullptr );
2824
2825 if ( !bFromTempFile )
2826 {
2827 GetItemSet().Put( SfxStringItem( SID_FILE_NAME, aFileName ) );
2828 if( !(pImpl->m_nStorOpenMode & StreamMode::WRITE) )
2829 GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, true ) );
2830 if (xInteractionHandler.is())
2831 GetItemSet().Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, Any(xInteractionHandler) ) );
2832 }
2833
2834 if ( pImpl->m_xInputStreamToLoadFrom.is() )
2835 {
2836 pImpl->xInputStream = pImpl->m_xInputStreamToLoadFrom;
2837 if (pImpl->m_bInputStreamIsReadOnly)
2838 GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, true ) );
2839 }
2840 else
2841 {
2842 TransformItems( SID_OPENDOC, GetItemSet(), xProps );
2843 utl::MediaDescriptor aMedium( xProps );
2844
2845 if ( pImpl->m_xLockingStream.is() && !bFromTempFile )
2846 {
2847 // the medium is not based on the temporary file, so the original stream can be used
2848 pImpl->xStream = pImpl->m_xLockingStream;
2849 }
2850 else
2851 {
2852 if ( bFromTempFile )
2853 {
2854 aMedium[utl::MediaDescriptor::PROP_URL] <<= aFileName;
2855 aMedium.erase( utl::MediaDescriptor::PROP_READONLY );
2856 aMedium.addInputStream();
2857 }
2858 else if ( GetURLObject().GetProtocol() == INetProtocol::File )
2859 {
2860 // use the special locking approach only for file URLs
2861 aMedium.addInputStreamOwnLock();
2862 }
2863 else
2864 {
2865 // add a check for protocol, if it's http or https or provide webdav then add
2866 // the interaction handler to be used by the authentication dialog
2867 if ( GetURLObject().isAnyKnownWebDAVScheme() )
2868 {
2870 }
2871 aMedium.addInputStream();
2872 }
2873 // the ReadOnly property set in aMedium is ignored
2874 // the check is done in LockOrigFileOnDemand() for file and non-file URLs
2875
2876 //TODO/MBA: what happens if property is not there?!
2877 aMedium[utl::MediaDescriptor::PROP_STREAM] >>= pImpl->xStream;
2878 aMedium[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= pImpl->xInputStream;
2879 }
2880
2881 GetContent();
2882 if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
2883 pImpl->xInputStream = pImpl->xStream->getInputStream();
2884 }
2885
2886 if ( !bFromTempFile )
2887 {
2888 //TODO/MBA: need support for SID_STREAM
2889 if ( pImpl->xStream.is() )
2890 GetItemSet().Put( SfxUnoAnyItem( SID_STREAM, Any( pImpl->xStream ) ) );
2891
2892 GetItemSet().Put( SfxUnoAnyItem( SID_INPUTSTREAM, Any( pImpl->xInputStream ) ) );
2893 }
2894 }
2895
2896 //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor
2897 if ( !GetError() && !pImpl->xStream.is() && !pImpl->xInputStream.is() )
2899
2900 if ( !GetError() && !pImpl->m_pInStream )
2901 {
2902 if ( pImpl->xStream.is() )
2903 pImpl->m_pInStream = utl::UcbStreamHelper::CreateStream( pImpl->xStream );
2904 else if ( pImpl->xInputStream.is() )
2905 pImpl->m_pInStream = utl::UcbStreamHelper::CreateStream( pImpl->xInputStream );
2906 }
2907
2908 pImpl->bDownloadDone = true;
2909 pImpl->aDoneLink.ClearPendingCall();
2910 ErrCode nError = GetError();
2911 pImpl->aDoneLink.Call( reinterpret_cast<void*>(sal_uInt32(nError)) );
2912}
2913
2915{
2916 return pImpl->m_bRemote;
2917}
2918
2920{
2921 pImpl->bUpdatePickList = bVal;
2922}
2923
2925{
2926 return pImpl->bUpdatePickList;
2927}
2928
2929void SfxMedium::SetLongName(const OUString &rName)
2930{
2931 pImpl->m_aLongName = rName;
2932}
2933
2934const OUString& SfxMedium::GetLongName() const
2935{
2936 return pImpl->m_aLongName;
2937}
2938
2940{
2941 pImpl->aDoneLink = rLink;
2942}
2943
2945{
2946 SetDoneLink( aLink );
2947 GetInStream();
2948 if ( pImpl->m_pInStream && !aLink.IsSet() )
2949 {
2950 while( !pImpl->bDownloadDone && !Application::IsQuit())
2952 }
2953}
2954
2955
2957/* [Description]
2958 Includes a valid:: sun:: com:: star:: util:: URL (If a file name was
2959 previously in there) in the logical name and if available sets the
2960 physical name as the file name.
2961 */
2962
2963{
2964 Reference< XOutputStream > rOutStream;
2965
2966 // TODO/LATER: handle lifetime of storages
2967 pImpl->bDisposeStorage = false;
2968
2969 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_DOC_SALVAGE, false);
2970 if ( pSalvageItem && pSalvageItem->GetValue().isEmpty() )
2971 {
2972 pSalvageItem = nullptr;
2973 pImpl->m_pSet->ClearItem( SID_DOC_SALVAGE );
2974 }
2975
2976 if (!pImpl->m_aLogicName.isEmpty())
2977 {
2978 INetURLObject aUrl( pImpl->m_aLogicName );
2979 INetProtocol eProt = aUrl.GetProtocol();
2980 if ( eProt == INetProtocol::NotValid )
2981 {
2982 SAL_WARN( "sfx.doc", "URL <" << pImpl->m_aLogicName << "> with unknown protocol" );
2983 }
2984 else
2985 {
2986 if ( aUrl.HasMark() )
2987 {
2988 std::unique_lock<std::recursive_mutex> chkEditLock;
2989 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
2990 chkEditLock = std::unique_lock<std::recursive_mutex>(
2991 *(pImpl->m_pCheckEditableWorkerMutex));
2993 if (chkEditLock.owns_lock())
2994 chkEditLock.unlock();
2995 GetItemSet().Put( SfxStringItem( SID_JUMPMARK, aUrl.GetMark() ) );
2996 }
2997
2998 // try to convert the URL into a physical name - but never change a physical name
2999 // physical name may be set if the logical name is changed after construction
3000 if ( pImpl->m_aName.isEmpty() )
3001 osl::FileBase::getSystemPathFromFileURL( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), pImpl->m_aName );
3002 else
3003 {
3004 DBG_ASSERT( pSalvageItem, "Suspicious change of logical name!" );
3005 }
3006 }
3007 }
3008
3009 if ( pSalvageItem )
3010 {
3011 std::unique_lock<std::recursive_mutex> chkEditLock;
3012 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
3013 chkEditLock
3014 = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
3015 pImpl->m_aLogicName = pSalvageItem->GetValue();
3016 pImpl->m_pURLObj.reset();
3017 if (chkEditLock.owns_lock())
3018 chkEditLock.unlock();
3019 pImpl->m_bSalvageMode = true;
3020 }
3021
3022 // in case output stream is by mistake here
3023 // clear the reference
3024 const SfxUnoAnyItem* pOutStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_OUTPUTSTREAM, false);
3025 if( pOutStreamItem
3026 && ( !( pOutStreamItem->GetValue() >>= rOutStream )
3027 || !pImpl->m_aLogicName.startsWith("private:stream")) )
3028 {
3029 pImpl->m_pSet->ClearItem( SID_OUTPUTSTREAM );
3030 SAL_WARN( "sfx.doc", "Unexpected Output stream parameter!" );
3031 }
3032
3033 if (!pImpl->m_aLogicName.isEmpty())
3034 {
3035 // if the logic name is set it should be set in MediaDescriptor as well
3036 const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3037 if ( !pFileNameItem )
3038 {
3039 // let the ItemSet be created if necessary
3040 GetItemSet().Put(
3042 SID_FILE_NAME, INetURLObject( pImpl->m_aLogicName ).GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
3043 }
3044 }
3045
3047
3048 osl::DirectoryItem item;
3049 if (osl::DirectoryItem::get(GetName(), item) == osl::FileBase::E_None) {
3050 osl::FileStatus stat(osl_FileStatus_Mask_Attributes);
3051 if (item.getFileStatus(stat) == osl::FileBase::E_None
3052 && stat.isValid(osl_FileStatus_Mask_Attributes))
3053 {
3054 if ((stat.getAttributes() & osl_File_Attribute_ReadOnly) != 0)
3055 {
3056 pImpl->m_bOriginallyReadOnly = true;
3057 }
3058 }
3059 }
3060}
3061
3062
3064{
3065 Init_Impl();
3066}
3067
3068
3070{
3071 pImpl->bAllowDefaultIntHdl = bUse;
3072}
3073
3074
3075css::uno::Reference< css::task::XInteractionHandler >
3077{
3078 // if interaction isn't allowed explicitly ... return empty reference!
3079 if ( !bGetAlways && !pImpl->bUseInteractionHandler )
3080 return css::uno::Reference< css::task::XInteractionHandler >();
3081
3082 // search a possible existing handler inside cached item set
3083 if ( pImpl->m_pSet )
3084 {
3085 css::uno::Reference< css::task::XInteractionHandler > xHandler;
3086 const SfxUnoAnyItem* pHandler = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_INTERACTIONHANDLER, false);
3087 if ( pHandler && (pHandler->GetValue() >>= xHandler) && xHandler.is() )
3088 return xHandler;
3089 }
3090
3091 // if default interaction isn't allowed explicitly ... return empty reference!
3092 if ( !bGetAlways && !pImpl->bAllowDefaultIntHdl )
3093 return css::uno::Reference< css::task::XInteractionHandler >();
3094
3095 // otherwise return cached default handler ... if it exist.
3096 if ( pImpl->xInteraction.is() )
3097 return pImpl->xInteraction;
3098
3099 // create default handler and cache it!
3100 Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
3101 pImpl->xInteraction.set(
3102 task::InteractionHandler::createWithParent(xContext, nullptr), UNO_QUERY_THROW );
3103 return pImpl->xInteraction;
3104}
3105
3106void SfxMedium::SetFilter( const std::shared_ptr<const SfxFilter>& pFilter )
3107{
3108 pImpl->m_pFilter = pFilter;
3109}
3110
3111const std::shared_ptr<const SfxFilter>& SfxMedium::GetFilter() const
3112{
3113 return pImpl->m_pFilter;
3114}
3115
3116sal_uInt32 SfxMedium::CreatePasswordToModifyHash( std::u16string_view aPasswd, bool bWriter )
3117{
3118 sal_uInt32 nHash = 0;
3119
3120 if ( !aPasswd.empty() )
3121 {
3122 if ( bWriter )
3123 {
3125 }
3126 else
3127 {
3128 rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
3129 nHash = ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd, nEncoding );
3130 }
3131 }
3132
3133 return nHash;
3134}
3135
3136
3137void SfxMedium::Close(bool bInDestruction)
3138{
3139 if ( pImpl->xStorage.is() )
3140 {
3141 CloseStorage();
3142 }
3143
3144 CloseStreams_Impl(bInDestruction);
3145
3146 UnlockFile( false );
3147}
3148
3150{
3151 if ( pImpl->xStorage.is() )
3152 {
3153 CloseStorage();
3154 }
3155
3157
3158 UnlockFile( true );
3159}
3160
3161void SfxMedium::DisableUnlockWebDAV( bool bDisableUnlockWebDAV )
3162{
3163 pImpl->m_bDisableUnlockWebDAV = bDisableUnlockWebDAV;
3164}
3165
3166void SfxMedium::DisableFileSync(bool bDisableFileSync)
3167{
3168 pImpl->m_bDisableFileSync = bDisableFileSync;
3169}
3170
3171void SfxMedium::UnlockFile( bool bReleaseLockStream )
3172{
3173#if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
3174 (void) bReleaseLockStream;
3175#else
3176 // check if webdav
3178 {
3179 // do nothing if WebDAV locking if disabled
3180 // (shouldn't happen because we already skipped locking,
3181 // see LockOrigFileOnDemand, but just in case ...)
3182 if (!IsWebDAVLockingUsed())
3183 return;
3184
3185 if ( pImpl->m_bLocked )
3186 {
3187 // an interaction handler should be used for authentication, if needed
3188 try {
3189 uno::Reference< css::task::XInteractionHandler > xHandler = GetInteractionHandler( true );
3190 uno::Reference< css::ucb::XCommandEnvironment > xComEnv = new ::ucbhelper::CommandEnvironment( xHandler,
3191 Reference< css::ucb::XProgressHandler >() );
3193 pImpl->m_bLocked = false;
3194 //check if WebDAV unlock was explicitly disabled
3195 if ( !pImpl->m_bDisableUnlockWebDAV )
3196 aContentToUnlock.unlock();
3197 }
3198 catch ( uno::Exception& )
3199 {
3200 TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
3201 }
3202 }
3203 return;
3204 }
3205
3206 if ( pImpl->m_xLockingStream.is() )
3207 {
3208 if ( bReleaseLockStream )
3209 {
3210 try
3211 {
3212 uno::Reference< io::XInputStream > xInStream = pImpl->m_xLockingStream->getInputStream();
3213 uno::Reference< io::XOutputStream > xOutStream = pImpl->m_xLockingStream->getOutputStream();
3214 if ( xInStream.is() )
3215 xInStream->closeInput();
3216 if ( xOutStream.is() )
3217 xOutStream->closeOutput();
3218 }
3219 catch( const uno::Exception& )
3220 {}
3221 }
3222
3223 pImpl->m_xLockingStream.clear();
3224 }
3225
3226 if ( !pImpl->m_bLocked )
3227 return;
3228
3229 ::svt::DocumentLockFile aLockFile( pImpl->m_aLogicName );
3230
3231 try
3232 {
3233 pImpl->m_bLocked = false;
3234 // TODO/LATER: A warning could be shown in case the file is not the own one
3235 aLockFile.RemoveFile();
3236 }
3237 catch( const io::WrongFormatException& )
3238 {
3239 try
3240 {
3241 // erase the empty or corrupt file
3242 aLockFile.RemoveFileDirectly();
3243 }
3244 catch( const uno::Exception& )
3245 {}
3246 }
3247 catch( const uno::Exception& )
3248 {}
3249
3250 if(!pImpl->m_bMSOLockFileCreated)
3251 return;
3252
3253 ::svt::MSODocumentLockFile aMSOLockFile( pImpl->m_aLogicName );
3254
3255 try
3256 {
3257 pImpl->m_bLocked = false;
3258 // TODO/LATER: A warning could be shown in case the file is not the own one
3259 aMSOLockFile.RemoveFile();
3260 }
3261 catch( const io::WrongFormatException& )
3262 {
3263 try
3264 {
3265 // erase the empty or corrupt file
3266 aMSOLockFile.RemoveFileDirectly();
3267 }
3268 catch( const uno::Exception& )
3269 {}
3270 }
3271 catch( const uno::Exception& )
3272 {}
3273 pImpl->m_bMSOLockFileCreated = false;
3274#endif
3275}
3276
3278{
3280
3281 uno::Reference< io::XInputStream > xInToClose = pImpl->xInputStream;
3282 uno::Reference< io::XOutputStream > xOutToClose;
3283 if ( pImpl->xStream.is() )
3284 {
3285 xOutToClose = pImpl->xStream->getOutputStream();
3286
3287 // if the locking stream is closed here the related member should be cleaned
3288 if ( pImpl->xStream == pImpl->m_xLockingStream )
3289 pImpl->m_xLockingStream.clear();
3290 }
3291
3292 // The probably existing SvStream wrappers should be closed first
3294
3295 // in case of salvage mode the storage is based on the streams
3296 if ( pImpl->m_bSalvageMode )
3297 return;
3298
3299 try
3300 {
3301 if ( xInToClose.is() )
3302 xInToClose->closeInput();
3303 if ( xOutToClose.is() )
3304 xOutToClose->closeOutput();
3305 }
3306 catch ( const uno::Exception& )
3307 {
3308 }
3309}
3310
3311
3312void SfxMedium::CloseStreams_Impl(bool bInDestruction)
3313{
3314 CloseInStream_Impl(bInDestruction);
3316
3317 if ( pImpl->m_pSet )
3318 pImpl->m_pSet->ClearItem( SID_CONTENT );
3319
3320 pImpl->aContent = ::ucbhelper::Content();
3321}
3322
3323
3325{
3326 INetURLObject aObj( GetName() );
3327 switch( aObj.GetProtocol() )
3328 {
3329 case INetProtocol::Ftp:
3330 case INetProtocol::Http:
3331 case INetProtocol::Https:
3332 pImpl->m_bRemote = true;
3333 break;
3334 default:
3335 pImpl->m_bRemote = GetName().startsWith("private:msgid");
3336 break;
3337 }
3338
3339 // As files that are written to the remote transmission must also be able
3340 // to be read.
3341 if (pImpl->m_bRemote)
3342 pImpl->m_nStorOpenMode |= StreamMode::READ;
3343}
3344
3345
3346void SfxMedium::SetName( const OUString& aNameP, bool bSetOrigURL )
3347{
3348 if (pImpl->aOrigURL.isEmpty())
3349 pImpl->aOrigURL = pImpl->m_aLogicName;
3350 if( bSetOrigURL )
3351 pImpl->aOrigURL = aNameP;
3352 std::unique_lock<std::recursive_mutex> chkEditLock;
3353 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
3354 chkEditLock = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
3355 pImpl->m_aLogicName = aNameP;
3356 pImpl->m_pURLObj.reset();
3357 if (chkEditLock.owns_lock())
3358 chkEditLock.unlock();
3359 pImpl->aContent = ::ucbhelper::Content();
3360 Init_Impl();
3361}
3362
3363
3364const OUString& SfxMedium::GetOrigURL() const
3365{
3366 return pImpl->aOrigURL.isEmpty() ? pImpl->m_aLogicName : pImpl->aOrigURL;
3367}
3368
3369
3370void SfxMedium::SetPhysicalName_Impl( const OUString& rNameP )
3371{
3372 if ( rNameP != pImpl->m_aName )
3373 {
3374 pImpl->pTempFile.reset();
3375
3376 if ( !pImpl->m_aName.isEmpty() || !rNameP.isEmpty() )
3377 pImpl->aContent = ::ucbhelper::Content();
3378
3379 pImpl->m_aName = rNameP;
3380 pImpl->m_bTriedStorage = false;
3381 pImpl->bIsStorage = false;
3382 }
3383}
3384
3386{
3387 bool bUseInteractionHandler = pImpl->bUseInteractionHandler;
3388 pImpl->bUseInteractionHandler = false;
3390 pImpl->bUseInteractionHandler = bUseInteractionHandler;
3391}
3392
3394{
3395 // do not use temporary file for reopen and in case of success throw the temporary file away
3396 bool bUseInteractionHandler = pImpl->bUseInteractionHandler;
3397 pImpl->bUseInteractionHandler = false;
3398
3399 std::unique_ptr<::utl::TempFileNamed> pTmpFile;
3400 if ( pImpl->pTempFile )
3401 {
3402 pTmpFile = std::move(pImpl->pTempFile);
3403 pImpl->m_aName.clear();
3404 }
3405
3407
3408 if ( GetError() )
3409 {
3410 if ( pImpl->pTempFile )
3411 {
3412 pImpl->pTempFile->EnableKillingFile();
3413 pImpl->pTempFile.reset();
3414 }
3415 pImpl->pTempFile = std::move( pTmpFile );
3416 if ( pImpl->pTempFile )
3417 pImpl->m_aName = pImpl->pTempFile->GetFileName();
3418 }
3419 else if (pTmpFile)
3420 {
3421 pTmpFile->EnableKillingFile();
3422 pTmpFile.reset();
3423 }
3424
3425 pImpl->bUseInteractionHandler = bUseInteractionHandler;
3426}
3427
3428SfxMedium::SfxMedium(const OUString &rName, StreamMode nOpenMode, std::shared_ptr<const SfxFilter> pFilter, const std::shared_ptr<SfxItemSet>& pInSet) :
3429 pImpl(new SfxMedium_Impl)
3430{
3431 pImpl->m_pSet = pInSet;
3432 pImpl->m_pFilter = std::move(pFilter);
3433 pImpl->m_aLogicName = rName;
3434 pImpl->m_nStorOpenMode = nOpenMode;
3435 Init_Impl();
3436}
3437
3438SfxMedium::SfxMedium(const OUString &rName, const OUString &rReferer, StreamMode nOpenMode, std::shared_ptr<const SfxFilter> pFilter, const std::shared_ptr<SfxItemSet>& pInSet) :
3439 pImpl(new SfxMedium_Impl)
3440{
3441 pImpl->m_pSet = pInSet;
3442 SfxItemSet& s = GetItemSet();
3443 if (s.GetItem(SID_REFERER) == nullptr) {
3444 s.Put(SfxStringItem(SID_REFERER, rReferer));
3445 }
3446 pImpl->m_pFilter = std::move(pFilter);
3447 pImpl->m_aLogicName = rName;
3448 pImpl->m_nStorOpenMode = nOpenMode;
3449 Init_Impl();
3450}
3451
3452SfxMedium::SfxMedium( const uno::Sequence<beans::PropertyValue>& aArgs ) :
3453 pImpl(new SfxMedium_Impl)
3454{
3455 SfxAllItemSet *pParams = new SfxAllItemSet( SfxGetpApp()->GetPool() );
3456 pImpl->m_pSet.reset( pParams );
3457 TransformParameters( SID_OPENDOC, aArgs, *pParams );
3458 SetArgs(aArgs);
3459
3460 OUString aFilterProvider, aFilterName;
3461 {
3462 const SfxStringItem* pItem = nullptr;
3463 if ((pItem = pImpl->m_pSet->GetItemIfSet(SID_FILTER_PROVIDER)))
3464 aFilterProvider = pItem->GetValue();
3465
3466 if ((pItem = pImpl->m_pSet->GetItemIfSet(SID_FILTER_NAME)))
3467 aFilterName = pItem->GetValue();
3468 }
3469
3470 if (aFilterProvider.isEmpty())
3471 {
3472 // This is a conventional filter type.
3473 pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName( aFilterName );
3474 }
3475 else
3476 {
3477 // This filter is from an external provider such as orcus.
3478 pImpl->m_pCustomFilter = std::make_shared<SfxFilter>(aFilterProvider, aFilterName);
3479 pImpl->m_pFilter = pImpl->m_pCustomFilter;
3480 }
3481
3482 const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_DOC_SALVAGE, false);
3483 if( pSalvageItem )
3484 {
3485 // QUESTION: there is some treatment of Salvage in Init_Impl; align!
3486 if ( !pSalvageItem->GetValue().isEmpty() )
3487 {
3488 // if a URL is provided in SalvageItem that means that the FileName refers to a temporary file
3489 // that must be copied here
3490
3491 const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3492 if (!pFileNameItem) throw uno::RuntimeException();
3493 OUString aNewTempFileURL = SfxMedium::CreateTempCopyWithExt( pFileNameItem->GetValue() );
3494 if ( !aNewTempFileURL.isEmpty() )
3495 {
3496 pImpl->m_pSet->Put( SfxStringItem( SID_FILE_NAME, aNewTempFileURL ) );
3497 pImpl->m_pSet->ClearItem( SID_INPUTSTREAM );
3498 pImpl->m_pSet->ClearItem( SID_STREAM );
3499 pImpl->m_pSet->ClearItem( SID_CONTENT );
3500 }
3501 else
3502 {
3503 SAL_WARN( "sfx.doc", "Can not create a new temporary file for crash recovery!" );
3504 }
3505 }
3506 }
3507
3508 const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
3509 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
3510 pImpl->m_bOriginallyLoadedReadOnly = true;
3511
3512 const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3513 if (!pFileNameItem) throw uno::RuntimeException();
3514 pImpl->m_aLogicName = pFileNameItem->GetValue();
3515 pImpl->m_nStorOpenMode = pImpl->m_bOriginallyLoadedReadOnly
3517 Init_Impl();
3518}
3519
3520void SfxMedium::SetArgs(const uno::Sequence<beans::PropertyValue>& rArgs)
3521{
3522 static constexpr OUStringLiteral sStream(u"Stream");
3523 static constexpr OUStringLiteral sInputStream(u"InputStream");
3524 comphelper::SequenceAsHashMap aArgsMap(rArgs);
3525 aArgsMap.erase(sStream);
3526 aArgsMap.erase(sInputStream);
3527 pImpl->m_aArgs = aArgsMap.getAsConstPropertyValueList();
3528}
3529
3530const uno::Sequence<beans::PropertyValue> & SfxMedium::GetArgs() const { return pImpl->m_aArgs; }
3531
3532SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const OUString& rBaseURL, const std::shared_ptr<SfxItemSet>& p ) :
3533 pImpl(new SfxMedium_Impl)
3534{
3535 OUString aType = SfxFilter::GetTypeFromStorage(rStor);
3536 pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4EA( aType );
3537 DBG_ASSERT( pImpl->m_pFilter, "No Filter for storage found!" );
3538
3539 Init_Impl();
3540 pImpl->xStorage = rStor;
3541 pImpl->bDisposeStorage = false;
3542
3543 // always take BaseURL first, could be overwritten by ItemSet
3544 GetItemSet().Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
3545 if ( p )
3546 GetItemSet().Put( *p );
3547}
3548
3549
3550SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const OUString& rBaseURL, const OUString &rTypeName, const std::shared_ptr<SfxItemSet>& p ) :
3551 pImpl(new SfxMedium_Impl)
3552{
3553 pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4EA( rTypeName );
3554 DBG_ASSERT( pImpl->m_pFilter, "No Filter for storage found!" );
3555
3556 Init_Impl();
3557 pImpl->xStorage = rStor;
3558 pImpl->bDisposeStorage = false;
3559
3560 // always take BaseURL first, could be overwritten by ItemSet
3561 GetItemSet().Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
3562 if ( p )
3563 GetItemSet().Put( *p );
3564}
3565
3566// NOTE: should only be called on main thread
3568{
3570
3571 // if there is a requirement to clean the backup this is the last possibility to do it
3573
3574 Close(/*bInDestruction*/true);
3575
3576 if( !pImpl->bIsTemp || pImpl->m_aName.isEmpty() )
3577 return;
3578
3579 OUString aTemp;
3580 if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aTemp )
3581 != osl::FileBase::E_None )
3582 {
3583 SAL_WARN( "sfx.doc", "Physical name not convertible!");
3584 }
3585
3586 if ( !::utl::UCBContentHelper::Kill( aTemp ) )
3587 {
3588 SAL_WARN( "sfx.doc", "Couldn't remove temporary file!");
3589 }
3590}
3591
3592const OUString& SfxMedium::GetName() const
3593{
3594 return pImpl->m_aLogicName;
3595}
3596
3598{
3599 std::unique_lock<std::recursive_mutex> chkEditLock;
3600 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
3601 chkEditLock = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
3602
3603 if (!pImpl->m_pURLObj)
3604 {
3605 pImpl->m_pURLObj.reset( new INetURLObject( pImpl->m_aLogicName ) );
3606 pImpl->m_pURLObj->SetMark(u"");
3607 }
3608
3609 return *pImpl->m_pURLObj;
3610}
3611
3612void SfxMedium::SetExpired_Impl( const DateTime& rDateTime )
3613{
3614 pImpl->aExpireTime = rDateTime;
3615}
3616
3617
3619{
3620 return pImpl->aExpireTime.IsValidAndGregorian() && pImpl->aExpireTime < DateTime( DateTime::SYSTEM );
3621}
3622
3623
3625{
3626 return pImpl->wLoadTargetFrame;
3627}
3628
3629void SfxMedium::setStreamToLoadFrom(const css::uno::Reference<css::io::XInputStream>& xInputStream, bool bIsReadOnly )
3630{
3631 pImpl->m_xInputStreamToLoadFrom = xInputStream;
3632 pImpl->m_bInputStreamIsReadOnly = bIsReadOnly;
3633}
3634
3636{
3637 pImpl->wLoadTargetFrame = pFrame;
3638}
3639
3640
3641void SfxMedium::SetStorage_Impl( const uno::Reference < embed::XStorage >& rStor )
3642{
3643 pImpl->xStorage = rStor;
3644}
3645
3646
3648{
3649 if (!pImpl->m_pSet)
3650 pImpl->m_pSet = std::make_shared<SfxAllItemSet>( SfxGetpApp()->GetPool() );
3651 return *pImpl->m_pSet;
3652}
3653
3654
3656{
3657 if( !pImpl->xAttributes.is() )
3658 {
3659 pImpl->xAttributes = SvKeyValueIteratorRef( new SvKeyValueIterator );
3660
3661 if ( GetContent().is() )
3662 {
3663 try
3664 {
3665 Any aAny = pImpl->aContent.getPropertyValue("MediaType");
3666 OUString aContentType;
3667 aAny >>= aContentType;
3668
3669 pImpl->xAttributes->Append( SvKeyValue( "content-type", aContentType ) );
3670 }
3671 catch ( const css::uno::Exception& )
3672 {
3673 }
3674 }
3675 }
3676
3677 return pImpl->xAttributes.get();
3678}
3679
3680css::uno::Reference< css::io::XInputStream > const & SfxMedium::GetInputStream()
3681{
3682 if ( !pImpl->xInputStream.is() )
3684 return pImpl->xInputStream;
3685}
3686
3687const uno::Sequence < util::RevisionTag >& SfxMedium::GetVersionList( bool _bNoReload )
3688{
3689 // if the medium has no name, then this medium should represent a new document and can have no version info
3690 if ( ( !_bNoReload || !pImpl->m_bVersionsAlreadyLoaded ) && !pImpl->aVersions.hasElements() &&
3691 ( !pImpl->m_aName.isEmpty() || !pImpl->m_aLogicName.isEmpty() ) && GetStorage().is() )
3692 {
3693 uno::Reference < document::XDocumentRevisionListPersistence > xReader =
3694 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3695 try
3696 {
3697 pImpl->aVersions = xReader->load( GetStorage() );
3698 }
3699 catch ( const uno::Exception& )
3700 {
3701 }
3702 }
3703
3704 if ( !pImpl->m_bVersionsAlreadyLoaded )
3705 pImpl->m_bVersionsAlreadyLoaded = true;
3706
3707 return pImpl->aVersions;
3708}
3709
3710uno::Sequence < util::RevisionTag > SfxMedium::GetVersionList( const uno::Reference < embed::XStorage >& xStorage )
3711{
3712 uno::Reference < document::XDocumentRevisionListPersistence > xReader =
3713 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3714 try
3715 {
3716 return xReader->load( xStorage );
3717 }
3718 catch ( const uno::Exception& )
3719 {
3720 }
3721
3722 return uno::Sequence < util::RevisionTag >();
3723}
3724
3725void SfxMedium::AddVersion_Impl( util::RevisionTag& rRevision )
3726{
3727 if ( !GetStorage().is() )
3728 return;
3729
3730 // To determine a unique name for the stream
3731 std::vector<sal_uInt32> aLongs;
3732 sal_Int32 nLength = pImpl->aVersions.getLength();
3733 for ( const auto& rVersion : std::as_const(pImpl->aVersions) )
3734 {
3735 sal_uInt32 nVer = static_cast<sal_uInt32>( o3tl::toInt32(rVersion.Identifier.subView(7)));
3736 size_t n;
3737 for ( n=0; n<aLongs.size(); ++n )
3738 if ( nVer<aLongs[n] )
3739 break;
3740
3741 aLongs.insert( aLongs.begin()+n, nVer );
3742 }
3743
3744 std::vector<sal_uInt32>::size_type nKey;
3745 for ( nKey=0; nKey<aLongs.size(); ++nKey )
3746 if ( aLongs[nKey] > nKey+1 )
3747 break;
3748
3749 OUString aRevName = "Version" + OUString::number( nKey + 1 );
3750 pImpl->aVersions.realloc( nLength+1 );
3751 rRevision.Identifier = aRevName;
3752 pImpl->aVersions.getArray()[nLength] = rRevision;
3753}
3754
3755void SfxMedium::RemoveVersion_Impl( const OUString& rName )
3756{
3757 if ( !pImpl->aVersions.hasElements() )
3758 return;
3759
3760 auto pVersion = std::find_if(std::cbegin(pImpl->aVersions), std::cend(pImpl->aVersions),
3761 [&rName](const auto& rVersion) { return rVersion.Identifier == rName; });
3762 if (pVersion != std::cend(pImpl->aVersions))
3763 {
3764 auto nIndex = static_cast<sal_Int32>(std::distance(std::cbegin(pImpl->aVersions), pVersion));
3766 }
3767}
3768
3770{
3771 if ( rMedium.pImpl->aVersions.hasElements() )
3772 {
3773 pImpl->aVersions = rMedium.pImpl->aVersions;
3774 return true;
3775 }
3776
3777 return false;
3778}
3779
3781{
3782 if ( !GetStorage().is() )
3783 return;
3784
3785 if ( !pImpl->aVersions.hasElements() )
3786 return;
3787
3788 uno::Reference < document::XDocumentRevisionListPersistence > xWriter =
3789 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3790 try
3791 {
3792 xWriter->store( GetStorage(), pImpl->aVersions );
3793 }
3794 catch ( const uno::Exception& )
3795 {
3796 }
3797}
3798
3800{
3801 // a) ReadOnly filter can't produce read/write contents!
3802 bool bReadOnly = pImpl->m_pFilter && (pImpl->m_pFilter->GetFilterFlags() & SfxFilterFlags::OPENREADONLY);
3803
3804 // b) if filter allow read/write contents .. check open mode of the storage
3805 if (!bReadOnly)
3806 bReadOnly = !( GetOpenMode() & StreamMode::WRITE );
3807
3808 // c) the API can force the readonly state!
3809 if (!bReadOnly)
3810 {
3811 const SfxBoolItem* pItem = GetItemSet().GetItem(SID_DOC_READONLY, false);
3812 if (pItem)
3813 bReadOnly = pItem->GetValue();
3814 }
3815
3816 return bReadOnly;
3817}
3818
3820{
3821 return pImpl->m_bOriginallyReadOnly;
3822}
3823
3825{
3826 pImpl->m_bOriginallyReadOnly = val;
3827}
3828
3830{
3831 return pImpl->m_bOriginallyLoadedReadOnly;
3832}
3833
3834bool SfxMedium::SetWritableForUserOnly( const OUString& aURL )
3835{
3836 // UCB does not allow to allow write access only for the user,
3837 // use osl API
3838 bool bResult = false;
3839
3840 ::osl::DirectoryItem aDirItem;
3841 if ( ::osl::DirectoryItem::get( aURL, aDirItem ) == ::osl::FileBase::E_None )
3842 {
3843 ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_Attributes );
3844 if ( aDirItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None
3845 && aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
3846 {
3847 sal_uInt64 nAttributes = aFileStatus.getAttributes();
3848
3849 nAttributes &= ~(osl_File_Attribute_OwnWrite |
3850 osl_File_Attribute_GrpWrite |
3851 osl_File_Attribute_OthWrite |
3852 osl_File_Attribute_ReadOnly);
3853 nAttributes |= (osl_File_Attribute_OwnWrite |
3854 osl_File_Attribute_OwnRead);
3855
3856 bResult = ( osl::File::setAttributes( aURL, nAttributes ) == ::osl::FileBase::E_None );
3857 }
3858 }
3859
3860 return bResult;
3861}
3862
3863namespace
3864{
3866OUString GetLogicBase(const INetURLObject& rURL, std::unique_ptr<SfxMedium_Impl> const & pImpl)
3867{
3868 OUString aLogicBase;
3869
3870#if HAVE_FEATURE_MACOSX_SANDBOX
3871 // In a sandboxed environment we don't want to attempt to create temporary files in the same
3872 // directory where the user has selected an output file to be stored. The sandboxed process has
3873 // permission only to create the specifically named output file in that directory.
3874 (void) rURL;
3875 (void) pImpl;
3876#else
3877
3878 if (!pImpl->m_bHasEmbeddedObjects // Embedded objects would mean a special base, ignore that.
3879 && rURL.GetProtocol() == INetProtocol::File && !pImpl->m_pInStream)
3880 {
3881 // Try to create the temp file in the same directory when storing.
3882 INetURLObject aURL(rURL);
3883 aURL.removeSegment();
3884 aLogicBase = aURL.GetMainURL(INetURLObject::DecodeMechanism::WithCharset);
3885 }
3886
3887#endif // !HAVE_FEATURE_MACOSX_SANDBOX
3888
3889 return aLogicBase;
3890}
3891}
3892
3893void SfxMedium::CreateTempFile( bool bReplace )
3894{
3895 if ( pImpl->pTempFile )
3896 {
3897 if ( !bReplace )
3898 return;
3899
3900 pImpl->pTempFile.reset();
3901 pImpl->m_aName.clear();
3902 }
3903
3904 OUString aLogicBase = GetLogicBase(GetURLObject(), pImpl);
3905 pImpl->pTempFile.reset(new ::utl::TempFileNamed(&aLogicBase));
3906 pImpl->pTempFile->EnableKillingFile();
3907 pImpl->m_aName = pImpl->pTempFile->GetFileName();
3908 OUString aTmpURL = pImpl->pTempFile->GetURL();
3909 if ( pImpl->m_aName.isEmpty() || aTmpURL.isEmpty() )
3910 {
3912 return;
3913 }
3914
3915 if ( !(pImpl->m_nStorOpenMode & StreamMode::TRUNC) )
3916 {
3917 bool bTransferSuccess = false;
3918
3919 if ( GetContent().is()
3920 && GetURLObject().GetProtocol() == INetProtocol::File
3921 && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
3922 {
3923 // if there is already such a document, we should copy it
3924 // if it is a file system use OS copy process
3925 try
3926 {
3927 uno::Reference< css::ucb::XCommandEnvironment > xComEnv;
3928 INetURLObject aTmpURLObj( aTmpURL );
3929 OUString aFileName = aTmpURLObj.getName( INetURLObject::LAST_SEGMENT,
3930 true,
3932 if ( !aFileName.isEmpty() && aTmpURLObj.removeSegment() )
3933 {
3935 OUString sMimeType = pImpl->getFilterMimeType();
3936 aTargetContent.transferContent( pImpl->aContent, ::ucbhelper::InsertOperation::Copy, aFileName, NameClash::OVERWRITE, sMimeType );
3937 SetWritableForUserOnly( aTmpURL );
3938 bTransferSuccess = true;
3939 }
3940 }
3941 catch( const uno::Exception& )
3942 {}
3943
3944 if ( bTransferSuccess )
3945 {
3947 CloseInStream();
3948 }
3949 }
3950
3951 if ( !bTransferSuccess && pImpl->m_pInStream )
3952 {
3953 // the case when there is no URL-access available or this is a remote protocol
3954 // but there is an input stream
3955 GetOutStream();
3956 if ( pImpl->m_pOutStream )
3957 {
3958 std::unique_ptr<char[]> pBuf(new char [8192]);
3959 ErrCode nErr = ERRCODE_NONE;
3960
3961 pImpl->m_pInStream->Seek(0);
3962 pImpl->m_pOutStream->Seek(0);
3963
3964 while( !pImpl->m_pInStream->eof() && nErr == ERRCODE_NONE )
3965 {
3966 sal_uInt32 nRead = pImpl->m_pInStream->ReadBytes(pBuf.get(), 8192);
3967 nErr = pImpl->m_pInStream->GetError();
3968 pImpl->m_pOutStream->WriteBytes( pBuf.get(), nRead );
3969 }
3970
3971 bTransferSuccess = true;
3972 CloseInStream();
3973 }
3975 }
3976 else
3977 {
3978 // Quite strange design, but currently it is expected that in this case no transfer happens
3979 // TODO/LATER: get rid of this inconsistent part of the call design
3980 bTransferSuccess = true;
3981 CloseInStream();
3982 }
3983
3984 if ( !bTransferSuccess )
3985 {
3987 return;
3988 }
3989 }
3990
3991 CloseStorage();
3992}
3993
3994
3996{
3997 // this call always replaces the existing temporary file
3998 pImpl->pTempFile.reset();
3999
4000 OUString aLogicBase = GetLogicBase(GetURLObject(), pImpl);
4001 pImpl->pTempFile.reset(new ::utl::TempFileNamed(&aLogicBase));
4002 pImpl->pTempFile->EnableKillingFile();
4003 pImpl->m_aName = pImpl->pTempFile->GetFileName();
4004 if ( pImpl->m_aName.isEmpty() )
4005 {
4007 return;
4008 }
4009
4011 CloseStorage();
4012}
4013
4015 const css::uno::Reference<css::frame::XModel>& xModel, bool bHasValidDocumentSignature,
4016 const Reference<XCertificate>& xCertificate)
4017{
4018 bool bChanges = false;
4019
4020 if (IsOpen() || GetError())
4021 {
4022 SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
4023 return bChanges;
4024 }
4025
4026 // The component should know if there was a valid document signature, since
4027 // it should show a warning in this case
4029 uno::Reference< security::XDocumentDigitalSignatures > xSigner(
4030 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
4031 comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
4032 auto xModelSigner = dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get());
4033 if (!xModelSigner)
4034 {
4035 return bChanges;
4036 }
4037
4038 uno::Reference< embed::XStorage > xWriteableZipStor;
4039
4040 // we can reuse the temporary file if there is one already
4041 CreateTempFile( false );
4043
4044 try
4045 {
4046 if ( !pImpl->xStream.is() )
4047 throw uno::RuntimeException();
4048
4049 bool bODF = GetFilter()->IsOwnFormat();
4050 try
4051 {
4053 }
4054 catch (const io::IOException&)
4055 {
4056 if (bODF)
4057 {
4058 TOOLS_WARN_EXCEPTION("sfx.doc", "ODF stream is not a zip storage");
4059 }
4060 }
4061
4062 if ( !xWriteableZipStor.is() && bODF )
4063 throw uno::RuntimeException();
4064
4065 uno::Reference< embed::XStorage > xMetaInf;
4066 if (xWriteableZipStor.is() && xWriteableZipStor->hasByName("META-INF"))
4067 {
4068 xMetaInf = xWriteableZipStor->openStorageElement(
4069 "META-INF",
4070 embed::ElementModes::READWRITE );
4071 if ( !xMetaInf.is() )
4072 throw uno::RuntimeException();
4073 }
4074
4075 {
4076 if (xMetaInf.is())
4077 {
4078 // ODF.
4079 uno::Reference< io::XStream > xStream;
4080 if (GetFilter() && GetFilter()->IsOwnFormat())
4081 xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW);
4082
4083 bool bSuccess = xModelSigner->SignModelWithCertificate(
4084 xModel, xCertificate, GetZipStorageToSign_Impl(), xStream);
4085
4086 if (bSuccess)
4087 {
4088 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
4089 xTransact->commit();
4090 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
4091 xTransact->commit();
4092
4093 // the temporary file has been written, commit it to the original file
4094 Commit();
4095 bChanges = true;
4096 }
4097 }
4098 else if (xWriteableZipStor.is())
4099 {
4100 // OOXML.
4101 uno::Reference<io::XStream> xStream;
4102
4103 // We need read-write to be able to add the signature relation.
4104 bool bSuccess = xModelSigner->SignModelWithCertificate(
4105 xModel, xCertificate, GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream);
4106
4107 if (bSuccess)
4108 {
4109 uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
4110 xTransact->commit();
4111
4112 // the temporary file has been written, commit it to the original file
4113 Commit();
4114 bChanges = true;
4115 }
4116 }
4117 else
4118 {
4119 // Something not ZIP based: e.g. PDF.
4120 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | StreamMode::WRITE));
4121 uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream));
4122 if (xModelSigner->SignModelWithCertificate(
4123 xModel, xCertificate, uno::Reference<embed::XStorage>(), xStream))
4124 bChanges = true;
4125 }
4126 }
4127 }
4128 catch ( const uno::Exception& )
4129 {
4130 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!" );
4131 }
4132
4134
4135 ResetError();
4136
4137 return bChanges;
4138}
4139
4141 bool bSignScriptingContent,
4142 bool bHasValidDocumentSignature,
4143 const OUString& aSignatureLineId,
4144 const Reference<XCertificate>& xCert,
4145 const Reference<XGraphic>& xValidGraphic,
4146 const Reference<XGraphic>& xInvalidGraphic,
4147 const OUString& aComment)
4148{
4149 bool bChanges = false;
4150
4151 if (IsOpen() || GetError())
4152 {
4153 SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
4154 return bChanges;
4155 }
4156
4157 // The component should know if there was a valid document signature, since
4158 // it should show a warning in this case
4160 uno::Reference< security::XDocumentDigitalSignatures > xSigner(
4161 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
4162 comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
4163 if (pDialogParent)
4164 xSigner->setParentWindow(pDialogParent->GetXWindow());
4165
4166 uno::Reference< embed::XStorage > xWriteableZipStor;
4167
4168 // we can reuse the temporary file if there is one already
4169 CreateTempFile( false );
4171
4172 try
4173 {
4174 if ( !pImpl->xStream.is() )
4175 throw uno::RuntimeException();
4176
4177 bool bODF = GetFilter()->IsOwnFormat();
4178 try
4179 {
4181 }
4182 catch (const io::IOException&)
4183 {
4184 if (bODF)
4185 {
4186 TOOLS_WARN_EXCEPTION("sfx.doc", "ODF stream is not a zip storage");
4187 }
4188 }
4189
4190 if ( !xWriteableZipStor.is() && bODF )
4191 throw uno::RuntimeException();
4192
4193 uno::Reference< embed::XStorage > xMetaInf;
4194 if (xWriteableZipStor.is() && xWriteableZipStor->hasByName("META-INF"))
4195 {
4196 xMetaInf = xWriteableZipStor->openStorageElement(
4197 "META-INF",
4198 embed::ElementModes::READWRITE );
4199 if ( !xMetaInf.is() )
4200 throw uno::RuntimeException();
4201 }
4202
4203 if ( bSignScriptingContent )
4204 {
4205 // If the signature has already the document signature it will be removed
4206 // after the scripting signature is inserted.
4207 uno::Reference< io::XStream > xStream(
4208 xMetaInf->openStreamElement( xSigner->getScriptingContentSignatureDefaultStreamName(),
4209 embed::ElementModes::READWRITE ),
4210 uno::UNO_SET_THROW );
4211
4212 if ( xSigner->signScriptingContent( GetZipStorageToSign_Impl(), xStream ) )
4213 {
4214 // remove the document signature if any
4215 OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName();
4216 if ( !aDocSigName.isEmpty() && xMetaInf->hasByName( aDocSigName ) )
4217 xMetaInf->removeElement( aDocSigName );
4218
4219 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
4220 xTransact->commit();
4221 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
4222 xTransact->commit();
4223
4224 // the temporary file has been written, commit it to the original file
4225 Commit();
4226 bChanges = true;
4227 }
4228 }
4229 else
4230 {
4231 if (xMetaInf.is())
4232 {
4233 // ODF.
4234 uno::Reference< io::XStream > xStream;
4235 if (GetFilter() && GetFilter()->IsOwnFormat())
4236 xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW);
4237
4238 bool bSuccess = false;
4239 if (xCert.is())
4240 bSuccess = xSigner->signSignatureLine(
4241 GetZipStorageToSign_Impl(), xStream, aSignatureLineId, xCert,
4242 xValidGraphic, xInvalidGraphic, aComment);
4243 else
4244 bSuccess = xSigner->signDocumentContent(GetZipStorageToSign_Impl(),
4245 xStream);
4246
4247 if (bSuccess)
4248 {
4249 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
4250 xTransact->commit();
4251 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
4252 xTransact->commit();
4253
4254 // the temporary file has been written, commit it to the original file
4255 Commit();
4256 bChanges = true;
4257 }
4258 }
4259 else if (xWriteableZipStor.is())
4260 {
4261 // OOXML.
4262 uno::Reference<io::XStream> xStream;
4263
4264 bool bSuccess = false;
4265 if (xCert.is())
4266 {
4267 bSuccess = xSigner->signSignatureLine(
4268 GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream, aSignatureLineId,
4269 xCert, xValidGraphic, xInvalidGraphic, aComment);
4270 }
4271 else
4272 {
4273 // We need read-write to be able to add the signature relation.
4274 bSuccess =xSigner->signDocumentContent(
4275 GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream);
4276 }
4277
4278 if (bSuccess)
4279 {
4280 uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
4281 xTransact->commit();
4282
4283 // the temporary file has been written, commit it to the original file
4284 Commit();
4285 bChanges = true;
4286 }
4287 }
4288 else
4289 {
4290 // Something not ZIP based: e.g. PDF.
4291 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | StreamMode::WRITE));
4292 uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream));
4293 if (xSigner->signDocumentContent(uno::Reference<embed::XStorage>(), xStream))
4294 bChanges = true;
4295 }
4296 }
4297 }
4298 catch ( const uno::Exception& )
4299 {
4300 SAL_WARN( "sfx.doc", "Couldn't use signing functionality!" );
4301 }
4302
4304
4305 ResetError();
4306
4307 return bChanges;
4308}
4309
4310
4312{
4313 return pImpl->m_nSignatureState;
4314}
4315
4316
4318{
4319 pImpl->m_nSignatureState = nState;
4320}
4321
4322void SfxMedium::SetHasEmbeddedObjects(bool bHasEmbeddedObjects)
4323{
4324 pImpl->m_bHasEmbeddedObjects = bHasEmbeddedObjects;
4325}
4326
4328{
4329 return pImpl->xStorage.is();
4330}
4331
4333{
4334 return pImpl->m_pInStream || pImpl->m_pOutStream || pImpl->xStorage.is();
4335}
4336
4337OUString SfxMedium::CreateTempCopyWithExt( std::u16string_view aURL )
4338{
4339 OUString aResult;
4340
4341 if ( !aURL.empty() )
4342 {
4343 size_t nPrefixLen = aURL.rfind( '.' );
4344 std::u16string_view aExt = ( nPrefixLen == std::u16string_view::npos ) ? std::u16string_view() : aURL.substr( nPrefixLen );
4345
4346 OUString aNewTempFileURL = ::utl::CreateTempURL( u"", true, aExt );
4347 if ( !aNewTempFileURL.isEmpty() )
4348 {
4349 INetURLObject aSource( aURL );
4350 INetURLObject aDest( aNewTempFileURL );
4351 OUString aFileName = aDest.getName( INetURLObject::LAST_SEGMENT,
4352 true,
4354 if ( !aFileName.isEmpty() && aDest.removeSegment() )
4355 {
4356 try
4357 {
4358 uno::Reference< css::ucb::XCommandEnvironment > xComEnv;
4361 aTargetContent.transferContent( aSourceContent,
4363 aFileName,
4364 NameClash::OVERWRITE );
4365 aResult = aNewTempFileURL;
4366 }
4367 catch( const uno::Exception& )
4368 {}
4369 }
4370 }
4371 }
4372
4373 return aResult;
4374}
4375
4376bool SfxMedium::CallApproveHandler(const uno::Reference< task::XInteractionHandler >& xHandler, const uno::Any& rRequest, bool bAllowAbort)
4377{
4378 bool bResult = false;
4379
4380 if ( xHandler.is() )
4381 {
4382 try
4383 {
4384 uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( bAllowAbort ? 2 : 1 );
4385 auto pContinuations = aContinuations.getArray();
4386
4387 ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( new ::comphelper::OInteractionApprove );
4388 pContinuations[ 0 ] = pApprove.get();
4389
4390 if ( bAllowAbort )
4391 {
4392 ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( new ::comphelper::OInteractionAbort );
4393 pContinuations[ 1 ] = pAbort.get();
4394 }
4395
4396 xHandler->handle(::framework::InteractionRequest::CreateRequest(rRequest, aContinuations));
4397 bResult = pApprove->wasSelected();
4398 }
4399 catch( const Exception& )
4400 {
4401 }
4402 }
4403
4404 return bResult;
4405}
4406
4408{
4409 // the method returns empty string in case of failure
4410 OUString aResult;
4411 OUString aOrigURL = pImpl->m_aLogicName;
4412
4413 if ( !aOrigURL.isEmpty() )
4414 {
4415 sal_Int32 nPrefixLen = aOrigURL.lastIndexOf( '.' );
4416 std::u16string_view aExt = (nPrefixLen == -1)
4417 ? std::u16string_view()
4418 : aOrigURL.subView(nPrefixLen);
4419 OUString aNewURL = ::utl::CreateTempURL( u"", true, aExt );
4420
4421 // TODO/LATER: In future the aLogicName should be set to shared folder URL
4422 // and a temporary file should be created. Transport_Impl should be impossible then.
4423 if ( !aNewURL.isEmpty() )
4424 {
4425 uno::Reference< embed::XStorage > xStorage = GetStorage();
4426 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
4427
4428 if ( xOptStorage.is() )
4429 {
4430 // TODO/LATER: reuse the pImpl->pTempFile if it already exists
4431 CanDisposeStorage_Impl( false );
4432 Close();
4433 SetPhysicalName_Impl( OUString() );
4434 SetName( aNewURL );
4435
4436 // remove the readonly state
4437 bool bWasReadonly = false;
4438 pImpl->m_nStorOpenMode = SFX_STREAM_READWRITE;
4439 const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
4440 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
4441 bWasReadonly = true;
4442 GetItemSet().ClearItem( SID_DOC_READONLY );
4443
4445 LockOrigFileOnDemand( false, false );
4448
4449 if ( pImpl->xStream.is() )
4450 {
4451 try
4452 {
4453 xOptStorage->writeAndAttachToStream( pImpl->xStream );
4454 pImpl->xStorage = xStorage;
4455 aResult = aNewURL;
4456 }
4457 catch( const uno::Exception& )
4458 {}
4459 }
4460
4461 if (bWasReadonly)
4462 {
4463 // set the readonly state back
4464 pImpl->m_nStorOpenMode = SFX_STREAM_READONLY;
4465 GetItemSet().Put(SfxBoolItem(SID_DOC_READONLY, true));
4466 }
4467
4468 if ( aResult.isEmpty() )
4469 {
4470 Close();
4471 SetPhysicalName_Impl( OUString() );
4472 SetName( aOrigURL );
4474 pImpl->xStorage = xStorage;
4475 }
4476 }
4477 }
4478 }
4479
4480 return aResult;
4481}
4482
4483bool SfxMedium::SwitchDocumentToFile( const OUString& aURL )
4484{
4485 // the method is only for storage based documents
4486 bool bResult = false;
4487 OUString aOrigURL = pImpl->m_aLogicName;
4488
4489 if ( !aURL.isEmpty() && !aOrigURL.isEmpty() )
4490 {
4491 uno::Reference< embed::XStorage > xStorage = GetStorage();
4492 uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
4493
4494 // TODO/LATER: reuse the pImpl->pTempFile if it already exists
4495 CanDisposeStorage_Impl( false );
4496 Close();
4497 SetPhysicalName_Impl( OUString() );
4498 SetName( aURL );
4499
4500 // open the temporary file based document
4502 LockOrigFileOnDemand( false, false );
4505
4506 if ( pImpl->xStream.is() )
4507 {
4508 try
4509 {
4510 uno::Reference< io::XTruncate > xTruncate( pImpl->xStream, uno::UNO_QUERY_THROW );
4511 xTruncate->truncate();
4512 if ( xOptStorage.is() )
4513 xOptStorage->writeAndAttachToStream( pImpl->xStream );
4514 pImpl->xStorage = xStorage;
4515 bResult = true;
4516 }
4517 catch( const uno::Exception& )
4518 {}
4519 }
4520
4521 if ( !bResult )
4522 {
4523 Close();
4524 SetPhysicalName_Impl( OUString() );
4525 SetName( aOrigURL );
4527 pImpl->xStorage = xStorage;
4528 }
4529 }
4530
4531 return bResult;
4532}
4533
4534void SfxMedium::SetInCheckIn( bool bInCheckIn )
4535{
4536 pImpl->m_bInCheckIn = bInCheckIn;
4537}
4538
4540{
4541 return pImpl->m_bInCheckIn;
4542}
4543
4544// should only be called on main thread
4545const std::shared_ptr<std::recursive_mutex>& SfxMedium::GetCheckEditableMutex() const
4546{
4547 return pImpl->m_pCheckEditableWorkerMutex;
4548}
4549
4550// should only be called while holding pImpl->m_pCheckEditableWorkerMutex
4552{
4553 pImpl->m_pReloadEvent = pEvent;
4554}
4555
4556// should only be called while holding pImpl->m_pCheckEditableWorkerMutex
4558{
4559 return pImpl->m_pReloadEvent;
4560}
4561
4562// should only be called on main thread
4564{
4565 if (!pImpl->m_bNotifyWhenEditable)
4566 return;
4567
4569
4570 if (pImpl->m_pCheckEditableWorkerMutex == nullptr)
4571 {
4572 pImpl->m_pCheckEditableWorkerMutex = std::make_shared<std::recursive_mutex>();
4573 if (pImpl->m_pCheckEditableWorkerMutex == nullptr)
4574 return;
4575 }
4576
4577 pImpl->m_pIsDestructed = std::make_shared<bool>(false);
4578 if (pImpl->m_pIsDestructed == nullptr)
4579 return;
4580
4581 std::unique_lock<std::mutex> globalLock(g_chkReadOnlyGlobalMutex);
4582 if (g_newReadOnlyDocs.find(this) == g_newReadOnlyDocs.end())
4583 {
4584 bool bAddNewEntry = false;
4586 {
4587 std::shared_ptr<comphelper::ThreadTaskTag> pTag
4589 if (pTag != nullptr)
4590 {
4592 bAddNewEntry = true;
4594 std::make_unique<CheckReadOnlyTask>(pTag));
4595 }
4596 }
4597 else
4598 bAddNewEntry = true;
4599
4600 if (bAddNewEntry)
4601 {
4602 std::shared_ptr<ReadOnlyMediumEntry> newEntry = std::make_shared<ReadOnlyMediumEntry>(
4603 pImpl->m_pCheckEditableWorkerMutex, pImpl->m_pIsDestructed);
4604
4605 if (newEntry != nullptr)
4606 {
4607 g_newReadOnlyDocs[this] = newEntry;
4608 }
4609 }
4610 }
4611}
4612
4613// should only be called on main thread
4615{
4616 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
4617 {
4618 std::unique_lock<std::recursive_mutex> lock(*(pImpl->m_pCheckEditableWorkerMutex));
4619
4620 if (pImpl->m_pReloadEvent != nullptr)
4621 {
4622 if (bRemoveEvent)
4623 Application::RemoveUserEvent(pImpl->m_pReloadEvent);
4624 // make sure destructor doesn't use a freed reference
4625 // and reset the event so we can check again
4626 pImpl->m_pReloadEvent = nullptr;
4627 }
4628
4629 if (pImpl->m_pIsDestructed != nullptr)
4630 {
4631 *(pImpl->m_pIsDestructed) = true;
4632 pImpl->m_pIsDestructed = nullptr;
4633 }
4634 }
4635}
4636
4641IMPL_STATIC_LINK(SfxMedium, ShowReloadEditableDialog, void*, p, void)
4642{
4643 SfxMedium* pMed = static_cast<SfxMedium*>(p);
4644 if (pMed == nullptr)
4645 return;
4646
4647 pMed->CancelCheckEditableEntry(false);
4648
4649 uno::Reference<task::XInteractionHandler> xHandler = pMed->GetInteractionHandler();
4650 if (xHandler.is())
4651 {
4652 OUString aDocumentURL
4655 = new ::ucbhelper::InteractionRequest(uno::Any(document::ReloadEditableRequest(
4656 OUString(), uno::Reference<uno::XInterface>(), aDocumentURL)));
4657 if (xInteractionRequestImpl != nullptr)
4658 {
4659 uno::Sequence<uno::Reference<task::XInteractionContinuation>> aContinuations{
4660 new ::ucbhelper::InteractionAbort(xInteractionRequestImpl.get()),
4661 new ::ucbhelper::InteractionApprove(xInteractionRequestImpl.get())
4662 };
4663 xInteractionRequestImpl->setContinuations(aContinuations);
4664 xHandler->handle(xInteractionRequestImpl);
4666 = xInteractionRequestImpl->getSelection();
4667 if (uno::Reference<task::XInteractionApprove>(xSelected.get(), uno::UNO_QUERY).is())
4668 {
4669 for (SfxViewFrame* pFrame = SfxViewFrame::GetFirst(); pFrame;
4670 pFrame = SfxViewFrame::GetNext(*pFrame))
4671 {
4672 if (pFrame->GetObjectShell()->GetMedium() == pMed)
4673 {
4674 // special case to ensure view isn't set to read-only in
4675 // SfxViewFrame::ExecReload_Impl after reloading
4676 pMed->SetOriginallyReadOnly(false);
4677 pFrame->GetDispatcher()->Execute(SID_RELOAD);
4678 break;
4679 }
4680 }
4681 }
4682 }
4683 }
4684}
4685
4687{
4688#if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
4689 bool bCanReload = true;
4690#else
4691 bool bCanReload = false;
4692 ::svt::DocumentLockFile aLockFile(GetName());
4694 osl::DirectoryItem rItem;
4695 auto nError1 = osl::DirectoryItem::get(aLockFile.GetURL(), rItem);
4696 if (nError1 == osl::FileBase::E_None)
4697 {
4698 try
4699 {
4700 aData = aLockFile.GetLockData();
4701 }
4702 catch (const io::WrongFormatException&)
4703 {
4704 // we get empty or corrupt data
4705 return false;
4706 }
4707 catch (const uno::Exception&)
4708 {
4709 // locked from other app
4710 return false;
4711 }
4713 bool bOwnLock
4714 = aOwnData[LockFileComponent::SYSUSERNAME] == aData[LockFileComponent::SYSUSERNAME];
4715 if (bOwnLock
4716 && aOwnData[LockFileComponent::LOCALHOST] == aData[LockFileComponent::LOCALHOST]
4717 && aOwnData[LockFileComponent::USERURL] == aData[LockFileComponent::USERURL])
4718 {
4719 // this is own lock from the same installation, it could remain because of crash
4720 bCanReload = true;
4721 }
4722 }
4723 else if (nError1 == osl::FileBase::E_NOENT) // file doesn't exist
4724 {
4725 try
4726 {
4727 aLockFile.CreateOwnLockFile();
4728 try
4729 {
4730 // TODO/LATER: A warning could be shown in case the file is not the own one
4731 aLockFile.RemoveFile();
4732 }
4733 catch (const io::WrongFormatException&)
4734 {
4735 try
4736 {
4737 // erase the empty or corrupt file
4738 aLockFile.RemoveFileDirectly();
4739 }
4740 catch (const uno::Exception&)
4741 {
4742 }
4743 }
4744 bCanReload = true;
4745 }
4746 catch (const uno::Exception&)
4747 {
4748 }
4749 }
4750#endif
4751 return bCanReload;
4752}
4753
4754// worker thread method, should only be one thread globally
4755void CheckReadOnlyTask::doWork()
4756{
4757 if (m_xListener == nullptr)
4758 return;
4759
4760 while (true)
4761 {
4762 std::unique_lock<std::mutex> termLock(m_xListener->mMutex);
4763 if (m_xListener->mCond.wait_for(termLock, std::chrono::seconds(60),
4764 [this] { return m_xListener->bIsTerminated; }))
4765 // signalled, spurious wakeups should not be possible
4766 return;
4767
4768 // must have timed-out
4769 termLock.unlock();
4770 std::unique_lock<std::mutex> globalLock(g_chkReadOnlyGlobalMutex);
4771 for (auto it = g_newReadOnlyDocs.begin(); it != g_newReadOnlyDocs.end(); )
4772 {
4773 auto [pMed, roEntry] = *it;
4774 g_existingReadOnlyDocs[pMed] = roEntry;
4775 it = g_newReadOnlyDocs.erase(it);
4776 }
4777 if (g_existingReadOnlyDocs.size() == 0)
4778 {
4780 return;
4781 }
4782 globalLock.unlock();
4783
4784 auto checkForErase = [](SfxMedium* pMed, const std::shared_ptr<ReadOnlyMediumEntry>& roEntry) -> bool
4785 {
4786 if (pMed == nullptr || roEntry == nullptr || roEntry->_pMutex == nullptr
4787 || roEntry->_pIsDestructed == nullptr)
4788 return true;
4789
4790 std::unique_lock<std::recursive_mutex> medLock(*(roEntry->_pMutex));
4791 if (*(roEntry->_pIsDestructed) || pMed->GetWorkerReloadEvent() != nullptr)
4792 return true;
4793
4794 osl::File aFile(
4796 if (aFile.open(osl_File_OpenFlag_Write) != osl::FileBase::E_None)
4797 return false;
4798
4799 if (!pMed->CheckCanGetLockfile())
4800 return false;
4801
4802 if (aFile.close() != osl::FileBase::E_None)
4803 return true;
4804
4805 // we can load, ask user
4807 LINK(nullptr, SfxMedium, ShowReloadEditableDialog), pMed);
4808 pMed->SetWorkerReloadEvent(pEvent);
4809 return true;
4810 };
4811
4812 for (auto it = g_existingReadOnlyDocs.begin(); it != g_existingReadOnlyDocs.end(); )
4813 {
4814 if (checkForErase(it->first, it->second))
4815 it = g_existingReadOnlyDocs.erase(it);
4816 else
4817 ++it;
4818 }
4819 }
4820}
4821
4822/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PropertiesInfo aProperties
Reference< XInputStream > xStream
SfxApplication * SfxGetpApp()
Definition: app.hxx:231
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
bool hasExtension() const
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString getExtension(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, 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
OUString GetPartBeforeLastName() 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:4686
SAL_DLLPRIVATE void GetLockingStream_Impl()
Definition: docfile.cxx:2741
SfxFrame * GetLoadTargetFrame() const
Definition: docfile.cxx:3624
void CloseStorage()
Definition: docfile.cxx:1923
ErrCode const & GetLastStorageCreationState() const
Definition: docfile.cxx:497
bool IsOpen() const
Definition: docfile.cxx:4332
void CreateTempFileNoCopy()
Definition: docfile.cxx:3995
bool IsExpired() const
Definition: docfile.cxx:3618
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:3111
void DisableFileSync(bool bDisableFileSync)
Lets Transfer_Impl() not fsync the output file.
Definition: docfile.cxx:3166
SAL_DLLPRIVATE void CloseAndReleaseStreams_Impl()
Definition: docfile.cxx:3277
void SetError(ErrCode nError)
Definition: docfile.cxx:502
void Close(bool bInDestruction=false)
Definition: docfile.cxx:3137
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:3629
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:4322
bool IsOriginallyLoadedReadOnly() const
Definition: docfile.cxx:3829
const INetURLObject & GetURLObject() const
Definition: docfile.cxx:3597
void UseInteractionHandler(bool)
Definition: docfile.cxx:3069
SAL_DLLPRIVATE bool IsUpdatePickList() const
Definition: docfile.cxx:2924
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:3641
void CloseAndRelease()
Definition: docfile.cxx:3149
SfxItemSet & GetItemSet() const
Definition: docfile.cxx:3647
void Download(const Link< void *, void > &aLink=Link< void *, void >())
Definition: docfile.cxx:2944
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:2608
SAL_DLLPRIVATE void SetPhysicalName_Impl(const OUString &rName)
Definition: docfile.cxx:3370
SAL_DLLPRIVATE SignatureState GetCachedSignatureState_Impl() const
Definition: docfile.cxx:4311
bool IsSkipImages() const
Definition: docfile.cxx:665
ErrCode GetErrorCode() const
Definition: docfile.cxx:512
SAL_DLLPRIVATE void SetUpdatePickList(bool)
Definition: docfile.cxx:2919
void SetDoneLink(const Link< void *, void > &rLink)
Definition: docfile.cxx:2939
SAL_DLLPRIVATE void CanDisposeStorage_Impl(bool bDisposeStorage)
Definition: docfile.cxx:1947
void SetInCheckIn(bool bInCheckIn)
Definition: docfile.cxx:4534
SAL_DLLPRIVATE void SaveVersionList_Impl()
Definition: docfile.cxx:3780
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:3819
bool ShowLockFileProblemDialog(MessageDlg nWhichDlg)
ErrCode GetError() const
Definition: docfile.hxx:147
SAL_DLLPRIVATE void DoBackup_Impl(bool bForceUsingBackupPath)
Definition: docfile.cxx:2644
SAL_DLLPRIVATE OUString const & GetBackup_Impl()
Definition: docfile.cxx:940
SAL_DLLPRIVATE bool TransferVersionList_Impl(SfxMedium const &rMedium)
Definition: docfile.cxx:3769
StreamMode GetOpenMode() const
Definition: docfile.cxx:1957
static sal_uInt32 CreatePasswordToModifyHash(std::u16string_view aPasswd, bool bWriter)
Definition: docfile.cxx:3116
std::unique_ptr< SfxMedium_Impl > pImpl
Definition: docfile.hxx:66
bool IsInCheckIn() const
Definition: docfile.cxx:4539
const OUString & GetOrigURL() const
Definition: docfile.cxx:3364
SAL_DLLPRIVATE void SetLongName(const OUString &rName)
Definition: docfile.cxx:2929
void CloseOutStream()
Definition: docfile.cxx:776
void SetName(const OUString &rName, bool bSetOrigURL=false)
Definition: docfile.cxx:3346
const css::uno::Sequence< css::util::RevisionTag > & GetVersionList(bool _bNoReload=false)
Definition: docfile.cxx:3687
const OUString & GetName() const
Definition: docfile.cxx:3592
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:4014
void DisableUnlockWebDAV(bool bDisableUnlockWebDAV=true)
Definition: docfile.cxx:3161
const std::shared_ptr< std::recursive_mutex > & GetCheckEditableMutex() const
Definition: docfile.cxx:4545
SAL_DLLPRIVATE void StorageBackup_Impl()
Definition: docfile.cxx:918
void CancelCheckEditableEntry(bool bRemoveEvent=true)
Definition: docfile.cxx:4614
void SetWarningError(ErrCode nWarningError)
Definition: docfile.cxx:507
bool IsRemote() const
Definition: docfile.cxx:2914
bool SwitchDocumentToFile(const OUString &aURL)
Definition: docfile.cxx:4483
static bool SetWritableForUserOnly(const OUString &aURL)
Definition: docfile.cxx:3834
SAL_DLLPRIVATE bool HasStorage_Impl() const
Definition: docfile.cxx:4327
static OUString CreateTempCopyWithExt(std::u16string_view aURL)
Definition: docfile.cxx:4337
void ReOpen()
Definition: docfile.cxx:3385
SAL_DLLPRIVATE SvKeyValueIterator * GetHeaderAttributes_Impl()
Definition: docfile.cxx:3655
void UnlockFile(bool bReleaseLockStream)
Definition: docfile.cxx:3171
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:3893
void CompleteReOpen()
Definition: docfile.cxx:3393
SAL_DLLPRIVATE void SetCachedSignatureState_Impl(SignatureState nState)
Definition: docfile.cxx:4317
virtual ~SfxMedium() override
Definition: docfile.cxx:3567
static bool CallApproveHandler(const css::uno::Reference< css::task::XInteractionHandler > &xHandler, const css::uno::Any &rRequest, bool bAllowAbort)
Definition: docfile.cxx:4376
void SetOriginallyReadOnly(bool val)
Definition: docfile.cxx:3824
const css::uno::Sequence< css::beans::PropertyValue > & GetArgs() const
Definition: docfile.cxx:3530
SAL_DLLPRIVATE void SetIsRemote_Impl()
Definition: docfile.cxx:3324
SAL_DLLPRIVATE void GetMedium_Impl()
Definition: docfile.cxx:2780
SAL_DLLPRIVATE void RemoveVersion_Impl(const OUString &rVersion)
Definition: docfile.cxx:3755
SAL_DLLPRIVATE const OUString & GetLongName() const
Definition: docfile.cxx:2934
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:3106
ShowLockResult ShowLockedDocumentDialog(const LockFileEntry &aData, bool bIsLoading, bool bOwnLock, bool bHandleSysLocked)
SAL_DLLPRIVATE void CloseStreams_Impl(bool bInDestruction=false)
Definition: docfile.cxx:3312
void SetLoadTargetFrame(SfxFrame *pFrame)
Definition: docfile.cxx:3635
bool IsReadOnly() const
Definition: docfile.cxx:3799
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:3612
SAL_DLLPRIVATE bool IsPreview_Impl() const
Definition: docfile.cxx:896
SvStream * GetOutStream()
Definition: docfile.cxx:741
ImplSVEvent * GetWorkerReloadEvent() const
Definition: docfile.cxx:4557
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:3680
SAL_DLLPRIVATE void ClearBackup_Impl()
Definition: docfile.cxx:2716
void SetWorkerReloadEvent(ImplSVEvent *pEvent)
Definition: docfile.cxx:4551
void AddToCheckEditableWorkerList()
Definition: docfile.cxx:4563
OUString SwitchDocumentToTempFile()
Definition: docfile.cxx:4407
bool IsStorage()
Definition: docfile.cxx:865
SAL_DLLPRIVATE void AddVersion_Impl(css::util::RevisionTag &rVersion)
Definition: docfile.cxx:3725
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:4140
SAL_DLLPRIVATE void Init_Impl()
Definition: docfile.cxx:2956
void SetArgs(const css::uno::Sequence< css::beans::PropertyValue > &rArgs)
Definition: docfile.cxx:3520
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:3076
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:2006
static SAL_WARN_UNUSED_RESULT SfxViewFrame * GetFirst(const SfxObjectShell *pDoc=nullptr, bool bOnlyVisible=true)
Definition: viewfrm.cxx:1983
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:4641
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
const sal_Unicode *const aMimeType[]
constexpr OUStringLiteral ZIP_STORAGE_FORMAT_STRING
StreamMode
Reference< XModel > xModel
INetProtocol
sal_Int32 nLength