xref: /core/sfx2/source/doc/docfile.cxx (revision 16bd75a56c16cce6d07284d041f225a81550eb48)
154c2e3c8STor Lillqvist /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2e2799d25SMichael Meeks /*
3e2799d25SMichael Meeks  * This file is part of the LibreOffice project.
4fd069beeSJens-Heiner Rechtien  *
5e2799d25SMichael Meeks  * This Source Code Form is subject to the terms of the Mozilla Public
6e2799d25SMichael Meeks  * License, v. 2.0. If a copy of the MPL was not distributed with this
7e2799d25SMichael Meeks  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
88dd61c3eSRüdiger Timm  *
9e2799d25SMichael Meeks  * This file incorporates work covered by the following license notice:
108dd61c3eSRüdiger Timm  *
11e2799d25SMichael Meeks  *   Licensed to the Apache Software Foundation (ASF) under one or more
12e2799d25SMichael Meeks  *   contributor license agreements. See the NOTICE file distributed
13e2799d25SMichael Meeks  *   with this work for additional information regarding copyright
14e2799d25SMichael Meeks  *   ownership. The ASF licenses this file to you under the Apache
15e2799d25SMichael Meeks  *   License, Version 2.0 (the "License"); you may not use this file
16e2799d25SMichael Meeks  *   except in compliance with the License. You may obtain a copy of
17e2799d25SMichael Meeks  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18e2799d25SMichael Meeks  */
1983e80133SOliver Bolte 
20a8c3c673STor Lillqvist #include <config_features.h>
21a8c3c673STor Lillqvist 
22546ed01eSMiklos Vajna #ifdef UNX
23546ed01eSMiklos Vajna #include <sys/stat.h>
24546ed01eSMiklos Vajna #endif
25546ed01eSMiklos Vajna 
26534d0d81SJens-Heiner Rechtien #include <sfx2/docfile.hxx>
279a26a423SNorbert Thiebaud #include <sfx2/signaturestate.hxx>
28fd069beeSJens-Heiner Rechtien 
29c25cb8a6SNoel Grandin #include <com/sun/star/task/InteractionHandler.hpp>
30ea68858cSGabor Kelemen #include <com/sun/star/task/XStatusIndicator.hpp>
317ad49c6fSMathias Bauer #include <com/sun/star/uno/Reference.h>
327ad49c6fSMathias Bauer #include <com/sun/star/ucb/XContent.hpp>
33c77a5343SMike Kaganski #include <com/sun/star/beans/StringPair.hpp>
341d221869SMichael Stahl #include <com/sun/star/beans/XPropertySet.hpp>
35966d20e3SCédric Bosdonnat #include <com/sun/star/container/XChild.hpp>
36b5181a5eSVladimir Glazounov #include <com/sun/star/document/XDocumentRevisionListPersistence.hpp>
372058774bSVladimir Glazounov #include <com/sun/star/document/LockedDocumentRequest.hpp>
38a30f8c4dSMike Kaganski #include <com/sun/star/document/LockedOnSavingRequest.hpp>
393dfe5a3fSJens-Heiner Rechtien #include <com/sun/star/document/OwnLockOnDocumentRequest.hpp>
403dfe5a3fSJens-Heiner Rechtien #include <com/sun/star/document/LockFileIgnoreRequest.hpp>
416ca3b364SJuergen Funk #include <com/sun/star/document/LockFileCorruptRequest.hpp>
423dfe5a3fSJens-Heiner Rechtien #include <com/sun/star/document/ChangedByOthersRequest.hpp>
4395eb0888SMatt K #include <com/sun/star/document/ReloadEditableRequest.hpp>
44762dd2b1SKurt Zenker #include <com/sun/star/embed/XTransactedObject.hpp>
45762dd2b1SKurt Zenker #include <com/sun/star/embed/ElementModes.hpp>
46762dd2b1SKurt Zenker #include <com/sun/star/embed/UseBackupException.hpp>
47117456a0SKurt Zenker #include <com/sun/star/embed/XOptimizedStorage.hpp>
4895eb0888SMatt K #include <com/sun/star/frame/Desktop.hpp>
49c3f87022SMiklos Vajna #include <com/sun/star/frame/XModel.hpp>
5095eb0888SMatt K #include <com/sun/star/frame/XTerminateListener.hpp>
516499ea2fSSamuel Mehrbrodt #include <com/sun/star/graphic/XGraphic.hpp>
529784934cSGabor Kelemen #include <com/sun/star/ucb/ContentCreationException.hpp>
53a73d45b8SMathias Bauer #include <com/sun/star/ucb/InteractiveIOException.hpp>
54a73d45b8SMathias Bauer #include <com/sun/star/ucb/CommandFailedException.hpp>
550856787dSMathias Bauer #include <com/sun/star/ucb/CommandAbortedException.hpp>
56b4576f3dSGiuseppe Castagno #include <com/sun/star/ucb/InteractiveLockingLockedException.hpp>
57b1f25771SMichael Stahl #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
5803263524SGiuseppe Castagno #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
59b4576f3dSGiuseppe Castagno #include <com/sun/star/ucb/Lock.hpp>
60a62878ffSAndreas Heinisch #include <com/sun/star/ucb/NameClashException.hpp>
61a73d45b8SMathias Bauer #include <com/sun/star/ucb/XCommandEnvironment.hpp>
62dfb5d4faSMikhail Voitenko #include <com/sun/star/ucb/XProgressHandler.hpp>
63fd069beeSJens-Heiner Rechtien #include <com/sun/star/io/XOutputStream.hpp>
64fd069beeSJens-Heiner Rechtien #include <com/sun/star/io/XInputStream.hpp>
65762dd2b1SKurt Zenker #include <com/sun/star/io/XTruncate.hpp>
667ad49c6fSMathias Bauer #include <com/sun/star/io/XSeekable.hpp>
673b347664SMichael Stahl #include <com/sun/star/io/TempFile.hpp>
6880152c8cSGabor Kelemen #include <com/sun/star/lang/XSingleServiceFactory.hpp>
69fd069beeSJens-Heiner Rechtien #include <com/sun/star/ucb/InsertCommandArgument.hpp>
70fd069beeSJens-Heiner Rechtien #include <com/sun/star/ucb/NameClash.hpp>
713b347664SMichael Stahl #include <com/sun/star/util/XModifiable.hpp>
7280152c8cSGabor Kelemen #include <com/sun/star/beans/NamedValue.hpp>
737165de29SMathias Bauer #include <com/sun/star/beans/PropertyValue.hpp>
74197a79e5SNoel Grandin #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
7586e8cfddSSamuel Mehrbrodt #include <com/sun/star/security/XCertificate.hpp>
767ad49c6fSMathias Bauer #include <tools/urlobj.hxx>
77642a49e8SMike Kaganski #include <tools/fileutil.hxx>
78a523b7c4SCaolán McNamara #include <unotools/configmgr.hxx>
790042696fSMathias Bauer #include <unotools/tempfile.hxx>
804a5ab800SMichael Meeks #include <comphelper/lok.hxx>
815da0dce1SStephan Bergmann #include <comphelper/fileurl.hxx>
82c8d2e22eSNoel Grandin #include <comphelper/memorystream.hxx>
8308581794SMathias Bauer #include <comphelper/processfactory.hxx>
84ce22935aSMike Kaganski #include <comphelper/propertyvalue.hxx>
85661e2cc1SMathias Bauer #include <comphelper/interaction.hxx>
8625b200ffSArkadiy Illarionov #include <comphelper/sequence.hxx>
873b26a2a4SGiuseppe Castagno #include <comphelper/simplefileaccessinteraction.hxx>
8836e0e88bSNoel Grandin #include <comphelper/string.hxx>
89ac49eeddSIvo Hinkelmann #include <framework/interaction.hxx>
9017a2c9e8SNoel Grandin #include <utility>
919f2fde7aSMathias Bauer #include <svl/stritem.hxx>
929f2fde7aSMathias Bauer #include <svl/eitem.hxx>
937ad49c6fSMathias Bauer #include <svtools/sfxecode.hxx>
949f2fde7aSMathias Bauer #include <svl/itemset.hxx>
959f2fde7aSMathias Bauer #include <svl/intitem.hxx>
96a7724966STor Lillqvist #include <svtools/svparser.hxx>
97b5867945SGabor Kelemen #include <sal/log.hxx>
98fd069beeSJens-Heiner Rechtien 
99762dd2b1SKurt Zenker #include <unotools/streamwrap.hxx>
100762dd2b1SKurt Zenker 
101ac49eeddSIvo Hinkelmann #include <osl/file.hxx>
10297de8bf5SOliver Bolte 
103762dd2b1SKurt Zenker #include <comphelper/storagehelper.hxx>
10424cad6a6SStephan Bergmann #include <unotools/mediadescriptor.hxx>
105e0986b32SMikhail Voytenko #include <comphelper/docpasswordhelper.hxx>
10609186fceSMatúš Kukan #include <tools/datetime.hxx>
107bff284e2SMathias Bauer #include <unotools/pathoptions.hxx>
108364b6ba9SDirk Völzke #include <svtools/asynclink.hxx>
109dfb5d4faSMikhail Voitenko #include <ucbhelper/commandenvironment.hxx>
1107165de29SMathias Bauer #include <unotools/ucbstreamhelper.hxx>
1115b978509SMathias Bauer #include <unotools/ucbhelper.hxx>
1125be98ebaSJens-Heiner Rechtien #include <unotools/progresshandlerwrap.hxx>
1135b978509SMathias Bauer #include <ucbhelper/content.hxx>
1142058774bSVladimir Glazounov #include <ucbhelper/interactionrequest.hxx>
1157df89ec7SStephan Bergmann #include <sot/storage.hxx>
1169f2fde7aSMathias Bauer #include <svl/documentlockfile.hxx>
11741dc917bSTamás Zolnai #include <svl/msodocumentlockfile.hxx>
1188c31a6baSNoel Grandin #include <com/sun/star/document/DocumentRevisionListPersistence.hpp>
1197ad49c6fSMathias Bauer 
120a7724966STor Lillqvist #include <sfx2/app.hxx>
121a7724966STor Lillqvist #include <sfx2/frame.hxx>
12295eb0888SMatt K #include <sfx2/dispatch.hxx>
123a7724966STor Lillqvist #include <sfx2/fcontnr.hxx>
124a7724966STor Lillqvist #include <sfx2/docfilt.hxx>
12500657aefSCaolán McNamara #include <sfx2/sfxsids.hrc>
12680152c8cSGabor Kelemen #include <sfx2/sfxuno.hxx>
1271c46c7a0SStephan Bergmann #include <openflag.hxx>
1289a26a423SNorbert Thiebaud #include <officecfg/Office/Common.hxx>
12916a52236SMiklos Vajna #include <comphelper/propertysequence.hxx>
130e8d0ab58SMike Kaganski #include <vcl/embeddedfontsmanager.hxx>
131bb9481a4SCaolán McNamara #include <vcl/weld.hxx>
1324304226dSGabor Kelemen #include <vcl/svapp.hxx>
13391ba9654SStephan Bergmann #include <comphelper/diagnose_ex.hxx>
134c3f87022SMiklos Vajna #include <sfx2/digitalsignatures.hxx>
13595eb0888SMatt K #include <sfx2/viewfrm.hxx>
13695eb0888SMatt K #include <comphelper/threadpool.hxx>
1373e767973SNoel Grandin #include <o3tl/string_view.hxx>
13812e50825SMiklos Vajna #include <svl/cryptosign.hxx>
13995eb0888SMatt K #include <condition_variable>
140fd069beeSJens-Heiner Rechtien 
1416ca3b364SJuergen Funk #include <com/sun/star/io/WrongFormatException.hpp>
1426ca3b364SJuergen Funk 
143eaf2c278SCaolán McNamara #include <memory>
144938d2f95SKohei Yoshida 
145938d2f95SKohei Yoshida using namespace ::com::sun::star;
1466499ea2fSSamuel Mehrbrodt using namespace ::com::sun::star::graphic;
147938d2f95SKohei Yoshida using namespace ::com::sun::star::uno;
148938d2f95SKohei Yoshida using namespace ::com::sun::star::ucb;
149938d2f95SKohei Yoshida using namespace ::com::sun::star::beans;
150938d2f95SKohei Yoshida using namespace ::com::sun::star::io;
15186e8cfddSSamuel Mehrbrodt using namespace ::com::sun::star::security;
152938d2f95SKohei Yoshida 
15395eb0888SMatt K namespace
15495eb0888SMatt K {
15595eb0888SMatt K 
15695eb0888SMatt K struct ReadOnlyMediumEntry
15795eb0888SMatt K {
ReadOnlyMediumEntry__anon6928f1030111::ReadOnlyMediumEntry15895eb0888SMatt K     ReadOnlyMediumEntry(std::shared_ptr<std::recursive_mutex> pMutex,
15995eb0888SMatt K                         std::shared_ptr<bool> pIsDestructed)
1608c15ccc2SNoel Grandin         : _pMutex(std::move(pMutex))
1618c15ccc2SNoel Grandin         , _pIsDestructed(std::move(pIsDestructed))
16295eb0888SMatt K     {
16395eb0888SMatt K     }
16495eb0888SMatt K     std::shared_ptr<std::recursive_mutex> _pMutex;
16595eb0888SMatt K     std::shared_ptr<bool> _pIsDestructed;
16695eb0888SMatt K };
16795eb0888SMatt K 
16895eb0888SMatt K }
16995eb0888SMatt K 
17095eb0888SMatt K static std::mutex g_chkReadOnlyGlobalMutex;
17195eb0888SMatt K static bool g_bChkReadOnlyTaskRunning = false;
17295eb0888SMatt K static std::unordered_map<SfxMedium*, std::shared_ptr<ReadOnlyMediumEntry>> g_newReadOnlyDocs;
17395eb0888SMatt K static std::unordered_map<SfxMedium*, std::shared_ptr<ReadOnlyMediumEntry>> g_existingReadOnlyDocs;
17495eb0888SMatt K 
1753dfe5a3fSJens-Heiner Rechtien namespace {
176a245ebc7SIvo Hinkelmann 
1771370a016STor Lillqvist #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1781370a016STor Lillqvist 
IsSystemFileLockingUsed()17950b4cbe9SKohei Yoshida bool IsSystemFileLockingUsed()
180a245ebc7SIvo Hinkelmann {
181063b3280STor Lillqvist #if HAVE_FEATURE_MACOSX_SANDBOX
182063b3280STor Lillqvist     return true;
183063b3280STor Lillqvist #else
184c02b3f85SJulien Nabet     return officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::get();
185063b3280STor Lillqvist #endif
186a245ebc7SIvo Hinkelmann }
187a245ebc7SIvo Hinkelmann 
1880ce0c369SAlexander Wilms 
IsOOoLockFileUsed()18950b4cbe9SKohei Yoshida bool IsOOoLockFileUsed()
190a245ebc7SIvo Hinkelmann {
191063b3280STor Lillqvist #if HAVE_FEATURE_MACOSX_SANDBOX
192063b3280STor Lillqvist     return false;
193063b3280STor Lillqvist #else
194c02b3f85SJulien Nabet     return officecfg::Office::Common::Misc::UseDocumentOOoLockFile::get();
195063b3280STor Lillqvist #endif
196a245ebc7SIvo Hinkelmann }
197a245ebc7SIvo Hinkelmann 
IsLockingUsed()198300b39ccSMarkus Mohrhard bool IsLockingUsed()
199300b39ccSMarkus Mohrhard {
2006fca59d9SStephan Bergmann     return officecfg::Office::Common::Misc::UseLocking::get();
201300b39ccSMarkus Mohrhard }
202300b39ccSMarkus Mohrhard 
2033ee3e794STor Lillqvist #endif
2043ee3e794STor Lillqvist 
2052452c3f0SMichael Stahl #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
IsWebDAVLockingUsed()206297be63cSKatarina Behrens bool IsWebDAVLockingUsed()
207297be63cSKatarina Behrens {
208297be63cSKatarina Behrens     return officecfg::Office::Common::Misc::UseWebDAVFileLocking::get();
209297be63cSKatarina Behrens }
2102452c3f0SMichael Stahl #endif
211297be63cSKatarina Behrens 
212fb04780cSMiklos Vajna /// Gets default attributes of a file:// URL.
GetDefaultFileAttributes(const OUString & rURL)213fb04780cSMiklos Vajna sal_uInt64 GetDefaultFileAttributes(const OUString& rURL)
214fb04780cSMiklos Vajna {
215fb04780cSMiklos Vajna     sal_uInt64 nRet = 0;
216fb04780cSMiklos Vajna 
217fb04780cSMiklos Vajna     if (!comphelper::isFileUrl(rURL))
218fb04780cSMiklos Vajna         return nRet;
219fb04780cSMiklos Vajna 
22038afe297SMiklos Vajna     // Make sure the file exists (and create it if not).
221fb04780cSMiklos Vajna     osl::File aFile(rURL);
22238afe297SMiklos Vajna     osl::File::RC nRes = aFile.open(osl_File_OpenFlag_Create);
22338afe297SMiklos Vajna     if (nRes != osl::File::E_None && nRes != osl::File::E_EXIST)
224fb04780cSMiklos Vajna         return nRet;
225fb04780cSMiklos Vajna 
226fb04780cSMiklos Vajna     aFile.close();
227fb04780cSMiklos Vajna 
228fb04780cSMiklos Vajna     osl::DirectoryItem aItem;
229fb04780cSMiklos Vajna     if (osl::DirectoryItem::get(rURL, aItem) != osl::DirectoryItem::E_None)
230fb04780cSMiklos Vajna         return nRet;
231fb04780cSMiklos Vajna 
232fb04780cSMiklos Vajna     osl::FileStatus aStatus(osl_FileStatus_Mask_Attributes);
233fb04780cSMiklos Vajna     if (aItem.getFileStatus(aStatus) != osl::DirectoryItem::E_None)
234fb04780cSMiklos Vajna         return nRet;
235fb04780cSMiklos Vajna 
236fb04780cSMiklos Vajna     nRet = aStatus.getAttributes();
237fb04780cSMiklos Vajna     return nRet;
238fb04780cSMiklos Vajna }
239fb04780cSMiklos Vajna 
2407823684cSMiklos Vajna /// Determines if rURL is safe to move or not.
IsFileMovable(const INetURLObject & rURL)241603b63b4SMike Kaganski bool IsFileMovable(const INetURLObject& rURL)
242546ed01eSMiklos Vajna {
2437823684cSMiklos Vajna #ifdef MACOSX
2447823684cSMiklos Vajna     (void)rURL;
2457823684cSMiklos Vajna     // Hide extension macOS-specific file property would be lost.
2467823684cSMiklos Vajna     return false;
2477823684cSMiklos Vajna #else
2487823684cSMiklos Vajna 
249603b63b4SMike Kaganski     if (rURL.GetProtocol() != INetProtocol::File)
2507823684cSMiklos Vajna         // Not a file:// URL.
251546ed01eSMiklos Vajna         return false;
252546ed01eSMiklos Vajna 
253546ed01eSMiklos Vajna #ifdef UNX
254603b63b4SMike Kaganski     OUString sPath = rURL.getFSysPath(FSysStyle::Unix);
255603b63b4SMike Kaganski     if (sPath.isEmpty())
256546ed01eSMiklos Vajna         return false;
257546ed01eSMiklos Vajna 
258546ed01eSMiklos Vajna     struct stat buf;
259603b63b4SMike Kaganski     if (lstat(sPath.toUtf8().getStr(), &buf) != 0)
260546ed01eSMiklos Vajna         return false;
261546ed01eSMiklos Vajna 
26272be5ac0SMiklos Vajna     // Hardlink or symlink: osl::File::move() doesn't play with these nicely.
26372be5ac0SMiklos Vajna     if (buf.st_nlink > 1 || S_ISLNK(buf.st_mode))
264546ed01eSMiklos Vajna         return false;
26563cb8d9dSMiklos Vajna 
26663cb8d9dSMiklos Vajna     // Read-only target path: this would be silently replaced.
26763cb8d9dSMiklos Vajna     if (access(sPath.toUtf8().getStr(), W_OK) == -1)
26863cb8d9dSMiklos Vajna         return false;
26963cb8d9dSMiklos Vajna 
270603b63b4SMike Kaganski #elif defined _WIN32
27120b1e644SMike Kaganski     if (tools::IsMappedWebDAVPath(rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)))
272603b63b4SMike Kaganski         return false;
273546ed01eSMiklos Vajna #endif
274546ed01eSMiklos Vajna 
275546ed01eSMiklos Vajna     return true;
2767823684cSMiklos Vajna #endif
277546ed01eSMiklos Vajna }
278546ed01eSMiklos Vajna 
27995eb0888SMatt K class CheckReadOnlyTaskTerminateListener
28095eb0888SMatt K     : public ::cppu::WeakImplHelper<css::frame::XTerminateListener>
28195eb0888SMatt K {
28295eb0888SMatt K public:
28395eb0888SMatt K     // XEventListener
28495eb0888SMatt K     void SAL_CALL disposing(const css::lang::EventObject& Source) override;
28595eb0888SMatt K 
28695eb0888SMatt K     // XTerminateListener
28795eb0888SMatt K     void SAL_CALL queryTermination(const css::lang::EventObject& aEvent) override;
28895eb0888SMatt K     void SAL_CALL notifyTermination(const css::lang::EventObject& aEvent) override;
28995eb0888SMatt K 
29095eb0888SMatt K     bool bIsTerminated = false;
29195eb0888SMatt K     std::condition_variable mCond;
29295eb0888SMatt K     std::mutex mMutex;
29395eb0888SMatt K };
29495eb0888SMatt K 
29595eb0888SMatt K class CheckReadOnlyTask : public comphelper::ThreadTask
29695eb0888SMatt K {
29795eb0888SMatt K public:
29895eb0888SMatt K     CheckReadOnlyTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag);
29995eb0888SMatt K     ~CheckReadOnlyTask();
30095eb0888SMatt K 
30195eb0888SMatt K     virtual void doWork() override;
30295eb0888SMatt K 
30395eb0888SMatt K private:
30495eb0888SMatt K     rtl::Reference<CheckReadOnlyTaskTerminateListener> m_xListener;
30595eb0888SMatt K };
30695eb0888SMatt K 
307a245ebc7SIvo Hinkelmann } // anonymous namespace
308c7c40687SAlexander Wilms 
CheckReadOnlyTask(const std::shared_ptr<comphelper::ThreadTaskTag> & pTag)30995eb0888SMatt K CheckReadOnlyTask::CheckReadOnlyTask(const std::shared_ptr<comphelper::ThreadTaskTag>& pTag)
31095eb0888SMatt K     : ThreadTask(pTag)
31195eb0888SMatt K     , m_xListener(new CheckReadOnlyTaskTerminateListener)
31295eb0888SMatt K {
31395eb0888SMatt K     Reference<css::frame::XDesktop> xDesktop
31495eb0888SMatt K         = css::frame::Desktop::create(comphelper::getProcessComponentContext());
31595eb0888SMatt K     if (xDesktop.is() && m_xListener != nullptr)
31695eb0888SMatt K     {
31795eb0888SMatt K         xDesktop->addTerminateListener(m_xListener);
31895eb0888SMatt K     }
31995eb0888SMatt K }
32095eb0888SMatt K 
~CheckReadOnlyTask()32195eb0888SMatt K CheckReadOnlyTask::~CheckReadOnlyTask()
32295eb0888SMatt K {
32395eb0888SMatt K     Reference<css::frame::XDesktop> xDesktop
32495eb0888SMatt K         = css::frame::Desktop::create(comphelper::getProcessComponentContext());
32595eb0888SMatt K     if (xDesktop.is() && m_xListener != nullptr)
32695eb0888SMatt K     {
32795eb0888SMatt K         std::unique_lock<std::mutex> lock(m_xListener->mMutex);
32895eb0888SMatt K         if (!m_xListener->bIsTerminated)
32995eb0888SMatt K         {
33095eb0888SMatt K             lock.unlock();
33195eb0888SMatt K             xDesktop->removeTerminateListener(m_xListener);
33295eb0888SMatt K         }
33395eb0888SMatt K     }
33495eb0888SMatt K }
33595eb0888SMatt K 
33695eb0888SMatt K namespace
33795eb0888SMatt K {
33895eb0888SMatt K void SAL_CALL
disposing(const css::lang::EventObject &)33995eb0888SMatt K CheckReadOnlyTaskTerminateListener::disposing(const css::lang::EventObject& /*Source*/)
34095eb0888SMatt K {
34195eb0888SMatt K }
34295eb0888SMatt K 
34395eb0888SMatt K void SAL_CALL
queryTermination(const css::lang::EventObject &)34495eb0888SMatt K CheckReadOnlyTaskTerminateListener::queryTermination(const css::lang::EventObject& /*aEvent*/)
34595eb0888SMatt K {
34695eb0888SMatt K }
34795eb0888SMatt K 
34895eb0888SMatt K void SAL_CALL
notifyTermination(const css::lang::EventObject &)34995eb0888SMatt K CheckReadOnlyTaskTerminateListener::notifyTermination(const css::lang::EventObject& /*aEvent*/)
35095eb0888SMatt K {
35195eb0888SMatt K     std::unique_lock<std::mutex> lock(mMutex);
35295eb0888SMatt K     bIsTerminated = true;
35395eb0888SMatt K     lock.unlock();
35495eb0888SMatt K     mCond.notify_one();
35595eb0888SMatt K }
3564a5ab800SMichael Meeks 
3572c8610f5SAndrea Gelmini /// Temporary file wrapper to handle tmp file lifecycle
3584a5ab800SMichael Meeks /// for lok fork a background saving worker issues.
3594a5ab800SMichael Meeks class MediumTempFile : public ::utl::TempFileNamed
3604a5ab800SMichael Meeks {
3614a5ab800SMichael Meeks     bool m_bWasChild;
3624a5ab800SMichael Meeks public:
MediumTempFile(const OUString * pParent)3634a5ab800SMichael Meeks     MediumTempFile(const OUString *pParent )
3644a5ab800SMichael Meeks         : ::utl::TempFileNamed(pParent)
3654a5ab800SMichael Meeks         , m_bWasChild(comphelper::LibreOfficeKit::isForkedChild())
3664a5ab800SMichael Meeks     {
3674a5ab800SMichael Meeks     }
3684a5ab800SMichael Meeks 
3694a5ab800SMichael Meeks     MediumTempFile(const MediumTempFile &rFrom ) = delete;
3704a5ab800SMichael Meeks 
~MediumTempFile()3714a5ab800SMichael Meeks     ~MediumTempFile()
3724a5ab800SMichael Meeks     {
3734a5ab800SMichael Meeks         bool isForked = comphelper::LibreOfficeKit::isForkedChild();
3744a5ab800SMichael Meeks 
3754a5ab800SMichael Meeks         // avoid deletion of files created by the parent
3764a5ab800SMichael Meeks         if (isForked && ! m_bWasChild)
3774a5ab800SMichael Meeks         {
3784a5ab800SMichael Meeks             EnableKillingFile(false);
3794a5ab800SMichael Meeks         }
3804a5ab800SMichael Meeks     }
3814a5ab800SMichael Meeks };
38295eb0888SMatt K }
38395eb0888SMatt K 
3840de868cdSJochen Nitschke class SfxMedium_Impl
385fd069beeSJens-Heiner Rechtien {
386fd069beeSJens-Heiner Rechtien public:
38711f2a588SKohei Yoshida     StreamMode m_nStorOpenMode;
388d9e322d6SNoel Grandin     ErrCodeMsg m_eError;
389d9e322d6SNoel Grandin     ErrCodeMsg m_eWarningError;
390f9ac1ab1SKohei Yoshida 
3915d88f117SIvo Hinkelmann     ::ucbhelper::Content aContent;
392df8a15d8SKohei Yoshida     bool bUpdatePickList:1;
393df8a15d8SKohei Yoshida     bool bIsTemp:1;
394df8a15d8SKohei Yoshida     bool bDownloadDone:1;
395df8a15d8SKohei Yoshida     bool bIsStorage:1;
396df8a15d8SKohei Yoshida     bool bUseInteractionHandler:1;
397df8a15d8SKohei Yoshida     bool bAllowDefaultIntHdl:1;
398df8a15d8SKohei Yoshida     bool bDisposeStorage:1;
399df8a15d8SKohei Yoshida     bool bStorageBasedOnInStream:1;
400df8a15d8SKohei Yoshida     bool m_bSalvageMode:1;
401df8a15d8SKohei Yoshida     bool m_bVersionsAlreadyLoaded:1;
402df8a15d8SKohei Yoshida     bool m_bLocked:1;
40341dc917bSTamás Zolnai     bool m_bMSOLockFileCreated : 1;
404b4576f3dSGiuseppe Castagno     bool m_bDisableUnlockWebDAV:1;
405df8a15d8SKohei Yoshida     bool m_bGotDateTime:1;
406dcceacb5SKohei Yoshida     bool m_bRemoveBackup:1;
407dcceacb5SKohei Yoshida     bool m_bOriginallyReadOnly:1;
408191c0a9eSStephan Bergmann     bool m_bOriginallyLoadedReadOnly:1;
409ed4ee6afSKohei Yoshida     bool m_bTriedStorage:1;
4103faf775cSKohei Yoshida     bool m_bRemote:1;
4111e355662SKohei Yoshida     bool m_bInputStreamIsReadOnly:1;
4121a926112SCédric Bosdonnat     bool m_bInCheckIn:1;
413d03a7547SMiklos Vajna     bool m_bDisableFileSync = false;
41495eb0888SMatt K     bool m_bNotifyWhenEditable = false;
4153b347664SMichael Stahl     /// if true, xStorage is an inner package and not directly from xStream
4163b347664SMichael Stahl     bool m_bODFWholesomeEncryption = false;
4173dfe5a3fSJens-Heiner Rechtien 
418fdd24dabSMike Kaganski     /// If there are such fonts, the document can't be set into editing mode;
419fdd24dabSMike Kaganski     /// these can't be embedded on save.
420fdd24dabSMike Kaganski     bool hasRestrictedFonts = false;
421badc9c68SMike Kaganski     /// font family, file URL
422c77a5343SMike Kaganski     std::vector<std::pair<OUString, OUString>> m_aEmbeddedFonts;
423badc9c68SMike Kaganski     std::vector<std::pair<OUString, OUString>> m_aEmbeddedFontsToActivate;
424badc9c68SMike Kaganski 
425d7f5f26bSKohei Yoshida     OUString m_aName;
426c44f1e7eSKohei Yoshida     OUString m_aLogicName;
427f9ac1ab1SKohei Yoshida     OUString m_aLongName;
428d7f5f26bSKohei Yoshida 
429cc4dbe47SNoel Grandin     mutable std::shared_ptr<SfxItemSet> m_pSet;
430e4c40331SNoel Grandin     mutable std::unique_ptr<INetURLObject> m_pURLObj;
4315f43d902SKohei Yoshida 
432e94d5233SMarkus Mohrhard     std::shared_ptr<const SfxFilter> m_pFilter;
433e94d5233SMarkus Mohrhard     std::shared_ptr<const SfxFilter> m_pCustomFilter;
4340552a09bSKohei Yoshida 
43595eb0888SMatt K     std::shared_ptr<std::recursive_mutex> m_pCheckEditableWorkerMutex;
43695eb0888SMatt K     std::shared_ptr<bool> m_pIsDestructed;
43795eb0888SMatt K     ImplSVEvent* m_pReloadEvent;
43895eb0888SMatt K 
43965e41592SNoel Grandin     std::unique_ptr<SvStream> m_pInStream;
44065e41592SNoel Grandin     std::unique_ptr<SvStream> m_pOutStream;
441fd069beeSJens-Heiner Rechtien 
4421946794aSLuboš Luňák     OUString    aOrigURL;
443fd069beeSJens-Heiner Rechtien     DateTime         aExpireTime;
444490d3028SNoel Grandin     SfxFrameWeakRef  wLoadTargetFrame;
445fd069beeSJens-Heiner Rechtien     SvKeyValueIteratorRef xAttributes;
446fd069beeSJens-Heiner Rechtien 
447364b6ba9SDirk Völzke     svtools::AsynchronLink  aDoneLink;
448fd069beeSJens-Heiner Rechtien 
449b5181a5eSVladimir Glazounov     uno::Sequence < util::RevisionTag > aVersions;
450b5181a5eSVladimir Glazounov 
4514a5ab800SMichael Meeks     std::unique_ptr<MediumTempFile> pTempFile;
452fd069beeSJens-Heiner Rechtien 
453dad7b573SKohei Yoshida     uno::Reference<embed::XStorage> xStorage;
454ac49eeddSIvo Hinkelmann     uno::Reference<embed::XStorage> m_xZipStorage;
455dad7b573SKohei Yoshida     uno::Reference<io::XInputStream> m_xInputStreamToLoadFrom;
456dad7b573SKohei Yoshida     uno::Reference<io::XInputStream> xInputStream;
457dad7b573SKohei Yoshida     uno::Reference<io::XStream> xStream;
45889fd6a8fSMikhail Voitenko     uno::Reference<io::XStream> m_xLockingStream;
459dad7b573SKohei Yoshida     uno::Reference<task::XInteractionHandler> xInteraction;
460c8d2e22eSNoel Grandin     rtl::Reference< comphelper::UNOMemoryStream > m_xODFDecryptedInnerPackageStream;
4613b347664SMichael Stahl     uno::Reference<embed::XStorage> m_xODFEncryptedOuterStorage;
4623b347664SMichael Stahl     uno::Reference<embed::XStorage> m_xODFDecryptedInnerZipStorage;
46389fd6a8fSMikhail Voitenko 
464d9e322d6SNoel Grandin     ErrCodeMsg  nLastStorageError;
465a20f3410SMikhail Voitenko 
4661946794aSLuboš Luňák     OUString m_aBackupURL;
4675be98ebaSJens-Heiner Rechtien 
468dad7b573SKohei Yoshida     // the following member is changed and makes sense only during saving
4699e332587SOliver Bolte     // TODO/LATER: in future the signature state should be controlled by the medium not by the document
4709e332587SOliver Bolte     //             in this case the member will hold this information
471d208cf83SNoel Grandin     SignatureState             m_nSignatureState;
4729e332587SOliver Bolte 
473c1676204SMiklos Vajna     bool m_bHasEmbeddedObjects = false;
474c1676204SMiklos Vajna 
4753dfe5a3fSJens-Heiner Rechtien     util::DateTime m_aDateTime;
4763dfe5a3fSJens-Heiner Rechtien 
477e0f20211SMiklos Vajna     uno::Sequence<beans::PropertyValue> m_aArgs;
478e0f20211SMiklos Vajna 
4791aa29c82SNoel Grandin     explicit SfxMedium_Impl();
480fd069beeSJens-Heiner Rechtien     ~SfxMedium_Impl();
4810de868cdSJochen Nitschke     SfxMedium_Impl(const SfxMedium_Impl&) = delete;
4820de868cdSJochen Nitschke     SfxMedium_Impl& operator=(const SfxMedium_Impl&) = delete;
483cba921eaSStephan Bergmann 
getFilterMimeType() const484df905f41SNoel Grandin     OUString getFilterMimeType() const
485e94d5233SMarkus Mohrhard         { return !m_pFilter ? OUString() : m_pFilter->GetMimeType(); }
486fd069beeSJens-Heiner Rechtien };
487fd069beeSJens-Heiner Rechtien 
SfxMedium_Impl()4881aa29c82SNoel Grandin SfxMedium_Impl::SfxMedium_Impl() :
48911f2a588SKohei Yoshida     m_nStorOpenMode(SFX_STREAM_READWRITE),
490de8caac6SNoel Grandin     m_eError(ERRCODE_NONE),
49129dad1e4SXisco Fauli     m_eWarningError(ERRCODE_NONE),
492f9ac1ab1SKohei Yoshida     bUpdatePickList(true),
493df8a15d8SKohei Yoshida     bIsTemp( false ),
494df8a15d8SKohei Yoshida     bDownloadDone( true ),
495df8a15d8SKohei Yoshida     bIsStorage( false ),
496df8a15d8SKohei Yoshida     bUseInteractionHandler( true ),
497df8a15d8SKohei Yoshida     bAllowDefaultIntHdl( false ),
4981f79b55bSJulien Nabet     bDisposeStorage( false ),
499df8a15d8SKohei Yoshida     bStorageBasedOnInStream( false ),
500df8a15d8SKohei Yoshida     m_bSalvageMode( false ),
501df8a15d8SKohei Yoshida     m_bVersionsAlreadyLoaded( false ),
502df8a15d8SKohei Yoshida     m_bLocked( false ),
50341dc917bSTamás Zolnai     m_bMSOLockFileCreated( false ),
504b4576f3dSGiuseppe Castagno     m_bDisableUnlockWebDAV( false ),
505df8a15d8SKohei Yoshida     m_bGotDateTime( false ),
506dcceacb5SKohei Yoshida     m_bRemoveBackup( false ),
507dcceacb5SKohei Yoshida     m_bOriginallyReadOnly(false),
508191c0a9eSStephan Bergmann     m_bOriginallyLoadedReadOnly(false),
509ed4ee6afSKohei Yoshida     m_bTriedStorage(false),
5103faf775cSKohei Yoshida     m_bRemote(false),
5111e355662SKohei Yoshida     m_bInputStreamIsReadOnly(false),
5121a926112SCédric Bosdonnat     m_bInCheckIn(false),
51395eb0888SMatt K     m_pReloadEvent(nullptr),
51484efa408STakeshi Abe     aExpireTime( DateTime( DateTime::SYSTEM ) + static_cast<sal_Int32>(10) ),
51552863266SNoel Grandin     nLastStorageError( ERRCODE_NONE ),
516d208cf83SNoel Grandin     m_nSignatureState( SignatureState::NOSIGNATURES )
517fd069beeSJens-Heiner Rechtien {
518fd069beeSJens-Heiner Rechtien }
519fd069beeSJens-Heiner Rechtien 
5200ce0c369SAlexander Wilms 
~SfxMedium_Impl()521fd069beeSJens-Heiner Rechtien SfxMedium_Impl::~SfxMedium_Impl()
522fd069beeSJens-Heiner Rechtien {
523fd069beeSJens-Heiner Rechtien     aDoneLink.ClearPendingCall();
524fd069beeSJens-Heiner Rechtien 
525e4c40331SNoel Grandin     pTempFile.reset();
526e4c40331SNoel Grandin     m_pSet.reset();
52795eb0888SMatt K     std::unique_lock<std::recursive_mutex> chkEditLock;
52895eb0888SMatt K     if (m_pCheckEditableWorkerMutex != nullptr)
52995eb0888SMatt K         chkEditLock = std::unique_lock<std::recursive_mutex>(*m_pCheckEditableWorkerMutex);
530e4c40331SNoel Grandin     m_pURLObj.reset();
531fd069beeSJens-Heiner Rechtien }
532fd069beeSJens-Heiner Rechtien 
ResetError()533fd069beeSJens-Heiner Rechtien void SfxMedium::ResetError()
534fd069beeSJens-Heiner Rechtien {
535de8caac6SNoel Grandin     pImpl->m_eError = ERRCODE_NONE;
5365e32815aSXisco Fauli     if( pImpl->m_pInStream )
5375e32815aSXisco Fauli         pImpl->m_pInStream->ResetError();
5385e32815aSXisco Fauli     if( pImpl->m_pOutStream )
5395e32815aSXisco Fauli         pImpl->m_pOutStream->ResetError();
540fd069beeSJens-Heiner Rechtien }
541fd069beeSJens-Heiner Rechtien 
GetWarningError() const542d9e322d6SNoel Grandin ErrCodeMsg const & SfxMedium::GetWarningError() const
54329dad1e4SXisco Fauli {
54429dad1e4SXisco Fauli     return pImpl->m_eWarningError;
54529dad1e4SXisco Fauli }
54629dad1e4SXisco Fauli 
GetLastStorageCreationState() const547d9e322d6SNoel Grandin ErrCodeMsg const & SfxMedium::GetLastStorageCreationState() const
548a20f3410SMikhail Voitenko {
5495e32815aSXisco Fauli     return pImpl->nLastStorageError;
550a20f3410SMikhail Voitenko }
551a20f3410SMikhail Voitenko 
SetError(const ErrCodeMsg & rError)55259768e60SCaolán McNamara void SfxMedium::SetError(const ErrCodeMsg& rError)
553a245ebc7SIvo Hinkelmann {
55459768e60SCaolán McNamara     if (pImpl->m_eError == ERRCODE_NONE || (pImpl->m_eError.IsWarning() && rError.IsError()))
55559768e60SCaolán McNamara         pImpl->m_eError = rError;
556a245ebc7SIvo Hinkelmann }
557a245ebc7SIvo Hinkelmann 
SetWarningError(const ErrCodeMsg & nWarningError)558d9e322d6SNoel Grandin void SfxMedium::SetWarningError(const ErrCodeMsg& nWarningError)
55929dad1e4SXisco Fauli {
56029dad1e4SXisco Fauli     pImpl->m_eWarningError = nWarningError;
56129dad1e4SXisco Fauli }
56229dad1e4SXisco Fauli 
GetErrorCode() const563d9e322d6SNoel Grandin ErrCodeMsg SfxMedium::GetErrorCode() const
564fd069beeSJens-Heiner Rechtien {
565d9e322d6SNoel Grandin     ErrCodeMsg lError = pImpl->m_eError;
5665e32815aSXisco Fauli     if(!lError && pImpl->m_pInStream)
5675e32815aSXisco Fauli         lError = pImpl->m_pInStream->GetErrorCode();
5685e32815aSXisco Fauli     if(!lError && pImpl->m_pOutStream)
5695e32815aSXisco Fauli         lError = pImpl->m_pOutStream->GetErrorCode();
570fd069beeSJens-Heiner Rechtien     return lError;
571fd069beeSJens-Heiner Rechtien }
572fd069beeSJens-Heiner Rechtien 
CheckFileDate(const util::DateTime & aInitDate)5733dfe5a3fSJens-Heiner Rechtien void SfxMedium::CheckFileDate( const util::DateTime& aInitDate )
5743dfe5a3fSJens-Heiner Rechtien {
575df8a15d8SKohei Yoshida     GetInitFileDate( true );
576536a6d6cSNoel Grandin     if ( pImpl->m_aDateTime.Seconds == aInitDate.Seconds
577536a6d6cSNoel Grandin       && pImpl->m_aDateTime.Minutes == aInitDate.Minutes
578536a6d6cSNoel Grandin       && pImpl->m_aDateTime.Hours == aInitDate.Hours
579536a6d6cSNoel Grandin       && pImpl->m_aDateTime.Day == aInitDate.Day
580536a6d6cSNoel Grandin       && pImpl->m_aDateTime.Month == aInitDate.Month
581536a6d6cSNoel Grandin       && pImpl->m_aDateTime.Year == aInitDate.Year )
582536a6d6cSNoel Grandin         return;
583536a6d6cSNoel Grandin 
5843dfe5a3fSJens-Heiner Rechtien     uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
5853dfe5a3fSJens-Heiner Rechtien 
586536a6d6cSNoel Grandin     if ( !xHandler.is() )
587536a6d6cSNoel Grandin         return;
588536a6d6cSNoel Grandin 
5893dfe5a3fSJens-Heiner Rechtien     try
5903dfe5a3fSJens-Heiner Rechtien     {
5910bfa6a18SStephan Bergmann         ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::Any(
5923dfe5a3fSJens-Heiner Rechtien             document::ChangedByOthersRequest() ) );
593ce22935aSMike Kaganski         uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations{
594ce22935aSMike Kaganski             new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() ),
595ce22935aSMike Kaganski             new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() )
596ce22935aSMike Kaganski         };
5973dfe5a3fSJens-Heiner Rechtien         xInteractionRequestImpl->setContinuations( aContinuations );
5983dfe5a3fSJens-Heiner Rechtien 
59997fa8702SNoel         xHandler->handle( xInteractionRequestImpl );
6003dfe5a3fSJens-Heiner Rechtien 
6013dfe5a3fSJens-Heiner Rechtien         ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
602e512091eSMike Kaganski         if ( uno::Reference< task::XInteractionAbort >( cppu::getXWeak(xSelected.get()), uno::UNO_QUERY ).is() )
6033dfe5a3fSJens-Heiner Rechtien         {
6049e4d84daSCaolán McNamara             SetError(ERRCODE_ABORT);
6053dfe5a3fSJens-Heiner Rechtien         }
6063dfe5a3fSJens-Heiner Rechtien     }
6076c89e69bSCaolán McNamara     catch ( const uno::Exception& )
6083dfe5a3fSJens-Heiner Rechtien     {}
6093dfe5a3fSJens-Heiner Rechtien }
6103dfe5a3fSJens-Heiner Rechtien 
DocNeedsFileDateCheck() const6116832d9f0SCaolán McNamara bool SfxMedium::DocNeedsFileDateCheck() const
6123dfe5a3fSJens-Heiner Rechtien {
613b4576f3dSGiuseppe Castagno     return ( !IsReadOnly() && ( GetURLObject().GetProtocol() == INetProtocol::File ||
614b4576f3dSGiuseppe Castagno                                 GetURLObject().isAnyKnownWebDAVScheme() ) );
6150849d5a2SIvo Hinkelmann }
6160849d5a2SIvo Hinkelmann 
GetInitFileDate(bool bIgnoreOldValue)617a967c8f6SNoel Grandin util::DateTime const & SfxMedium::GetInitFileDate( bool bIgnoreOldValue )
6180849d5a2SIvo Hinkelmann {
6195e32815aSXisco Fauli     if ( ( bIgnoreOldValue || !pImpl->m_bGotDateTime ) && !pImpl->m_aLogicName.isEmpty() )
6203dfe5a3fSJens-Heiner Rechtien     {
6213dfe5a3fSJens-Heiner Rechtien         try
6223dfe5a3fSJens-Heiner Rechtien         {
62326c99e42SGiuseppe Castagno             // add a default css::ucb::XCommandEnvironment
62426c99e42SGiuseppe Castagno             // in order to have the WebDAV UCP provider manage http/https authentication correctly
625bfde4866SNoel Grandin             ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ),
62626c99e42SGiuseppe Castagno                                            utl::UCBContentHelper::getDefaultCommandEnvironment(),
62726c99e42SGiuseppe Castagno                                            comphelper::getProcessComponentContext() );
628cac6eb16SMikhail Voitenko 
629ca5c9591SNoel Grandin             aContent.getPropertyValue(u"DateModified"_ustr) >>= pImpl->m_aDateTime;
6305e32815aSXisco Fauli             pImpl->m_bGotDateTime = true;
6313dfe5a3fSJens-Heiner Rechtien         }
632913a2d36SNoel Grandin         catch ( const css::uno::Exception& )
6333dfe5a3fSJens-Heiner Rechtien         {
6343dfe5a3fSJens-Heiner Rechtien         }
6353dfe5a3fSJens-Heiner Rechtien     }
6363dfe5a3fSJens-Heiner Rechtien 
6375e32815aSXisco Fauli     return pImpl->m_aDateTime;
6383dfe5a3fSJens-Heiner Rechtien }
6393dfe5a3fSJens-Heiner Rechtien 
6400ce0c369SAlexander Wilms 
GetContent() const641fd069beeSJens-Heiner Rechtien Reference < XContent > SfxMedium::GetContent() const
642fd069beeSJens-Heiner Rechtien {
6435e32815aSXisco Fauli     if ( !pImpl->aContent.get().is() )
644fd069beeSJens-Heiner Rechtien     {
645913a2d36SNoel Grandin         Reference < css::ucb::XContent > xContent;
6463b26a2a4SGiuseppe Castagno 
6473b26a2a4SGiuseppe Castagno         // tdf#95144 add a default css::ucb::XCommandEnvironment
648211cb2deSGiuseppe Castagno         // in order to have the WebDAV UCP provider manage https protocol certificates correctly
6493b26a2a4SGiuseppe Castagno         css:: uno::Reference< task::XInteractionHandler > xIH(
6503b26a2a4SGiuseppe Castagno                 css::task::InteractionHandler::createWithParent( comphelper::getProcessComponentContext(), nullptr ) );
6513b26a2a4SGiuseppe Castagno 
6523b26a2a4SGiuseppe Castagno         css::uno::Reference< css::ucb::XProgressHandler > xProgress;
653d49277fcSNoel         rtl::Reference<::ucbhelper::CommandEnvironment> pCommandEnv = new ::ucbhelper::CommandEnvironment( new comphelper::SimpleFileAccessInteraction( xIH ), xProgress );
654dceeb1cbSJens-Heiner Rechtien 
655e4c40331SNoel Grandin         const SfxUnoAnyItem* pItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_CONTENT, false);
6568bb4993fSMathias Bauer         if ( pItem )
6578bb4993fSMathias Bauer             pItem->GetValue() >>= xContent;
6588bb4993fSMathias Bauer 
6598bb4993fSMathias Bauer         if ( xContent.is() )
660fc3a7d9cSMathias Bauer         {
6618bb4993fSMathias Bauer             try
6628bb4993fSMathias Bauer             {
663d49277fcSNoel                 pImpl->aContent = ::ucbhelper::Content( xContent, pCommandEnv, comphelper::getProcessComponentContext() );
664fc3a7d9cSMathias Bauer             }
6656c89e69bSCaolán McNamara             catch ( const Exception& )
666fc3a7d9cSMathias Bauer             {
6678bb4993fSMathias Bauer             }
6688bb4993fSMathias Bauer         }
6698bb4993fSMathias Bauer         else
6708bb4993fSMathias Bauer         {
6714a9ac82cSAndrea Gelmini             // TODO: SAL_WARN( "sfx.doc", "SfxMedium::GetContent()\nCreate Content? This code exists as fallback only. Please clarify, why it's used.");
6721946794aSLuboš Luňák             OUString aURL;
6735e32815aSXisco Fauli             if ( !pImpl->m_aName.isEmpty() )
6745e32815aSXisco Fauli                 osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aURL );
6755e32815aSXisco Fauli             else if ( !pImpl->m_aLogicName.isEmpty() )
676bfde4866SNoel Grandin                 aURL = GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE );
6773c62fbcdSCaolán McNamara             if (!aURL.isEmpty() )
678d49277fcSNoel                 (void)::ucbhelper::Content::create( aURL, pCommandEnv, comphelper::getProcessComponentContext(), pImpl->aContent );
679fd069beeSJens-Heiner Rechtien         }
680fc3a7d9cSMathias Bauer     }
681fd069beeSJens-Heiner Rechtien 
6825e32815aSXisco Fauli     return pImpl->aContent.get();
683fd069beeSJens-Heiner Rechtien }
684fd069beeSJens-Heiner Rechtien 
GetBaseURL(bool bForSaving)6851946794aSLuboš Luňák OUString SfxMedium::GetBaseURL( bool bForSaving )
6868bb4993fSMathias Bauer {
68781d0b356SMike Kaganski     if (bForSaving)
68881d0b356SMike Kaganski     {
68981d0b356SMike Kaganski         bool bIsRemote = IsRemote();
69081d0b356SMike Kaganski         if ((bIsRemote && !officecfg::Office::Common::Save::URL::Internet::get())
69181d0b356SMike Kaganski             || (!bIsRemote && !officecfg::Office::Common::Save::URL::FileSystem::get()))
69281d0b356SMike Kaganski             return OUString();
69381d0b356SMike Kaganski     }
69481d0b356SMike Kaganski 
695f5dd4faeSMike Kaganski     if (const SfxStringItem* pBaseURLItem = GetItemSet().GetItem<SfxStringItem>(SID_DOC_BASEURL))
69681d0b356SMike Kaganski         return pBaseURLItem->GetValue();
69781d0b356SMike Kaganski 
6981946794aSLuboš Luňák     OUString aBaseURL;
699f0a8b5b8SCaolán McNamara     if (!comphelper::IsFuzzing() && GetContent().is())
7008bb4993fSMathias Bauer     {
7018bb4993fSMathias Bauer         try
7028bb4993fSMathias Bauer         {
703ca5c9591SNoel Grandin             Any aAny = pImpl->aContent.getPropertyValue(u"BaseURI"_ustr);
704984b2bbbSRüdiger Timm             aAny >>= aBaseURL;
7058bb4993fSMathias Bauer         }
706913a2d36SNoel Grandin         catch ( const css::uno::Exception& )
7078bb4993fSMathias Bauer         {
7088bb4993fSMathias Bauer         }
7098bb4993fSMathias Bauer 
710e24a27b4SOlivier Hallot         if ( aBaseURL.isEmpty() )
711bfde4866SNoel Grandin             aBaseURL = GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE );
712cb0685cbSJens-Heiner Rechtien     }
713984b2bbbSRüdiger Timm     return aBaseURL;
7148bb4993fSMathias Bauer }
7158bb4993fSMathias Bauer 
IsSkipImages() const716df905f41SNoel Grandin bool SfxMedium::IsSkipImages() const
7179b0e09deSLászló Németh {
718f5dd4faeSMike Kaganski     const SfxStringItem* pSkipImagesItem = GetItemSet().GetItem<SfxStringItem>(SID_FILE_FILTEROPTIONS);
7199b0e09deSLászló Németh     return pSkipImagesItem && pSkipImagesItem->GetValue() == "SkipImages";
7209b0e09deSLászló Németh }
7210ce0c369SAlexander Wilms 
GetInStream()722fd069beeSJens-Heiner Rechtien SvStream* SfxMedium::GetInStream()
723fd069beeSJens-Heiner Rechtien {
7245e32815aSXisco Fauli     if ( pImpl->m_pInStream )
72565e41592SNoel Grandin         return pImpl->m_pInStream.get();
726fd069beeSJens-Heiner Rechtien 
7275e32815aSXisco Fauli     if ( pImpl->pTempFile )
728fd069beeSJens-Heiner Rechtien     {
72965e41592SNoel Grandin         pImpl->m_pInStream.reset( new SvFileStream(pImpl->m_aName, pImpl->m_nStorOpenMode) );
730fd069beeSJens-Heiner Rechtien 
7315e32815aSXisco Fauli         pImpl->m_eError = pImpl->m_pInStream->GetError();
732fd069beeSJens-Heiner Rechtien 
7335e32815aSXisco Fauli         if (!pImpl->m_eError && (pImpl->m_nStorOpenMode & StreamMode::WRITE)
7345e32815aSXisco Fauli                     && ! pImpl->m_pInStream->IsWritable() )
735fd069beeSJens-Heiner Rechtien         {
7365e32815aSXisco Fauli             pImpl->m_eError = ERRCODE_IO_ACCESSDENIED;
73765e41592SNoel Grandin             pImpl->m_pInStream.reset();
738fd069beeSJens-Heiner Rechtien         }
739fd069beeSJens-Heiner Rechtien         else
74065e41592SNoel Grandin             return pImpl->m_pInStream.get();
741fd069beeSJens-Heiner Rechtien     }
742fd069beeSJens-Heiner Rechtien 
743fd069beeSJens-Heiner Rechtien     GetMedium_Impl();
744fd069beeSJens-Heiner Rechtien 
745ed774e9fSNoel Grandin     if ( GetErrorIgnoreWarning() )
74628034eafSStephan Bergmann         return nullptr;
747762dd2b1SKurt Zenker 
74865e41592SNoel Grandin     return pImpl->m_pInStream.get();
749fd069beeSJens-Heiner Rechtien }
750fd069beeSJens-Heiner Rechtien 
7510ce0c369SAlexander Wilms 
CloseInStream()752fd069beeSJens-Heiner Rechtien void SfxMedium::CloseInStream()
753fd069beeSJens-Heiner Rechtien {
754fd069beeSJens-Heiner Rechtien     CloseInStream_Impl();
755fd069beeSJens-Heiner Rechtien }
756fd069beeSJens-Heiner Rechtien 
CloseInStream_Impl(bool bInDestruction)757c0d372d7SNoel Grandin void SfxMedium::CloseInStream_Impl(bool bInDestruction)
758fd069beeSJens-Heiner Rechtien {
759fd069beeSJens-Heiner Rechtien     // if there is a storage based on the InStream, we have to
760fd069beeSJens-Heiner Rechtien     // close the storage, too, because otherwise the storage
761fd069beeSJens-Heiner Rechtien     // would use an invalid ( deleted ) stream.
7625e32815aSXisco Fauli     if ( pImpl->m_pInStream && pImpl->xStorage.is() )
763fd069beeSJens-Heiner Rechtien     {
7645e32815aSXisco Fauli         if ( pImpl->bStorageBasedOnInStream )
765fd069beeSJens-Heiner Rechtien             CloseStorage();
766fd069beeSJens-Heiner Rechtien     }
767fd069beeSJens-Heiner Rechtien 
768c0d372d7SNoel Grandin     if ( pImpl->m_pInStream && !GetContent().is() && !bInDestruction )
769762dd2b1SKurt Zenker     {
770e5da350eSNoel Grandin         CreateTempFile();
771762dd2b1SKurt Zenker         return;
772762dd2b1SKurt Zenker     }
773762dd2b1SKurt Zenker 
77465e41592SNoel Grandin     pImpl->m_pInStream.reset();
7755e32815aSXisco Fauli     if ( pImpl->m_pSet )
7765e32815aSXisco Fauli         pImpl->m_pSet->ClearItem( SID_INPUTSTREAM );
7779df731d6SMathias Bauer 
778ac49eeddSIvo Hinkelmann     CloseZipStorage_Impl();
7795e32815aSXisco Fauli     pImpl->xInputStream.clear();
780083d2f57SVladimir Glazounov 
7815e32815aSXisco Fauli     if ( !pImpl->m_pOutStream )
782762dd2b1SKurt Zenker     {
783762dd2b1SKurt Zenker         // output part of the stream is not used so the whole stream can be closed
784762dd2b1SKurt Zenker         // TODO/LATER: is it correct?
7855e32815aSXisco Fauli         pImpl->xStream.clear();
7865e32815aSXisco Fauli         if ( pImpl->m_pSet )
7875e32815aSXisco Fauli             pImpl->m_pSet->ClearItem( SID_STREAM );
788762dd2b1SKurt Zenker     }
789fd069beeSJens-Heiner Rechtien }
790fd069beeSJens-Heiner Rechtien 
7910ce0c369SAlexander Wilms 
GetOutStream()792fd069beeSJens-Heiner Rechtien SvStream* SfxMedium::GetOutStream()
793fd069beeSJens-Heiner Rechtien {
7945e32815aSXisco Fauli     if ( !pImpl->m_pOutStream )
795fd069beeSJens-Heiner Rechtien     {
796fd069beeSJens-Heiner Rechtien         // Create a temp. file if there is none because we always
797fd069beeSJens-Heiner Rechtien         // need one.
798df8a15d8SKohei Yoshida         CreateTempFile( false );
799fd069beeSJens-Heiner Rechtien 
8005e32815aSXisco Fauli         if ( pImpl->pTempFile )
801fd069beeSJens-Heiner Rechtien         {
8023d125493Smatt_51             // On windows we try to re-use XOutStream from xStream if that exists;
8033d125493Smatt_51             // because opening new SvFileStream in this situation may fail with ERROR_SHARING_VIOLATION
8047c441540SMichael Stahl             // TODO: this is a horrible hack that should probably be removed,
8057c441540SMichael Stahl             // somebody needs to investigate this more thoroughly...
8065e32815aSXisco Fauli             if (getenv("SFX_MEDIUM_REUSE_STREAM") && pImpl->xStream.is())
8073d125493Smatt_51             {
8085e32815aSXisco Fauli                 assert(pImpl->xStream->getOutputStream().is()); // need that...
8095e32815aSXisco Fauli                 pImpl->m_pOutStream = utl::UcbStreamHelper::CreateStream(
8105e32815aSXisco Fauli                         pImpl->xStream, false);
8113d125493Smatt_51             }
8123d125493Smatt_51             else
8133d125493Smatt_51             {
8147c441540SMichael Stahl             // On Unix don't try to re-use XOutStream from xStream if that exists;
8157c441540SMichael Stahl             // it causes fdo#59022 (fails opening files via SMB on Linux)
81665e41592SNoel Grandin                 pImpl->m_pOutStream.reset( new SvFileStream(
81765e41592SNoel Grandin                             pImpl->m_aName, StreamMode::STD_READWRITE) );
8183d125493Smatt_51             }
819fd069beeSJens-Heiner Rechtien             CloseStorage();
820fd069beeSJens-Heiner Rechtien         }
821fd069beeSJens-Heiner Rechtien     }
822fd069beeSJens-Heiner Rechtien 
82365e41592SNoel Grandin     return pImpl->m_pOutStream.get();
824fd069beeSJens-Heiner Rechtien }
825fd069beeSJens-Heiner Rechtien 
8260ce0c369SAlexander Wilms 
CloseOutStream()827c9dcd0a6SNoel Grandin void SfxMedium::CloseOutStream()
828fd069beeSJens-Heiner Rechtien {
829fd069beeSJens-Heiner Rechtien     CloseOutStream_Impl();
830fd069beeSJens-Heiner Rechtien }
831fd069beeSJens-Heiner Rechtien 
CloseOutStream_Impl()83238c23520SNoel Grandin void SfxMedium::CloseOutStream_Impl()
833fd069beeSJens-Heiner Rechtien {
8345e32815aSXisco Fauli     if ( pImpl->m_pOutStream )
835fd069beeSJens-Heiner Rechtien     {
836fd069beeSJens-Heiner Rechtien         // if there is a storage based on the OutStream, we have to
837fd069beeSJens-Heiner Rechtien         // close the storage, too, because otherwise the storage
838fd069beeSJens-Heiner Rechtien         // would use an invalid ( deleted ) stream.
839762dd2b1SKurt Zenker         //TODO/MBA: how to deal with this?!
840762dd2b1SKurt Zenker         //maybe we need a new flag when the storage was created from the outstream
8415e32815aSXisco Fauli         if ( pImpl->xStorage.is() )
842fd069beeSJens-Heiner Rechtien         {
843fd069beeSJens-Heiner Rechtien                 CloseStorage();
844fd069beeSJens-Heiner Rechtien         }
845fd069beeSJens-Heiner Rechtien 
84665e41592SNoel Grandin         pImpl->m_pOutStream.reset();
847fd069beeSJens-Heiner Rechtien     }
848fd069beeSJens-Heiner Rechtien 
8495e32815aSXisco Fauli     if ( !pImpl->m_pInStream )
850762dd2b1SKurt Zenker     {
851762dd2b1SKurt Zenker         // input part of the stream is not used so the whole stream can be closed
852762dd2b1SKurt Zenker         // TODO/LATER: is it correct?
8535e32815aSXisco Fauli         pImpl->xStream.clear();
8545e32815aSXisco Fauli         if ( pImpl->m_pSet )
8555e32815aSXisco Fauli             pImpl->m_pSet->ClearItem( SID_STREAM );
856762dd2b1SKurt Zenker     }
857fd069beeSJens-Heiner Rechtien }
858fd069beeSJens-Heiner Rechtien 
8590ce0c369SAlexander Wilms 
GetPhysicalName() const8601946794aSLuboš Luňák const OUString& SfxMedium::GetPhysicalName() const
861fd069beeSJens-Heiner Rechtien {
8625e32815aSXisco Fauli     if ( pImpl->m_aName.isEmpty() && !pImpl->m_aLogicName.isEmpty() )
86398ce4ac4SStephan Bergmann         const_cast<SfxMedium*>(this)->CreateFileStream();
864fd069beeSJens-Heiner Rechtien 
865fd069beeSJens-Heiner Rechtien     // return the name then
8665e32815aSXisco Fauli     return pImpl->m_aName;
867fd069beeSJens-Heiner Rechtien }
868fd069beeSJens-Heiner Rechtien 
8690ce0c369SAlexander Wilms 
CreateFileStream()870fd069beeSJens-Heiner Rechtien void SfxMedium::CreateFileStream()
871fd069beeSJens-Heiner Rechtien {
872337e19bfSNoel Grandin     // force synchron
873337e19bfSNoel Grandin     if( pImpl->m_pInStream )
874337e19bfSNoel Grandin     {
875337e19bfSNoel Grandin         SvLockBytes* pBytes = pImpl->m_pInStream->GetLockBytes();
876337e19bfSNoel Grandin         if( pBytes )
877337e19bfSNoel Grandin             pBytes->SetSynchronMode();
878337e19bfSNoel Grandin     }
879337e19bfSNoel Grandin 
8800042696fSMathias Bauer     GetInStream();
8815e32815aSXisco Fauli     if( pImpl->m_pInStream )
882fd069beeSJens-Heiner Rechtien     {
883df8a15d8SKohei Yoshida         CreateTempFile( false );
8845e32815aSXisco Fauli         pImpl->bIsTemp = true;
885fd069beeSJens-Heiner Rechtien         CloseInStream_Impl();
886fd069beeSJens-Heiner Rechtien     }
887fd069beeSJens-Heiner Rechtien }
888fd069beeSJens-Heiner Rechtien 
8890ce0c369SAlexander Wilms 
Commit()8905fe7ecc0SNoel Grandin bool SfxMedium::Commit()
891fd069beeSJens-Heiner Rechtien {
8925e32815aSXisco Fauli     if( pImpl->xStorage.is() )
893762dd2b1SKurt Zenker         StorageCommit_Impl();
8945e32815aSXisco Fauli     else if( pImpl->m_pOutStream  )
89517950f4dSNoel Grandin         pImpl->m_pOutStream->FlushBuffer();
8965e32815aSXisco Fauli     else if( pImpl->m_pInStream  )
89717950f4dSNoel Grandin         pImpl->m_pInStream->FlushBuffer();
898fd069beeSJens-Heiner Rechtien 
899ed774e9fSNoel Grandin     if ( GetErrorIgnoreWarning() == ERRCODE_NONE )
900f343dc80SRüdiger Timm     {
901f343dc80SRüdiger Timm         // does something only in case there is a temporary file ( means aName points to different location than aLogicName )
902fd069beeSJens-Heiner Rechtien         Transfer_Impl();
903f343dc80SRüdiger Timm     }
904fd069beeSJens-Heiner Rechtien 
905ed774e9fSNoel Grandin     bool bResult = ( GetErrorIgnoreWarning() == ERRCODE_NONE );
9063dfe5a3fSJens-Heiner Rechtien 
9070849d5a2SIvo Hinkelmann     if ( bResult && DocNeedsFileDateCheck() )
908df8a15d8SKohei Yoshida         GetInitFileDate( true );
9093dfe5a3fSJens-Heiner Rechtien 
910ef3e6790SRüdiger Timm     // remove truncation mode from the flags
911e4472d3cSNoel Grandin     pImpl->m_nStorOpenMode &= ~StreamMode::TRUNC;
9123dfe5a3fSJens-Heiner Rechtien     return bResult;
913fd069beeSJens-Heiner Rechtien }
914fd069beeSJens-Heiner Rechtien 
9150ce0c369SAlexander Wilms 
IsStorage()9165fe7ecc0SNoel Grandin bool SfxMedium::IsStorage()
917fd069beeSJens-Heiner Rechtien {
9185e32815aSXisco Fauli     if ( pImpl->xStorage.is() )
919df8a15d8SKohei Yoshida         return true;
920028454b9SMathias Bauer 
9215e32815aSXisco Fauli     if ( pImpl->m_bTriedStorage )
9225e32815aSXisco Fauli         return pImpl->bIsStorage;
923e17cc7dfSMathias Bauer 
9245e32815aSXisco Fauli     if ( pImpl->pTempFile )
9254f7b8123SMathias Bauer     {
9261946794aSLuboš Luňák         OUString aURL;
9275e32815aSXisco Fauli         if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aURL )
928b1881e85STor Lillqvist              != osl::FileBase::E_None )
92985cd316fSOliver Bolte         {
930b1881e85STor Lillqvist             SAL_WARN( "sfx.doc", "Physical name '" << pImpl->m_aName << "' not convertible to file URL");
93185cd316fSOliver Bolte         }
9325e32815aSXisco Fauli         pImpl->bIsStorage = SotStorage::IsStorageFile( aURL ) && !SotStorage::IsOLEStorage( aURL);
9335e32815aSXisco Fauli         if ( !pImpl->bIsStorage )
9345e32815aSXisco Fauli             pImpl->m_bTriedStorage = true;
9354f7b8123SMathias Bauer     }
936abd354c8SMathias Bauer     else if ( GetInStream() )
9374f7b8123SMathias Bauer     {
93865e41592SNoel Grandin         pImpl->bIsStorage = SotStorage::IsStorageFile( pImpl->m_pInStream.get() ) && !SotStorage::IsOLEStorage( pImpl->m_pInStream.get() );
9395e32815aSXisco Fauli         if ( !pImpl->m_pInStream->GetError() && !pImpl->bIsStorage )
9405e32815aSXisco Fauli             pImpl->m_bTriedStorage = true;
9414f7b8123SMathias Bauer     }
9424f7b8123SMathias Bauer 
9435e32815aSXisco Fauli     return pImpl->bIsStorage;
9447ad49c6fSMathias Bauer }
945fd069beeSJens-Heiner Rechtien 
9460ce0c369SAlexander Wilms 
IsPreview_Impl() const947df905f41SNoel Grandin bool SfxMedium::IsPreview_Impl() const
948fd069beeSJens-Heiner Rechtien {
94950b4cbe9SKohei Yoshida     bool bPreview = false;
950f5dd4faeSMike Kaganski     const SfxBoolItem* pPreview = GetItemSet().GetItem(SID_PREVIEW, false);
951fd069beeSJens-Heiner Rechtien     if ( pPreview )
952fd069beeSJens-Heiner Rechtien         bPreview = pPreview->GetValue();
953fd069beeSJens-Heiner Rechtien     else
954fd069beeSJens-Heiner Rechtien     {
955f5dd4faeSMike Kaganski         const SfxStringItem* pFlags = GetItemSet().GetItem(SID_OPTIONS, false);
956fd069beeSJens-Heiner Rechtien         if ( pFlags )
957fd069beeSJens-Heiner Rechtien         {
958f9e78cd4SNoel Grandin             OUString aFileFlags = pFlags->GetValue();
959f9e78cd4SNoel Grandin             aFileFlags = aFileFlags.toAsciiUpperCase();
960f9e78cd4SNoel Grandin             if ( -1 != aFileFlags.indexOf( 'B' ) )
961df8a15d8SKohei Yoshida                 bPreview = true;
962fd069beeSJens-Heiner Rechtien         }
963fd069beeSJens-Heiner Rechtien     }
964fd069beeSJens-Heiner Rechtien 
965fd069beeSJens-Heiner Rechtien     return bPreview;
966fd069beeSJens-Heiner Rechtien }
967fd069beeSJens-Heiner Rechtien 
9680ce0c369SAlexander Wilms 
StorageBackup_Impl()969762dd2b1SKurt Zenker void SfxMedium::StorageBackup_Impl()
9706a6dcd60SMathias Bauer {
9715d88f117SIvo Hinkelmann     ::ucbhelper::Content aOriginalContent;
972913a2d36SNoel Grandin     Reference< css::ucb::XCommandEnvironment > xDummyEnv;
973ac49eeddSIvo Hinkelmann 
974e67657d5SNoel Grandin     bool bBasedOnOriginalFile =
975e67657d5SNoel Grandin         !pImpl->pTempFile
976e67657d5SNoel Grandin         && ( pImpl->m_aLogicName.isEmpty() || !pImpl->m_bSalvageMode )
977bfde4866SNoel Grandin         && !GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ).isEmpty()
9786d64afb3SStephan Bergmann         && GetURLObject().GetProtocol() == INetProtocol::File
979e67657d5SNoel Grandin         && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
980ac49eeddSIvo Hinkelmann 
9815e32815aSXisco Fauli     if ( bBasedOnOriginalFile && pImpl->m_aBackupURL.isEmpty()
982bfde4866SNoel Grandin       && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDummyEnv, comphelper::getProcessComponentContext(), aOriginalContent ) )
983762dd2b1SKurt Zenker     {
984762dd2b1SKurt Zenker         DoInternalBackup_Impl( aOriginalContent );
9855e32815aSXisco Fauli         if( pImpl->m_aBackupURL.isEmpty() )
9869e4d84daSCaolán McNamara             SetError(ERRCODE_SFX_CANTCREATEBACKUP);
987762dd2b1SKurt Zenker     }
988fd069beeSJens-Heiner Rechtien }
989fd069beeSJens-Heiner Rechtien 
9900ce0c369SAlexander Wilms 
GetBackup_Impl()991a967c8f6SNoel Grandin OUString const & SfxMedium::GetBackup_Impl()
992135171a9SRüdiger Timm {
9935e32815aSXisco Fauli     if ( pImpl->m_aBackupURL.isEmpty() )
994135171a9SRüdiger Timm         StorageBackup_Impl();
995135171a9SRüdiger Timm 
9965e32815aSXisco Fauli     return pImpl->m_aBackupURL;
997135171a9SRüdiger Timm }
998135171a9SRüdiger Timm 
9990ce0c369SAlexander Wilms 
GetOutputStorage()1000762dd2b1SKurt Zenker uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage()
1001ea400a20SMathias Bauer {
1002ed774e9fSNoel Grandin     if ( GetErrorIgnoreWarning() )
1003762dd2b1SKurt Zenker         return uno::Reference< embed::XStorage >();
1004762dd2b1SKurt Zenker 
1005762dd2b1SKurt Zenker     // if the medium was constructed with a Storage: use this one, not a temp. storage
1006471f965bSMathias Bauer     // if a temporary storage already exists: use it
10073b347664SMichael Stahl     if (pImpl->xStorage.is()
10083b347664SMichael Stahl         && (pImpl->m_bODFWholesomeEncryption || pImpl->m_aLogicName.isEmpty() || pImpl->pTempFile))
10093b347664SMichael Stahl     {
10105e32815aSXisco Fauli         return pImpl->xStorage;
10113b347664SMichael Stahl     }
1012762dd2b1SKurt Zenker 
1013762dd2b1SKurt Zenker     // if necessary close stream that was used for reading
10145e32815aSXisco Fauli     if ( pImpl->m_pInStream && !pImpl->m_pInStream->IsWritable() )
1015ea400a20SMathias Bauer         CloseInStream();
1016762dd2b1SKurt Zenker 
10175e32815aSXisco Fauli     DBG_ASSERT( !pImpl->m_pOutStream, "OutStream in a readonly Medium?!" );
1018762dd2b1SKurt Zenker 
1019ef3e6790SRüdiger Timm     // TODO/LATER: The current solution is to store the document temporary and then copy it to the target location;
1020ef3e6790SRüdiger Timm     // in future it should be stored directly and then copied to the temporary location, since in this case no
1021ef3e6790SRüdiger Timm     // file attributes have to be preserved and system copying mechanics could be used instead of streaming.
10227b88567cSPascal Junck     CreateTempFileNoCopy();
1023762dd2b1SKurt Zenker 
1024762dd2b1SKurt Zenker     return GetStorage();
1025762dd2b1SKurt Zenker }
1026762dd2b1SKurt Zenker 
10270ce0c369SAlexander Wilms 
SetEncryptionDataToStorage_Impl()10283b347664SMichael Stahl bool SfxMedium::SetEncryptionDataToStorage_Impl()
1029fe23d400SKurt Zenker {
1030fe23d400SKurt Zenker     // in case media-descriptor contains password it should be used on opening
1031536a6d6cSNoel Grandin     if ( !pImpl->xStorage.is() || !pImpl->m_pSet )
10323b347664SMichael Stahl         return false;
1033536a6d6cSNoel Grandin 
103434a04ae5SMikhail Voytenko     uno::Sequence< beans::NamedValue > aEncryptionData;
1035536a6d6cSNoel Grandin     if ( !GetEncryptionData_Impl( pImpl->m_pSet.get(), aEncryptionData ) )
10363b347664SMichael Stahl         return false;
1037536a6d6cSNoel Grandin 
103834a04ae5SMikhail Voytenko     // replace the password with encryption data
10395e32815aSXisco Fauli     pImpl->m_pSet->ClearItem( SID_PASSWORD );
10400bfa6a18SStephan Bergmann     pImpl->m_pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ) );
104134a04ae5SMikhail Voytenko 
1042fe23d400SKurt Zenker     try
1043fe23d400SKurt Zenker     {
10445e32815aSXisco Fauli         ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( pImpl->xStorage, aEncryptionData );
1045fe23d400SKurt Zenker     }
10466c89e69bSCaolán McNamara     catch( const uno::Exception& )
1047fe23d400SKurt Zenker     {
1048d38cb53eSMichael Stahl         SAL_WARN( "sfx.doc", "It must be possible to set a common password for the storage" );
10493b347664SMichael Stahl         SetError(ERRCODE_IO_GENERAL);
10503b347664SMichael Stahl         return false;
1051fe23d400SKurt Zenker     }
10523b347664SMichael Stahl     return true;
1053fe23d400SKurt Zenker }
1054fe23d400SKurt Zenker 
1055b9a07c37STor Lillqvist #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1056b9a07c37STor Lillqvist 
1057063b3280STor Lillqvist // FIXME: Hmm actually lock files should be used for sftp: documents
1058063b3280STor Lillqvist // even if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT. Only the use of lock
1059063b3280STor Lillqvist // files for *local* documents is unnecessary in that case. But
1060063b3280STor Lillqvist // actually, the checks for sftp: here are just wishful thinking; I
1061063b3280STor Lillqvist // don't this there is any support for actually editing documents
1062063b3280STor Lillqvist // behind sftp: URLs anyway.
1063c7c40687SAlexander Wilms 
1064063b3280STor Lillqvist // Sure, there could perhaps be a 3rd-party extension that brings UCB
1065063b3280STor Lillqvist // the potential to handle files behind sftp:. But there could also be
1066063b3280STor Lillqvist // an extension that handles some arbitrary foobar: scheme *and* it
1067063b3280STor Lillqvist // could be that lock files would be the correct thing to use for
1068063b3280STor Lillqvist // foobar: documents, too. But the hardcoded test below won't know
1069063b3280STor Lillqvist // that. Clearly the knowledge whether lock files should be used or
1070063b3280STor Lillqvist // not for some URL scheme belongs in UCB, not here.
1071063b3280STor Lillqvist 
1072607b80caSMike Kaganski namespace
1073607b80caSMike Kaganski {
1074607b80caSMike Kaganski 
tryMSOwnerFiles(std::u16string_view sDocURL)1075d3849255SNoel Grandin OUString tryMSOwnerFiles(std::u16string_view sDocURL)
1076607b80caSMike Kaganski {
1077ad47e9b1STamás Zolnai     svt::MSODocumentLockFile aMSOLockFile(sDocURL);
1078ad47e9b1STamás Zolnai     LockFileEntry aData;
1079ad47e9b1STamás Zolnai     try
1080607b80caSMike Kaganski     {
1081ad47e9b1STamás Zolnai         aData = aMSOLockFile.GetLockData();
1082607b80caSMike Kaganski     }
1083ad47e9b1STamás Zolnai     catch( const uno::Exception& )
1084ad47e9b1STamás Zolnai     {
1085ad47e9b1STamás Zolnai         return OUString();
1086ad47e9b1STamás Zolnai     }
1087ad47e9b1STamás Zolnai 
1088ad47e9b1STamás Zolnai     OUString sUserData = aData[LockFileComponent::OOOUSERNAME];
1089607b80caSMike Kaganski 
1090607b80caSMike Kaganski     if (!sUserData.isEmpty())
1091607b80caSMike Kaganski         sUserData += " (MS Office)"; // Mention the used office suite
1092607b80caSMike Kaganski 
1093607b80caSMike Kaganski     return sUserData;
1094607b80caSMike Kaganski }
1095607b80caSMike Kaganski 
tryForeignLockfiles(std::u16string_view sDocURL)1096d3849255SNoel Grandin OUString tryForeignLockfiles(std::u16string_view sDocURL)
1097607b80caSMike Kaganski {
1098607b80caSMike Kaganski     OUString sUserData = tryMSOwnerFiles(sDocURL);
1099607b80caSMike Kaganski     // here we can test for empty result, and add other known applications' lockfile testing
1100607b80caSMike Kaganski     return sUserData.trim();
1101607b80caSMike Kaganski }
1102607b80caSMike Kaganski }
1103607b80caSMike Kaganski 
ShowLockedDocumentDialog(const LockFileEntry & aData,bool bIsLoading,bool bOwnLock,bool bHandleSysLocked)1104c49ea4f3SMike Kaganski SfxMedium::ShowLockResult SfxMedium::ShowLockedDocumentDialog(const LockFileEntry& aData,
1105607b80caSMike Kaganski                                                               bool bIsLoading, bool bOwnLock,
1106607b80caSMike Kaganski                                                               bool bHandleSysLocked)
11072058774bSVladimir Glazounov {
110811570275SNoel Grandin     ShowLockResult nResult = ShowLockResult::NoLock;
11092058774bSVladimir Glazounov 
11106ca3b364SJuergen Funk     // tdf#92817: Simple check for empty lock file that needs to be deleted, when system locking is enabled
11116ca3b364SJuergen Funk     if( aData[LockFileComponent::OOOUSERNAME].isEmpty() && aData[LockFileComponent::SYSUSERNAME].isEmpty() && !bHandleSysLocked )
11128d411a4aSJaskaran         bOwnLock=true;
11138d411a4aSJaskaran 
11142058774bSVladimir Glazounov     // show the interaction regarding the document opening
11152058774bSVladimir Glazounov     uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
11163dfe5a3fSJens-Heiner Rechtien 
1117a0e01e3aSNoel Grandin     if ( xHandler.is() && ( bIsLoading || !bHandleSysLocked || bOwnLock ) )
11182058774bSVladimir Glazounov     {
11198dc3fe63SMike Kaganski         OUString aDocumentURL
11208dc3fe63SMike Kaganski             = GetURLObject().GetLastName(INetURLObject::DecodeMechanism::WithCharset);
11211946794aSLuboš Luňák         OUString aInfo;
11223dfe5a3fSJens-Heiner Rechtien         ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl;
11233dfe5a3fSJens-Heiner Rechtien 
11242a705725SMike Kaganski         sal_Int32 nContinuations = 3;
11252a705725SMike Kaganski 
11263dfe5a3fSJens-Heiner Rechtien         if ( bOwnLock )
11273dfe5a3fSJens-Heiner Rechtien         {
1128f0461e83SNoel Grandin             aInfo = aData[LockFileComponent::EDITTIME];
11293dfe5a3fSJens-Heiner Rechtien 
11300bfa6a18SStephan Bergmann             xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::Any(
11311946794aSLuboš Luňák                 document::OwnLockOnDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo, !bIsLoading ) ) );
11323dfe5a3fSJens-Heiner Rechtien         }
1133a30f8c4dSMike Kaganski         else
11343dfe5a3fSJens-Heiner Rechtien         {
1135a30f8c4dSMike Kaganski             // Use a fourth continuation in case there's no filesystem lock:
1136a30f8c4dSMike Kaganski             // "Ignore lock file and open/replace the document"
1137a30f8c4dSMike Kaganski             if (!bHandleSysLocked)
1138a30f8c4dSMike Kaganski                 nContinuations = 4;
1139a30f8c4dSMike Kaganski 
1140f0461e83SNoel Grandin             if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
1141f0461e83SNoel Grandin                 aInfo = aData[LockFileComponent::OOOUSERNAME];
11422058774bSVladimir Glazounov             else
1143f0461e83SNoel Grandin                 aInfo = aData[LockFileComponent::SYSUSERNAME];
11442058774bSVladimir Glazounov 
1145c49ea4f3SMike Kaganski             if (aInfo.isEmpty() && !GetURLObject().isAnyKnownWebDAVScheme())
1146607b80caSMike Kaganski                 // Try to get name of user who has locked the file using other applications
1147c49ea4f3SMike Kaganski                 aInfo = tryForeignLockfiles(
1148c49ea4f3SMike Kaganski                     GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE));
1149607b80caSMike Kaganski 
1150f0461e83SNoel Grandin             if ( !aInfo.isEmpty() && !aData[LockFileComponent::EDITTIME].isEmpty() )
1151a30f8c4dSMike Kaganski                 aInfo += " ( " + aData[LockFileComponent::EDITTIME] + " )";
11522058774bSVladimir Glazounov 
1153a30f8c4dSMike Kaganski             if (!bIsLoading) // so, !bHandleSysLocked
1154a30f8c4dSMike Kaganski             {
11550bfa6a18SStephan Bergmann                 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest(uno::Any(
1156a30f8c4dSMike Kaganski                     document::LockedOnSavingRequest(OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo)));
1157a30f8c4dSMike Kaganski                 // Currently, only the last "Retry" continuation (meaning ignore the lock and try overwriting) can be returned.
1158a30f8c4dSMike Kaganski             }
1159a30f8c4dSMike Kaganski             else /*logically therefore bIsLoading is set */
1160a30f8c4dSMike Kaganski             {
11610bfa6a18SStephan Bergmann                 xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::Any(
11621946794aSLuboš Luňák                     document::LockedDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
1163a30f8c4dSMike Kaganski             }
11643dfe5a3fSJens-Heiner Rechtien         }
11652058774bSVladimir Glazounov 
11662a705725SMike Kaganski         uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations(nContinuations);
1167ce22935aSMike Kaganski         auto pContinuations = aContinuations.getArray();
1168ce22935aSMike Kaganski         pContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
1169ce22935aSMike Kaganski         pContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
1170ce22935aSMike Kaganski         pContinuations[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl.get() );
11712a705725SMike Kaganski         if (nContinuations > 3)
11722a705725SMike Kaganski         {
11732a705725SMike Kaganski             // We use InteractionRetry to reflect that user wants to
1174a30f8c4dSMike Kaganski             // ignore the (stale?) alien lock file and open/overwrite the document
1175ce22935aSMike Kaganski             pContinuations[3] = new ::ucbhelper::InteractionRetry(xInteractionRequestImpl.get());
11762a705725SMike Kaganski         }
11772058774bSVladimir Glazounov         xInteractionRequestImpl->setContinuations( aContinuations );
11782058774bSVladimir Glazounov 
117997fa8702SNoel         xHandler->handle( xInteractionRequestImpl );
11802058774bSVladimir Glazounov 
118195eb0888SMatt K         bool bOpenReadOnly = false;
11822058774bSVladimir Glazounov         ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection();
1183e512091eSMike Kaganski         if ( uno::Reference< task::XInteractionAbort >( cppu::getXWeak(xSelected.get()), uno::UNO_QUERY ).is() )
11842058774bSVladimir Glazounov         {
11859e4d84daSCaolán McNamara             SetError(ERRCODE_ABORT);
11862058774bSVladimir Glazounov         }
1187e512091eSMike Kaganski         else if ( uno::Reference< task::XInteractionDisapprove >( cppu::getXWeak(xSelected.get()), uno::UNO_QUERY ).is() )
11882058774bSVladimir Glazounov         {
11893dfe5a3fSJens-Heiner Rechtien             // own lock on loading, user has selected to ignore the lock
11903dfe5a3fSJens-Heiner Rechtien             // own lock on saving, user has selected to ignore the lock
11913dfe5a3fSJens-Heiner Rechtien             // alien lock on loading, user has selected to edit a copy of document
11923dfe5a3fSJens-Heiner Rechtien             // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location
11932a705725SMike Kaganski             if ( !bOwnLock ) // bIsLoading implied from outermost condition
11943dfe5a3fSJens-Heiner Rechtien             {
11952058774bSVladimir Glazounov                 // means that a copy of the document should be opened
1196f5dd4faeSMike Kaganski                 GetItemSet().Put( SfxBoolItem( SID_TEMPLATE, true ) );
11972058774bSVladimir Glazounov             }
11982a705725SMike Kaganski             else
11992a705725SMike Kaganski                 nResult = ShowLockResult::Succeeded;
12002a705725SMike Kaganski         }
1201e512091eSMike Kaganski         else if (uno::Reference< task::XInteractionRetry >(cppu::getXWeak(xSelected.get()), uno::UNO_QUERY).is())
12022a705725SMike Kaganski         {
12032a705725SMike Kaganski             // User decided to ignore the alien (stale?) lock file without filesystem lock
120411570275SNoel Grandin             nResult = ShowLockResult::Succeeded;
12053dfe5a3fSJens-Heiner Rechtien         }
1206e512091eSMike Kaganski         else if (uno::Reference< task::XInteractionApprove >( cppu::getXWeak(xSelected.get()), uno::UNO_QUERY ).is())
120795eb0888SMatt K         {
120895eb0888SMatt K             bOpenReadOnly = true;
120995eb0888SMatt K         }
121095eb0888SMatt K         else // user selected "Notify"
121195eb0888SMatt K         {
121295eb0888SMatt K             pImpl->m_bNotifyWhenEditable = true;
121395eb0888SMatt K             AddToCheckEditableWorkerList();
121495eb0888SMatt K             bOpenReadOnly = true;
121595eb0888SMatt K         }
121695eb0888SMatt K 
121795eb0888SMatt K         if (bOpenReadOnly)
12183dfe5a3fSJens-Heiner Rechtien         {
12193dfe5a3fSJens-Heiner Rechtien             // own lock on loading, user has selected to open readonly
12203dfe5a3fSJens-Heiner Rechtien             // own lock on saving, user has selected to open readonly
12213dfe5a3fSJens-Heiner Rechtien             // alien lock on loading, user has selected to retry saving
12223dfe5a3fSJens-Heiner Rechtien             // TODO/LATER: alien lock on saving, user has selected to retry saving
12233dfe5a3fSJens-Heiner Rechtien 
12243dfe5a3fSJens-Heiner Rechtien             if (bIsLoading)
1225f5dd4faeSMike Kaganski                 GetItemSet().Put(SfxBoolItem(SID_DOC_READONLY, true));
12263dfe5a3fSJens-Heiner Rechtien             else
122711570275SNoel Grandin                 nResult = ShowLockResult::Try;
12283dfe5a3fSJens-Heiner Rechtien         }
12292058774bSVladimir Glazounov     }
12302058774bSVladimir Glazounov     else
12312058774bSVladimir Glazounov     {
12323dfe5a3fSJens-Heiner Rechtien         if ( bIsLoading )
12333dfe5a3fSJens-Heiner Rechtien         {
12343dfe5a3fSJens-Heiner Rechtien             // if no interaction handler is provided the default answer is open readonly
12352058774bSVladimir Glazounov             // that usually happens in case the document is loaded per API
12362058774bSVladimir Glazounov             // so the document must be opened readonly for backward compatibility
1237f5dd4faeSMike Kaganski             GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, true ) );
12382058774bSVladimir Glazounov         }
12393dfe5a3fSJens-Heiner Rechtien         else
12409e4d84daSCaolán McNamara             SetError(ERRCODE_IO_ACCESSDENIED);
12413dfe5a3fSJens-Heiner Rechtien 
12423dfe5a3fSJens-Heiner Rechtien     }
12433dfe5a3fSJens-Heiner Rechtien 
12443dfe5a3fSJens-Heiner Rechtien     return nResult;
12453dfe5a3fSJens-Heiner Rechtien }
12463dfe5a3fSJens-Heiner Rechtien 
ShowLockFileProblemDialog(MessageDlg nWhichDlg)12476ca3b364SJuergen Funk bool SfxMedium::ShowLockFileProblemDialog(MessageDlg nWhichDlg)
12486ca3b364SJuergen Funk {
12496ca3b364SJuergen Funk     // system file locking is not active, ask user whether he wants to open the document without any locking
12506ca3b364SJuergen Funk     uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler();
12516ca3b364SJuergen Funk 
12526ca3b364SJuergen Funk     if (xHandler.is())
12536ca3b364SJuergen Funk     {
12546ca3b364SJuergen Funk         ::rtl::Reference< ::ucbhelper::InteractionRequest > xIgnoreRequestImpl;
12556ca3b364SJuergen Funk 
12566ca3b364SJuergen Funk         switch (nWhichDlg)
12576ca3b364SJuergen Funk         {
12586ca3b364SJuergen Funk             case MessageDlg::LockFileIgnore:
12590bfa6a18SStephan Bergmann                 xIgnoreRequestImpl = new ::ucbhelper::InteractionRequest(uno::Any( document::LockFileIgnoreRequest() ));
12606ca3b364SJuergen Funk                 break;
12616ca3b364SJuergen Funk             case MessageDlg::LockFileCorrupt:
12620bfa6a18SStephan Bergmann                 xIgnoreRequestImpl = new ::ucbhelper::InteractionRequest(uno::Any( document::LockFileCorruptRequest() ));
12636ca3b364SJuergen Funk                 break;
12646ca3b364SJuergen Funk         }
12656ca3b364SJuergen Funk 
1266ce22935aSMike Kaganski         uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations{
1267ce22935aSMike Kaganski             new ::ucbhelper::InteractionAbort(xIgnoreRequestImpl.get()),
1268ce22935aSMike Kaganski             new ::ucbhelper::InteractionApprove(xIgnoreRequestImpl.get())
1269ce22935aSMike Kaganski         };
12706ca3b364SJuergen Funk         xIgnoreRequestImpl->setContinuations(aContinuations);
12716ca3b364SJuergen Funk 
127297fa8702SNoel         xHandler->handle(xIgnoreRequestImpl);
12736ca3b364SJuergen Funk 
12746ca3b364SJuergen Funk         ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xIgnoreRequestImpl->getSelection();
127595eb0888SMatt K         bool bReadOnly = true;
12766ca3b364SJuergen Funk 
1277e512091eSMike Kaganski         if (uno::Reference<task::XInteractionAbort>(cppu::getXWeak(xSelected.get()), uno::UNO_QUERY).is())
12786ca3b364SJuergen Funk         {
12796ca3b364SJuergen Funk             SetError(ERRCODE_ABORT);
128095eb0888SMatt K             bReadOnly = false;
12816ca3b364SJuergen Funk         }
1282e512091eSMike Kaganski         else if (!uno::Reference<task::XInteractionApprove>(cppu::getXWeak(xSelected.get()), uno::UNO_QUERY).is())
128395eb0888SMatt K         {
128495eb0888SMatt K             // user selected "Notify"
128595eb0888SMatt K             pImpl->m_bNotifyWhenEditable = true;
128695eb0888SMatt K             AddToCheckEditableWorkerList();
128795eb0888SMatt K         }
128895eb0888SMatt K 
128995eb0888SMatt K         if (bReadOnly)
1290f5dd4faeSMike Kaganski             GetItemSet().Put(SfxBoolItem(SID_DOC_READONLY, true));
12916ca3b364SJuergen Funk 
12926ca3b364SJuergen Funk         return bReadOnly;
12936ca3b364SJuergen Funk     }
12946ca3b364SJuergen Funk 
12956ca3b364SJuergen Funk     return false;
12966ca3b364SJuergen Funk }
12976ca3b364SJuergen Funk 
12987af7025bSCaolán McNamara namespace
12997af7025bSCaolán McNamara {
isSuitableProtocolForLocking(const OUString & rLogicName)1300f9e78cd4SNoel Grandin     bool isSuitableProtocolForLocking(const OUString & rLogicName)
13017af7025bSCaolán McNamara     {
13027af7025bSCaolán McNamara         INetURLObject aUrl( rLogicName );
13037af7025bSCaolán McNamara         INetProtocol eProt = aUrl.GetProtocol();
130476352133SStephan Bergmann #if !HAVE_FEATURE_MACOSX_SANDBOX
130576352133SStephan Bergmann         if (eProt == INetProtocol::File) {
130676352133SStephan Bergmann             return true;
130776352133SStephan Bergmann         }
1308063b3280STor Lillqvist #endif
130976352133SStephan Bergmann         return eProt == INetProtocol::Smb || eProt == INetProtocol::Sftp;
13107af7025bSCaolán McNamara     }
13117af7025bSCaolán McNamara }
13127af7025bSCaolán McNamara 
1313b1f25771SMichael Stahl namespace
1314b1f25771SMichael Stahl {
1315b1f25771SMichael Stahl 
1316b1f25771SMichael Stahl // for LOCK request, suppress dialog on 403, typically indicates read-only
1317b1f25771SMichael Stahl // document and there's a 2nd dialog prompting to open a copy anyway
1318b1f25771SMichael Stahl class LockInteractionHandler : public ::cppu::WeakImplHelper<task::XInteractionHandler>
1319b1f25771SMichael Stahl {
1320b1f25771SMichael Stahl private:
1321b1f25771SMichael Stahl     uno::Reference<task::XInteractionHandler> m_xHandler;
1322b1f25771SMichael Stahl 
1323b1f25771SMichael Stahl public:
LockInteractionHandler(uno::Reference<task::XInteractionHandler> const & xHandler)1324b1f25771SMichael Stahl     explicit LockInteractionHandler(uno::Reference<task::XInteractionHandler> const& xHandler)
1325b1f25771SMichael Stahl         : m_xHandler(xHandler)
1326b1f25771SMichael Stahl     {
1327b1f25771SMichael Stahl     }
1328b1f25771SMichael Stahl 
handle(uno::Reference<task::XInteractionRequest> const & xRequest)1329b1f25771SMichael Stahl     virtual void SAL_CALL handle(uno::Reference<task::XInteractionRequest> const& xRequest) override
1330b1f25771SMichael Stahl     {
1331b1f25771SMichael Stahl         ucb::InteractiveNetworkWriteException readException;
1332b1f25771SMichael Stahl         ucb::InteractiveNetworkReadException writeException;
1333b1f25771SMichael Stahl         if ((xRequest->getRequest() >>= readException)
1334b1f25771SMichael Stahl             || (xRequest->getRequest() >>= writeException))
1335b1f25771SMichael Stahl         {
1336b1f25771SMichael Stahl             return; // 403 gets reported as one of these; ignore to avoid dialog
1337b1f25771SMichael Stahl         }
1338b1f25771SMichael Stahl         m_xHandler->handle(xRequest);
1339b1f25771SMichael Stahl     }
1340b1f25771SMichael Stahl };
1341b1f25771SMichael Stahl 
1342b1f25771SMichael Stahl } // namespace
1343b1f25771SMichael Stahl 
1344063b3280STor Lillqvist #endif // HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1345b9a07c37STor Lillqvist 
1346b1500002SStephan Bergmann // sets SID_DOC_READONLY if the document cannot be opened for editing
13473dfe5a3fSJens-Heiner Rechtien // if user cancel the loading the ERROR_ABORT is set
LockOrigFileOnDemand(bool bLoading,bool bNoUI,bool bTryIgnoreLockFile,LockFileEntry * pLockData)13480f9599b6SMike Kaganski SfxMedium::LockFileResult SfxMedium::LockOrigFileOnDemand(bool bLoading, bool bNoUI,
13490f9599b6SMike Kaganski                                                           bool bTryIgnoreLockFile,
13500f9599b6SMike Kaganski                                                           LockFileEntry* pLockData)
1351300b39ccSMarkus Mohrhard {
1352a8c3c673STor Lillqvist #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
13533ee3e794STor Lillqvist     (void) bLoading;
13543ee3e794STor Lillqvist     (void) bNoUI;
13552a705725SMike Kaganski     (void) bTryIgnoreLockFile;
13563f009ab4SJan-Marek Glogowski     (void) pLockData;
13572a705725SMike Kaganski     return LockFileResult::Succeeded;
13583ee3e794STor Lillqvist #else
13592a705725SMike Kaganski     LockFileResult eResult = LockFileResult::Failed;
13602a705725SMike Kaganski 
1361b4576f3dSGiuseppe Castagno     // check if path scheme is http:// or https://
1362b4576f3dSGiuseppe Castagno     // may be this is better if used always, in Android and iOS as well?
1363b4576f3dSGiuseppe Castagno     // if this code should be always there, remember to move the relevant code in UnlockFile method as well !
1364b4576f3dSGiuseppe Castagno 
1365b4576f3dSGiuseppe Castagno     if ( GetURLObject().isAnyKnownWebDAVScheme() )
1366b4576f3dSGiuseppe Castagno     {
1367297be63cSKatarina Behrens         // do nothing if WebDAV locking is disabled
1368297be63cSKatarina Behrens         if (!IsWebDAVLockingUsed())
1369297be63cSKatarina Behrens             return LockFileResult::Succeeded;
1370297be63cSKatarina Behrens 
1371b4576f3dSGiuseppe Castagno         {
13725e32815aSXisco Fauli             bool bResult = pImpl->m_bLocked;
1373f95e7ef3SJan-Marek Glogowski             bool bIsTemplate = false;
1374b4576f3dSGiuseppe Castagno             // so, this is webdav stuff...
1375b4576f3dSGiuseppe Castagno             if ( !bResult )
1376b4576f3dSGiuseppe Castagno             {
1377b4576f3dSGiuseppe Castagno                 // no read-write access is necessary on loading if the document is explicitly opened as copy
1378f5dd4faeSMike Kaganski                 const SfxBoolItem* pTemplateItem = GetItemSet().GetItem(SID_TEMPLATE, false);
1379f95e7ef3SJan-Marek Glogowski                 bIsTemplate = ( bLoading && pTemplateItem && pTemplateItem->GetValue() );
1380b4576f3dSGiuseppe Castagno             }
1381b4576f3dSGiuseppe Castagno 
1382f95e7ef3SJan-Marek Glogowski             if ( !bIsTemplate && !bResult && !IsReadOnly() )
1383b4576f3dSGiuseppe Castagno             {
138411570275SNoel Grandin                 ShowLockResult bUIStatus = ShowLockResult::NoLock;
1385b4576f3dSGiuseppe Castagno                 do
1386b4576f3dSGiuseppe Castagno                 {
1387b4576f3dSGiuseppe Castagno                     if( !bResult )
1388b4576f3dSGiuseppe Castagno                     {
1389b4576f3dSGiuseppe Castagno                         uno::Reference< task::XInteractionHandler > xCHandler = GetInteractionHandler( true );
1390b1f25771SMichael Stahl                         // Dialog with error is superfluous:
1391b1f25771SMichael Stahl                         // on loading, will result in read-only with infobar.
1392b1f25771SMichael Stahl                         // bNoUI case for Reload failing, will open dialog later.
1393b1f25771SMichael Stahl                         if (bLoading || bNoUI)
1394b1f25771SMichael Stahl                         {
1395b1f25771SMichael Stahl                             xCHandler = new LockInteractionHandler(xCHandler);
1396b1f25771SMichael Stahl                         }
1397913a2d36SNoel Grandin                         Reference< css::ucb::XCommandEnvironment > xComEnv = new ::ucbhelper::CommandEnvironment(
1398913a2d36SNoel Grandin                             xCHandler, Reference< css::ucb::XProgressHandler >() );
1399b4576f3dSGiuseppe Castagno 
1400b4576f3dSGiuseppe Castagno                         ucbhelper::Content aContentToLock(
1401bfde4866SNoel Grandin                             GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1402b4576f3dSGiuseppe Castagno                             xComEnv, comphelper::getProcessComponentContext() );
1403b4576f3dSGiuseppe Castagno 
1404b4576f3dSGiuseppe Castagno                         try
1405b4576f3dSGiuseppe Castagno                         {
1406b4576f3dSGiuseppe Castagno                             aContentToLock.lock();
1407b4576f3dSGiuseppe Castagno                             bResult = true;
1408b4576f3dSGiuseppe Castagno                         }
1409b4576f3dSGiuseppe Castagno                         catch ( ucb::InteractiveLockingLockedException& )
1410b4576f3dSGiuseppe Castagno                         {
1411b4576f3dSGiuseppe Castagno                             // received when the resource is already locked
14120f9599b6SMike Kaganski                             if (!bNoUI || pLockData)
14130f9599b6SMike Kaganski                             {
1414b4576f3dSGiuseppe Castagno                                 // get the lock owner, using a special ucb.webdav property
1415b4576f3dSGiuseppe Castagno                                 // the owner property retrieved here is  what the other principal send the server
1416b4576f3dSGiuseppe Castagno                                 // when activating the lock.
1417b4576f3dSGiuseppe Castagno                                 // See http://tools.ietf.org/html/rfc4918#section-14.17 for details
1418b4576f3dSGiuseppe Castagno                                 LockFileEntry aLockData;
141911fe4810SStephan Bergmann                                 aLockData[LockFileComponent::OOOUSERNAME] = "Unknown user";
142097353e5cSGiuseppe Castagno                                 // This solution works right when the LO user name and the WebDAV user
142197353e5cSGiuseppe Castagno                                 // name are the same.
142297353e5cSGiuseppe Castagno                                 // A better thing to do would be to obtain the 'real' WebDAV user name,
142397353e5cSGiuseppe Castagno                                 // but that's not possible from a WebDAV UCP provider client.
142497353e5cSGiuseppe Castagno                                 LockFileEntry aOwnData = svt::LockFileCommon::GenerateOwnEntry();
142597353e5cSGiuseppe Castagno                                 // use the current LO user name as the system name
14260f9599b6SMike Kaganski                                 aLockData[LockFileComponent::SYSUSERNAME]
14270f9599b6SMike Kaganski                                     = aOwnData[LockFileComponent::SYSUSERNAME];
142806cc80bbSGiuseppe Castagno 
142906cc80bbSGiuseppe Castagno                                 uno::Sequence<css::ucb::Lock> aLocks;
143006cc80bbSGiuseppe Castagno                                 // getting the property, send a PROPFIND to the server over the net
1431ca5c9591SNoel Grandin                                 if ((aContentToLock.getPropertyValue(u"DAV:lockdiscovery"_ustr) >>= aLocks) && aLocks.hasElements())
143206cc80bbSGiuseppe Castagno                                 {
143306cc80bbSGiuseppe Castagno                                     // got at least a lock, show the owner of the first lock returned
143441ab82d5SNoel Grandin                                     const css::ucb::Lock& aLock = aLocks[0];
143506cc80bbSGiuseppe Castagno                                     OUString aOwner;
143606cc80bbSGiuseppe Castagno                                     if (aLock.Owner >>= aOwner)
143706cc80bbSGiuseppe Castagno                                     {
143897353e5cSGiuseppe Castagno                                         // we need to display the WebDAV user name owning the lock, not the local one
1439b4576f3dSGiuseppe Castagno                                         aLockData[LockFileComponent::OOOUSERNAME] = aOwner;
1440b4576f3dSGiuseppe Castagno                                     }
144197353e5cSGiuseppe Castagno                                 }
1442b4576f3dSGiuseppe Castagno 
14430f9599b6SMike Kaganski                                 if (!bNoUI)
1444b4576f3dSGiuseppe Castagno                                 {
14450f9599b6SMike Kaganski                                     bUIStatus = ShowLockedDocumentDialog(aLockData, bLoading, false,
14460f9599b6SMike Kaganski                                                                          true);
14470f9599b6SMike Kaganski                                 }
14480f9599b6SMike Kaganski 
14490f9599b6SMike Kaganski                                 if (pLockData)
14500f9599b6SMike Kaganski                                 {
14510f9599b6SMike Kaganski                                     std::copy(aLockData.begin(), aLockData.end(), pLockData->begin());
14520f9599b6SMike Kaganski                                 }
1453b4576f3dSGiuseppe Castagno                             }
1454b4576f3dSGiuseppe Castagno                         }
145503263524SGiuseppe Castagno                         catch( ucb::InteractiveNetworkWriteException& )
145603263524SGiuseppe Castagno                         {
145703263524SGiuseppe Castagno                             // This catch it's not really needed, here just for the sake of documentation on the behaviour.
145803263524SGiuseppe Castagno                             // This is the most likely reason:
145903263524SGiuseppe Castagno                             // - the remote site is a WebDAV with special configuration: read/only for read operations
146003263524SGiuseppe Castagno                             //   and read/write for write operations, the user is not allowed to lock/write and
146103263524SGiuseppe Castagno                             //   she cancelled the credentials request.
146203263524SGiuseppe Castagno                             //   this is not actually an error, but the exception is sent directly from ucb, avoiding the automatic
146303263524SGiuseppe Castagno                             //   management that takes part in cancelCommandExecution()
146403263524SGiuseppe Castagno                             // Unfortunately there is no InteractiveNetwork*Exception available to signal this more correctly
146503263524SGiuseppe Castagno                             // since it mostly happens on read/only part of webdav, this can be the most correct
146603263524SGiuseppe Castagno                             // exception available
146703263524SGiuseppe Castagno                         }
1468b4576f3dSGiuseppe Castagno                         catch( uno::Exception& )
146908c979e2SMichael Stahl                         {
147008c979e2SMichael Stahl                             TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
147108c979e2SMichael Stahl                         }
1472b4576f3dSGiuseppe Castagno                     }
147311570275SNoel Grandin                 } while( !bResult && bUIStatus == ShowLockResult::Try );
1474b4576f3dSGiuseppe Castagno             }
1475b4576f3dSGiuseppe Castagno 
14765e32815aSXisco Fauli             pImpl->m_bLocked = bResult;
1477b4576f3dSGiuseppe Castagno 
1478ed774e9fSNoel Grandin             if ( !bResult && GetErrorIgnoreWarning() == ERRCODE_NONE )
1479b4576f3dSGiuseppe Castagno             {
1480b4576f3dSGiuseppe Castagno                 // the error should be set in case it is storing process
1481b4576f3dSGiuseppe Castagno                 // or the document has been opened for editing explicitly
1482e4c40331SNoel Grandin                 const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
1483b4576f3dSGiuseppe Castagno 
1484b4576f3dSGiuseppe Castagno                 if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) )
14859e4d84daSCaolán McNamara                     SetError(ERRCODE_IO_ACCESSDENIED);
1486b4576f3dSGiuseppe Castagno                 else
1487f5dd4faeSMike Kaganski                     GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1488b4576f3dSGiuseppe Castagno             }
1489b4576f3dSGiuseppe Castagno 
1490b4576f3dSGiuseppe Castagno             // when the file is locked, get the current file date
1491b4576f3dSGiuseppe Castagno             if ( bResult && DocNeedsFileDateCheck() )
1492b4576f3dSGiuseppe Castagno                 GetInitFileDate( true );
14932a705725SMike Kaganski 
14942a705725SMike Kaganski             if ( bResult )
14952a705725SMike Kaganski                 eResult = LockFileResult::Succeeded;
1496b4576f3dSGiuseppe Castagno         }
14972a705725SMike Kaganski         return eResult;
1498b4576f3dSGiuseppe Castagno     }
1499b4576f3dSGiuseppe Castagno 
15002a705725SMike Kaganski     if (!IsLockingUsed())
15012a705725SMike Kaganski         return LockFileResult::Succeeded;
15022a705725SMike Kaganski     if (GetURLObject().HasError())
15032a705725SMike Kaganski         return eResult;
1504300b39ccSMarkus Mohrhard 
1505e2799d25SMichael Meeks     try
1506b4b69861SMikhail Voytenko     {
15075e32815aSXisco Fauli         if ( pImpl->m_bLocked && bLoading
15086d64afb3SStephan Bergmann              && GetURLObject().GetProtocol() == INetProtocol::File )
150981a766e5SMikhail Voitenko         {
15102a705725SMike Kaganski             // if the document is already locked the system locking might be temporarily off after storing
151181a766e5SMikhail Voitenko             // check whether the system file locking should be taken again
151281a766e5SMikhail Voitenko             GetLockingStream_Impl();
151381a766e5SMikhail Voitenko         }
151481a766e5SMikhail Voitenko 
15155e32815aSXisco Fauli         bool bResult = pImpl->m_bLocked;
15163dfe5a3fSJens-Heiner Rechtien 
151796f1e7bbSVladimir Glazounov         if ( !bResult )
151896f1e7bbSVladimir Glazounov         {
151996f1e7bbSVladimir Glazounov             // no read-write access is necessary on loading if the document is explicitly opened as copy
1520f5dd4faeSMike Kaganski             const SfxBoolItem* pTemplateItem = GetItemSet().GetItem(SID_TEMPLATE, false);
152196f1e7bbSVladimir Glazounov             bResult = ( bLoading && pTemplateItem && pTemplateItem->GetValue() );
152296f1e7bbSVladimir Glazounov         }
152396f1e7bbSVladimir Glazounov 
152496f1e7bbSVladimir Glazounov         if ( !bResult && !IsReadOnly() )
152596f1e7bbSVladimir Glazounov         {
152650b4cbe9SKohei Yoshida             bool bContentReadonly = false;
15276d64afb3SStephan Bergmann             if ( bLoading && GetURLObject().GetProtocol() == INetProtocol::File )
15288c895561SJens-Heiner Rechtien             {
152989fd6a8fSMikhail Voitenko                 // let the original document be opened to check the possibility to open it for editing
153089fd6a8fSMikhail Voitenko                 // and to let the writable stream stay open to hold the lock on the document
153189fd6a8fSMikhail Voitenko                 GetLockingStream_Impl();
15328c895561SJens-Heiner Rechtien             }
15338c895561SJens-Heiner Rechtien 
15348c895561SJens-Heiner Rechtien             // "IsReadOnly" property does not allow to detect whether the file is readonly always
15358c895561SJens-Heiner Rechtien             // so we try always to open the file for editing
15368c895561SJens-Heiner Rechtien             // the file is readonly only in case the read-write stream can not be opened
15375e32815aSXisco Fauli             if ( bLoading && !pImpl->m_xLockingStream.is() )
153896f1e7bbSVladimir Glazounov             {
153996f1e7bbSVladimir Glazounov                 try
154096f1e7bbSVladimir Glazounov                 {
154196f1e7bbSVladimir Glazounov                     // MediaDescriptor does this check also, the duplication should be avoided in future
1542913a2d36SNoel Grandin                     Reference< css::ucb::XCommandEnvironment > xDummyEnv;
1543bfde4866SNoel Grandin                     ::ucbhelper::Content aContent( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDummyEnv, comphelper::getProcessComponentContext() );
1544ca5c9591SNoel Grandin                     aContent.getPropertyValue(u"IsReadOnly"_ustr) >>= bContentReadonly;
154596f1e7bbSVladimir Glazounov                 }
1546e2799d25SMichael Meeks                 catch( const uno::Exception& ) {}
1547b9ecec7cSStephan Bergmann             }
154896f1e7bbSVladimir Glazounov 
15498c895561SJens-Heiner Rechtien             // do further checks only if the file not readonly in fs
155096f1e7bbSVladimir Glazounov             if ( !bContentReadonly )
155196f1e7bbSVladimir Glazounov             {
15527af7025bSCaolán McNamara                 // the special file locking should be used only for suitable URLs
15535e32815aSXisco Fauli                 if ( isSuitableProtocolForLocking( pImpl->m_aLogicName ) )
15543dfe5a3fSJens-Heiner Rechtien                 {
15553dfe5a3fSJens-Heiner Rechtien 
15563dfe5a3fSJens-Heiner Rechtien                     // in case of storing the document should request the output before locking
15573dfe5a3fSJens-Heiner Rechtien                     if ( bLoading )
15583dfe5a3fSJens-Heiner Rechtien                     {
15593dfe5a3fSJens-Heiner Rechtien                         // let the stream be opened to check the system file locking
15603dfe5a3fSJens-Heiner Rechtien                         GetMedium_Impl();
1561ed774e9fSNoel Grandin                         if (GetErrorIgnoreWarning() != ERRCODE_NONE) {
15622a705725SMike Kaganski                             return eResult;
1563fd08abb5SStephan Bergmann                         }
15643dfe5a3fSJens-Heiner Rechtien                     }
15653dfe5a3fSJens-Heiner Rechtien 
156611570275SNoel Grandin                     ShowLockResult bUIStatus = ShowLockResult::NoLock;
15673dfe5a3fSJens-Heiner Rechtien 
15683dfe5a3fSJens-Heiner Rechtien                     // check whether system file locking has been used, the default value is false
15695e32815aSXisco Fauli                     bool bUseSystemLock = comphelper::isFileUrl( pImpl->m_aLogicName ) && IsSystemFileLockingUsed();
15703dfe5a3fSJens-Heiner Rechtien 
15713dfe5a3fSJens-Heiner Rechtien                     // TODO/LATER: This implementation does not allow to detect the system lock on saving here, actually this is no big problem
157296f1e7bbSVladimir Glazounov                     // if system lock is used the writeable stream should be available
15735e32815aSXisco Fauli                     bool bHandleSysLocked = ( bLoading && bUseSystemLock && !pImpl->xStream.is() && !pImpl->m_pOutStream );
15743dfe5a3fSJens-Heiner Rechtien 
1575a30f8c4dSMike Kaganski                     // The file is attempted to get locked for the duration of lockfile creation on save
1576a30f8c4dSMike Kaganski                     std::unique_ptr<osl::File> pFileLock;
1577a30f8c4dSMike Kaganski                     if (!bLoading && bUseSystemLock && pImpl->pTempFile)
1578a30f8c4dSMike Kaganski                     {
1579a30f8c4dSMike Kaganski                         INetURLObject aDest(GetURLObject());
1580a30f8c4dSMike Kaganski                         OUString aDestURL(aDest.GetMainURL(INetURLObject::DecodeMechanism::NONE));
1581a30f8c4dSMike Kaganski 
1582a30f8c4dSMike Kaganski                         if (comphelper::isFileUrl(aDestURL) || !aDest.removeSegment())
1583a30f8c4dSMike Kaganski                         {
15844e8a15caSGabor Kelemen                             pFileLock = std::make_unique<osl::File>(aDestURL);
1585a30f8c4dSMike Kaganski                             auto rc = pFileLock->open(osl_File_OpenFlag_Write);
1586a30f8c4dSMike Kaganski                             if (rc == osl::FileBase::E_ACCES)
1587a30f8c4dSMike Kaganski                                 bHandleSysLocked = true;
1588a30f8c4dSMike Kaganski                         }
1589a30f8c4dSMike Kaganski                     }
1590a30f8c4dSMike Kaganski 
15913dfe5a3fSJens-Heiner Rechtien                     do
15923dfe5a3fSJens-Heiner Rechtien                     {
15933dfe5a3fSJens-Heiner Rechtien                         try
15943dfe5a3fSJens-Heiner Rechtien                         {
15955e32815aSXisco Fauli                             ::svt::DocumentLockFile aLockFile( pImpl->m_aLogicName );
159641dc917bSTamás Zolnai 
159741dc917bSTamás Zolnai                             std::unique_ptr<svt::MSODocumentLockFile> pMSOLockFile;
1598e6f77135SGabor Kelemen                             if (officecfg::Office::Common::Filter::Microsoft::Import::CreateMSOLockFiles::get()  && svt::MSODocumentLockFile::IsMSOSupportedFileFormat(pImpl->m_aLogicName))
159941dc917bSTamás Zolnai                             {
160041dc917bSTamás Zolnai                                 pMSOLockFile.reset(new svt::MSODocumentLockFile(pImpl->m_aLogicName));
160141dc917bSTamás Zolnai                                 pImpl->m_bMSOLockFileCreated = true;
160241dc917bSTamás Zolnai                             }
160341dc917bSTamás Zolnai 
16046ca3b364SJuergen Funk                             bool  bIoErr = false;
16056ca3b364SJuergen Funk 
160696f1e7bbSVladimir Glazounov                             if (!bHandleSysLocked)
16073dfe5a3fSJens-Heiner Rechtien                             {
16083dfe5a3fSJens-Heiner Rechtien                                 try
16093dfe5a3fSJens-Heiner Rechtien                                 {
16103dfe5a3fSJens-Heiner Rechtien                                     bResult = aLockFile.CreateOwnLockFile();
161141dc917bSTamás Zolnai                                     if(pMSOLockFile)
161241dc917bSTamás Zolnai                                         bResult &= pMSOLockFile->CreateOwnLockFile();
16133dfe5a3fSJens-Heiner Rechtien                                 }
16146c89e69bSCaolán McNamara                                 catch (const uno::Exception&)
1615a245ebc7SIvo Hinkelmann                                 {
161620b1e644SMike Kaganski                                     if (tools::IsMappedWebDAVPath(GetURLObject().GetMainURL(
161720b1e644SMike Kaganski                                             INetURLObject::DecodeMechanism::NONE)))
1618642a49e8SMike Kaganski                                     {
1619642a49e8SMike Kaganski                                         // This is a path that redirects to a WebDAV resource;
1620642a49e8SMike Kaganski                                         // so failure creating lockfile is not an error here.
1621642a49e8SMike Kaganski                                         bResult = true;
1622642a49e8SMike Kaganski                                     }
1623642a49e8SMike Kaganski                                     else if (bLoading && !bNoUI)
1624a245ebc7SIvo Hinkelmann                                     {
16256ca3b364SJuergen Funk                                         bIoErr = true;
1626af9bea21SJuergen Funk                                         ShowLockFileProblemDialog(MessageDlg::LockFileIgnore);
1627af9bea21SJuergen Funk                                         bResult = true;   // always delete the defect lock-file
1628a245ebc7SIvo Hinkelmann                                     }
1629a245ebc7SIvo Hinkelmann                                 }
1630a245ebc7SIvo Hinkelmann 
1631a245ebc7SIvo Hinkelmann                                 // in case OOo locking is turned off the lock file is still written if possible
1632a245ebc7SIvo Hinkelmann                                 // but it is ignored while deciding whether the document should be opened for editing or not
16336ca3b364SJuergen Funk                                 if (!bResult && !IsOOoLockFileUsed() && !bIoErr)
1634a245ebc7SIvo Hinkelmann                                 {
1635e2799d25SMichael Meeks                                     bResult = true;
1636a245ebc7SIvo Hinkelmann                                     // take the ownership over the lock file
1637a245ebc7SIvo Hinkelmann                                     aLockFile.OverwriteOwnLockFile();
163841dc917bSTamás Zolnai 
163941dc917bSTamás Zolnai                                     if(pMSOLockFile)
164041dc917bSTamás Zolnai                                         pMSOLockFile->OverwriteOwnLockFile();
16413dfe5a3fSJens-Heiner Rechtien                                 }
16423dfe5a3fSJens-Heiner Rechtien                             }
16433dfe5a3fSJens-Heiner Rechtien 
16443dfe5a3fSJens-Heiner Rechtien                             if ( !bResult )
16452058774bSVladimir Glazounov                             {
1646f0461e83SNoel Grandin                                 LockFileEntry aData;
16473dfe5a3fSJens-Heiner Rechtien                                 try
16483dfe5a3fSJens-Heiner Rechtien                                 {
16493dfe5a3fSJens-Heiner Rechtien                                     aData = aLockFile.GetLockData();
16503dfe5a3fSJens-Heiner Rechtien                                 }
16516ca3b364SJuergen Funk                                 catch (const io::WrongFormatException&)
16526ca3b364SJuergen Funk                                 {
16536ca3b364SJuergen Funk                                     // we get empty or corrupt data
16546ca3b364SJuergen Funk                                     // info to the user
16556ca3b364SJuergen Funk                                     if (!bIoErr && bLoading && !bNoUI )
16566ca3b364SJuergen Funk                                         bResult = ShowLockFileProblemDialog(MessageDlg::LockFileCorrupt);
16576ca3b364SJuergen Funk 
16586ca3b364SJuergen Funk                                     // not show the Lock Document Dialog
16596ca3b364SJuergen Funk                                     bIoErr = true;
16606ca3b364SJuergen Funk                                 }
16616c89e69bSCaolán McNamara                                 catch( const uno::Exception& )
16626c89e69bSCaolán McNamara                                 {
16636ca3b364SJuergen Funk                                     // show the Lock Document Dialog, when locked from other app
16646ca3b364SJuergen Funk                                     bIoErr = !bHandleSysLocked;
16656c89e69bSCaolán McNamara                                 }
16663dfe5a3fSJens-Heiner Rechtien 
166750b4cbe9SKohei Yoshida                                 bool bOwnLock = false;
16683dfe5a3fSJens-Heiner Rechtien 
166996f1e7bbSVladimir Glazounov                                 if (!bHandleSysLocked)
16703dfe5a3fSJens-Heiner Rechtien                                 {
1671f0461e83SNoel Grandin                                     LockFileEntry aOwnData = svt::LockFileCommon::GenerateOwnEntry();
16726af02550SNoel Grandin                                     bOwnLock = aOwnData[LockFileComponent::SYSUSERNAME] == aData[LockFileComponent::SYSUSERNAME];
16733dfe5a3fSJens-Heiner Rechtien 
16743dfe5a3fSJens-Heiner Rechtien                                     if (bOwnLock
16756af02550SNoel Grandin                                         && aOwnData[LockFileComponent::LOCALHOST] == aData[LockFileComponent::LOCALHOST]
16766af02550SNoel Grandin                                         && aOwnData[LockFileComponent::USERURL] == aData[LockFileComponent::USERURL])
16773dfe5a3fSJens-Heiner Rechtien                                     {
16783dfe5a3fSJens-Heiner Rechtien                                         // this is own lock from the same installation, it could remain because of crash
1679e2799d25SMichael Meeks                                         bResult = true;
16802058774bSVladimir Glazounov                                     }
16812058774bSVladimir Glazounov                                 }
16823dfe5a3fSJens-Heiner Rechtien 
16832a705725SMike Kaganski                                 if ( !bResult && !bIoErr)
16843dfe5a3fSJens-Heiner Rechtien                                 {
16852a705725SMike Kaganski                                     if (!bNoUI)
1686607b80caSMike Kaganski                                         bUIStatus = ShowLockedDocumentDialog(
1687c49ea4f3SMike Kaganski                                             aData, bLoading, bOwnLock, bHandleSysLocked);
16882a705725SMike Kaganski                                     else if (bLoading && bTryIgnoreLockFile && !bHandleSysLocked)
16892a705725SMike Kaganski                                         bUIStatus = ShowLockResult::Succeeded;
16902a705725SMike Kaganski 
169111570275SNoel Grandin                                     if ( bUIStatus == ShowLockResult::Succeeded )
16923dfe5a3fSJens-Heiner Rechtien                                     {
16933dfe5a3fSJens-Heiner Rechtien                                         // take the ownership over the lock file
16943dfe5a3fSJens-Heiner Rechtien                                         bResult = aLockFile.OverwriteOwnLockFile();
169541dc917bSTamás Zolnai 
169641dc917bSTamás Zolnai                                         if(pMSOLockFile)
169741dc917bSTamás Zolnai                                             pMSOLockFile->OverwriteOwnLockFile();
16982058774bSVladimir Glazounov                                     }
16992a705725SMike Kaganski                                     else if (bLoading && !bHandleSysLocked)
17002a705725SMike Kaganski                                         eResult = LockFileResult::FailedLockFile;
17010f9599b6SMike Kaganski 
17020f9599b6SMike Kaganski                                     if (!bResult && pLockData)
17030f9599b6SMike Kaganski                                     {
17040f9599b6SMike Kaganski                                         std::copy(aData.begin(), aData.end(), pLockData->begin());
17050f9599b6SMike Kaganski                                     }
17062058774bSVladimir Glazounov                                 }
17073dfe5a3fSJens-Heiner Rechtien                             }
17082058774bSVladimir Glazounov                         }
17096c89e69bSCaolán McNamara                         catch( const uno::Exception& )
17102058774bSVladimir Glazounov                         {
17112058774bSVladimir Glazounov                         }
171211570275SNoel Grandin                     } while( !bResult && bUIStatus == ShowLockResult::Try );
17133dfe5a3fSJens-Heiner Rechtien 
17145e32815aSXisco Fauli                     pImpl->m_bLocked = bResult;
17153dfe5a3fSJens-Heiner Rechtien                 }
171696f1e7bbSVladimir Glazounov                 else
171796f1e7bbSVladimir Glazounov                 {
171896f1e7bbSVladimir Glazounov                     // this is no file URL, check whether the file is readonly
171996f1e7bbSVladimir Glazounov                     bResult = !bContentReadonly;
172096f1e7bbSVladimir Glazounov                 }
172196f1e7bbSVladimir Glazounov             }
172295eb0888SMatt K             else // read-only
172395eb0888SMatt K             {
172495eb0888SMatt K                 AddToCheckEditableWorkerList();
172595eb0888SMatt K             }
172696f1e7bbSVladimir Glazounov         }
17272058774bSVladimir Glazounov 
1728ed774e9fSNoel Grandin         if ( !bResult && GetErrorIgnoreWarning() == ERRCODE_NONE )
17292058774bSVladimir Glazounov         {
17302058774bSVladimir Glazounov             // the error should be set in case it is storing process
17312058774bSVladimir Glazounov             // or the document has been opened for editing explicitly
1732e4c40331SNoel Grandin             const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
1733e2799d25SMichael Meeks 
17347545436cSRüdiger Timm             if ( !bLoading || (pReadOnlyItem && !pReadOnlyItem->GetValue()) )
17359e4d84daSCaolán McNamara                 SetError(ERRCODE_IO_ACCESSDENIED);
17362058774bSVladimir Glazounov             else
1737f5dd4faeSMike Kaganski                 GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, true ) );
17382058774bSVladimir Glazounov         }
17392058774bSVladimir Glazounov 
17400849d5a2SIvo Hinkelmann         // when the file is locked, get the current file date
17410849d5a2SIvo Hinkelmann         if ( bResult && DocNeedsFileDateCheck() )
1742df8a15d8SKohei Yoshida             GetInitFileDate( true );
17432a705725SMike Kaganski 
17442a705725SMike Kaganski         if ( bResult )
17452a705725SMike Kaganski             eResult = LockFileResult::Succeeded;
1746b4b69861SMikhail Voytenko     }
17476c89e69bSCaolán McNamara     catch( const uno::Exception& )
1748b4b69861SMikhail Voytenko     {
1749889dc7bfSNoel Grandin         TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: high probability, that the content has not been created" );
1750b4b69861SMikhail Voytenko     }
17512a705725SMike Kaganski 
17522a705725SMike Kaganski     return eResult;
17533ee3e794STor Lillqvist #endif
17542058774bSVladimir Glazounov }
17552058774bSVladimir Glazounov 
17563b347664SMichael Stahl // this either returns non-null or throws exception
17573b347664SMichael Stahl uno::Reference<embed::XStorage>
TryEncryptedInnerPackage(uno::Reference<embed::XStorage> const & xStorage)1758193207c5SNoel Grandin SfxMedium::TryEncryptedInnerPackage(uno::Reference<embed::XStorage> const & xStorage)
17593b347664SMichael Stahl {
17603b347664SMichael Stahl     uno::Reference<embed::XStorage> xRet;
1761ca5c9591SNoel Grandin     if (xStorage->hasByName(u"encrypted-package"_ustr))
17623b347664SMichael Stahl     {
17633b347664SMichael Stahl         uno::Reference<io::XStream> const
17643b347664SMichael Stahl             xDecryptedInnerPackage = xStorage->openStreamElement(
1765ca5c9591SNoel Grandin                 u"encrypted-package"_ustr,
17663b347664SMichael Stahl                 embed::ElementModes::READ | embed::ElementModes::NOCREATE);
17671d221869SMichael Stahl         // either this throws due to wrong password or IO error, or returns stream
17681d221869SMichael Stahl         assert(xDecryptedInnerPackage.is());
17693b347664SMichael Stahl         // need a seekable stream => copy
1770ed0b12f4SNoel Grandin         Reference<uno::XComponentContext> const& xContext(::comphelper::getProcessComponentContext());
1771c8d2e22eSNoel Grandin         rtl::Reference< comphelper::UNOMemoryStream > xDecryptedInnerPackageStream = new comphelper::UNOMemoryStream();
17723b347664SMichael Stahl         comphelper::OStorageHelper::CopyInputToOutput(xDecryptedInnerPackage->getInputStream(), xDecryptedInnerPackageStream->getOutputStream());
17733b347664SMichael Stahl         xDecryptedInnerPackageStream->getOutputStream()->closeOutput();
17743b347664SMichael Stahl #if 0
17753b347664SMichael Stahl         // debug: dump to temp file
17763b347664SMichael Stahl         uno::Reference<io::XTempFile> const xTempFile(io::TempFile::create(xContext), uno::UNO_SET_THROW);
17773b347664SMichael Stahl         xTempFile->setRemoveFile(false);
17783b347664SMichael Stahl         comphelper::OStorageHelper::CopyInputToOutput(xDecryptedInnerPackageStream->getInputStream(), xTempFile->getOutputStream());
17793b347664SMichael Stahl         xTempFile->getOutputStream()->closeOutput();
17803b347664SMichael Stahl         SAL_DE BUG("AAA tempfile " << xTempFile->getResourceName());
17813b347664SMichael Stahl         uno::Reference<io::XSeekable>(xDecryptedInnerPackageStream, uno::UNO_QUERY_THROW)->seek(0);
17823b347664SMichael Stahl #endif
17831d221869SMichael Stahl         // create inner storage; opening the stream should have already verified
17841d221869SMichael Stahl         // the password so any failure here is probably due to a bug
17853b347664SMichael Stahl         xRet = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
17863b347664SMichael Stahl             PACKAGE_STORAGE_FORMAT_STRING, xDecryptedInnerPackageStream,
17873b347664SMichael Stahl             embed::ElementModes::READWRITE, xContext, false);
17883b347664SMichael Stahl         assert(xRet.is());
17891d221869SMichael Stahl         // consistency check: outer and inner package must have same mimetype
17901d221869SMichael Stahl         OUString const outerMediaType(uno::Reference<beans::XPropertySet>(pImpl->xStorage,
1791ca5c9591SNoel Grandin             uno::UNO_QUERY_THROW)->getPropertyValue(u"MediaType"_ustr).get<OUString>());
17921d221869SMichael Stahl         OUString const innerMediaType(uno::Reference<beans::XPropertySet>(xRet,
1793ca5c9591SNoel Grandin             uno::UNO_QUERY_THROW)->getPropertyValue(u"MediaType"_ustr).get<OUString>());
17941d221869SMichael Stahl         if (outerMediaType.isEmpty() || outerMediaType != innerMediaType)
17951d221869SMichael Stahl         {
1796ca5c9591SNoel Grandin             throw io::WrongFormatException(u"MediaType inconsistent in encrypted ODF package"_ustr);
17971d221869SMichael Stahl         }
17981d221869SMichael Stahl         // success:
17993b347664SMichael Stahl         pImpl->m_bODFWholesomeEncryption = true;
18004db31bcdSCaolán McNamara         pImpl->m_xODFDecryptedInnerPackageStream = std::move(xDecryptedInnerPackageStream);
18013b347664SMichael Stahl         pImpl->m_xODFEncryptedOuterStorage = xStorage;
18023b347664SMichael Stahl         pImpl->xStorage = xRet;
18033b347664SMichael Stahl     }
18043b347664SMichael Stahl     return xRet;
18053b347664SMichael Stahl }
18060ce0c369SAlexander Wilms 
IsRepairPackage() const18074981c0e7SMike Kaganski bool SfxMedium::IsRepairPackage() const
18084981c0e7SMike Kaganski {
18094981c0e7SMike Kaganski     const SfxBoolItem* pRepairItem = GetItemSet().GetItem(SID_REPAIRPACKAGE, false);
18104981c0e7SMike Kaganski     return pRepairItem && pRepairItem->GetValue();
18114981c0e7SMike Kaganski }
18124981c0e7SMike Kaganski 
GetStorage(bool bCreateTempFile)18139aadd633SSamuel Mehrbrodt uno::Reference < embed::XStorage > SfxMedium::GetStorage( bool bCreateTempFile )
1814762dd2b1SKurt Zenker {
18155e32815aSXisco Fauli     if ( pImpl->xStorage.is() || pImpl->m_bTriedStorage )
18165e32815aSXisco Fauli         return pImpl->xStorage;
1817762dd2b1SKurt Zenker 
1818fe23d400SKurt Zenker     uno::Sequence< uno::Any > aArgs( 2 );
1819ce22935aSMike Kaganski     auto pArgs = aArgs.getArray();
1820fe23d400SKurt Zenker 
1821ac49eeddSIvo Hinkelmann     // the medium should be retrieved before temporary file creation
1822ac49eeddSIvo Hinkelmann     // to let the MediaDescriptor be filled with the streams
1823fe23d400SKurt Zenker     GetMedium_Impl();
1824fe23d400SKurt Zenker 
18259aadd633SSamuel Mehrbrodt     if ( bCreateTempFile )
1826df8a15d8SKohei Yoshida         CreateTempFile( false );
1827fe23d400SKurt Zenker 
1828762dd2b1SKurt Zenker     GetMedium_Impl();
1829ac49eeddSIvo Hinkelmann 
1830ed774e9fSNoel Grandin     if ( GetErrorIgnoreWarning() )
18315e32815aSXisco Fauli         return pImpl->xStorage;
1832762dd2b1SKurt Zenker 
18334981c0e7SMike Kaganski     if (IsRepairPackage())
18345be98ebaSJens-Heiner Rechtien     {
183501ee5668SOliver Bolte         // the storage should be created for repairing mode
1836df8a15d8SKohei Yoshida         CreateTempFile( false );
1837ac49eeddSIvo Hinkelmann         GetMedium_Impl();
1838ac49eeddSIvo Hinkelmann 
1839913a2d36SNoel Grandin         Reference< css::ucb::XProgressHandler > xProgressHandler;
1840913a2d36SNoel Grandin         Reference< css::task::XStatusIndicator > xStatusIndicator;
1841762dd2b1SKurt Zenker 
1842f5dd4faeSMike Kaganski         const SfxUnoAnyItem* pxProgressItem = GetItemSet().GetItem(SID_PROGRESS_STATUSBAR_CONTROL, false);
18435be98ebaSJens-Heiner Rechtien         if( pxProgressItem && ( pxProgressItem->GetValue() >>= xStatusIndicator ) )
1844c8782b39SNoel Grandin             xProgressHandler.set( new utl::ProgressHandlerWrap( xStatusIndicator ) );
18455be98ebaSJens-Heiner Rechtien 
1846ce22935aSMike Kaganski         uno::Sequence< beans::PropertyValue > aAddProps{
1847ca5c9591SNoel Grandin             comphelper::makePropertyValue(u"RepairPackage"_ustr, true),
1848ca5c9591SNoel Grandin             comphelper::makePropertyValue(u"StatusIndicator"_ustr, xProgressHandler)
1849ce22935aSMike Kaganski         };
1850762dd2b1SKurt Zenker 
1851ac49eeddSIvo Hinkelmann         // the first arguments will be filled later
185201ee5668SOliver Bolte         aArgs.realloc( 3 );
1853ce22935aSMike Kaganski         pArgs = aArgs.getArray();
1854ce22935aSMike Kaganski         pArgs[2] <<= aAddProps;
1855ac49eeddSIvo Hinkelmann     }
185601ee5668SOliver Bolte 
18575e32815aSXisco Fauli     if ( pImpl->xStream.is() )
1858ac49eeddSIvo Hinkelmann     {
1859ac49eeddSIvo Hinkelmann         // since the storage is based on temporary stream we open it always read-write
1860ce22935aSMike Kaganski         pArgs[0] <<= pImpl->xStream;
1861ce22935aSMike Kaganski         pArgs[1] <<= embed::ElementModes::READWRITE;
18625e32815aSXisco Fauli         pImpl->bStorageBasedOnInStream = true;
186316a52236SMiklos Vajna         if (pImpl->m_bDisableFileSync)
186416a52236SMiklos Vajna         {
186516a52236SMiklos Vajna             // Forward NoFileSync to the storage factory.
1866ce22935aSMike Kaganski             aArgs.realloc(3); // ??? this may re-write the data added above for pRepairItem
1867ce22935aSMike Kaganski             pArgs = aArgs.getArray();
186816a52236SMiklos Vajna             uno::Sequence<beans::PropertyValue> aProperties(
18690bfa6a18SStephan Bergmann                 comphelper::InitPropertySequence({ { "NoFileSync", uno::Any(true) } }));
1870ce22935aSMike Kaganski             pArgs[2] <<= aProperties;
187116a52236SMiklos Vajna         }
1872ac49eeddSIvo Hinkelmann     }
18735e32815aSXisco Fauli     else if ( pImpl->xInputStream.is() )
1874ac49eeddSIvo Hinkelmann     {
1875ac49eeddSIvo Hinkelmann         // since the storage is based on temporary stream we open it always read-write
1876ce22935aSMike Kaganski         pArgs[0] <<= pImpl->xInputStream;
1877ce22935aSMike Kaganski         pArgs[1] <<= embed::ElementModes::READ;
18785e32815aSXisco Fauli         pImpl->bStorageBasedOnInStream = true;
1879ac49eeddSIvo Hinkelmann     }
1880ac49eeddSIvo Hinkelmann     else
1881ac49eeddSIvo Hinkelmann     {
1882ac49eeddSIvo Hinkelmann         CloseStreams_Impl();
1883ce22935aSMike Kaganski         pArgs[0] <<= pImpl->m_aName;
1884ce22935aSMike Kaganski         pArgs[1] <<= embed::ElementModes::READ;
18855e32815aSXisco Fauli         pImpl->bStorageBasedOnInStream = false;
18865be98ebaSJens-Heiner Rechtien     }
18875be98ebaSJens-Heiner Rechtien 
1888ac49eeddSIvo Hinkelmann     try
1889ac49eeddSIvo Hinkelmann     {
18905e32815aSXisco Fauli         pImpl->xStorage.set( ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ),
1891762dd2b1SKurt Zenker                             uno::UNO_QUERY );
18925be98ebaSJens-Heiner Rechtien     }
18936c89e69bSCaolán McNamara     catch( const uno::Exception& )
1894b268c93dSVladimir Glazounov     {
1895ac49eeddSIvo Hinkelmann         // impossibility to create the storage is no error
1896ea400a20SMathias Bauer     }
1897ea400a20SMathias Bauer 
1898d9e322d6SNoel Grandin     pImpl->nLastStorageError = GetErrorIgnoreWarning();
1899d9e322d6SNoel Grandin     if( pImpl->nLastStorageError != ERRCODE_NONE )
19000baa4c4fSMathias Bauer     {
19015e32815aSXisco Fauli         pImpl->xStorage = nullptr;
19025e32815aSXisco Fauli         if ( pImpl->m_pInStream )
19035e32815aSXisco Fauli             pImpl->m_pInStream->Seek(0);
1904ac49eeddSIvo Hinkelmann         return uno::Reference< embed::XStorage >();
19050baa4c4fSMathias Bauer     }
1906ea400a20SMathias Bauer 
19075e32815aSXisco Fauli     pImpl->m_bTriedStorage = true;
1908fd069beeSJens-Heiner Rechtien 
19093b347664SMichael Stahl     if (pImpl->xStorage.is())
19103b347664SMichael Stahl     {
19113b347664SMichael Stahl         pImpl->m_bODFWholesomeEncryption = false;
19123b347664SMichael Stahl         if (SetEncryptionDataToStorage_Impl())
19133b347664SMichael Stahl         {
19143b347664SMichael Stahl             try
19153b347664SMichael Stahl             {
19163b347664SMichael Stahl                 TryEncryptedInnerPackage(pImpl->xStorage);
19173b347664SMichael Stahl             }
19183b347664SMichael Stahl             catch (Exception const&)
19193b347664SMichael Stahl             {
19203b347664SMichael Stahl                 TOOLS_WARN_EXCEPTION("sfx.doc", "exception from TryEncryptedInnerPackage: ");
19213b347664SMichael Stahl                 SetError(ERRCODE_IO_GENERAL);
19223b347664SMichael Stahl             }
19233b347664SMichael Stahl         }
19243b347664SMichael Stahl     }
19253b347664SMichael Stahl 
19267101c620SMichael Stahl     if (GetErrorCode()) // decryption failed?
19277101c620SMichael Stahl     {
19287101c620SMichael Stahl         pImpl->xStorage.clear();
19297101c620SMichael Stahl     }
19307101c620SMichael Stahl 
1931ac49eeddSIvo Hinkelmann     // TODO/LATER: Get versionlist on demand
19325e32815aSXisco Fauli     if ( pImpl->xStorage.is() )
19339635faf2SRüdiger Timm     {
1934fd069beeSJens-Heiner Rechtien         GetVersionList();
19359635faf2SRüdiger Timm     }
1936fd069beeSJens-Heiner Rechtien 
1937e4c40331SNoel Grandin     const SfxInt16Item* pVersion = SfxItemSet::GetItem<SfxInt16Item>(pImpl->m_pSet.get(), SID_VERSION, false);
1938fd069beeSJens-Heiner Rechtien 
193950b4cbe9SKohei Yoshida     bool bResetStorage = false;
19402db4e62dSMathias Bauer     if ( pVersion && pVersion->GetValue() )
1941fd069beeSJens-Heiner Rechtien     {
1942dcd5dee8SAlbert Thuswaldner         // Read all available versions
194325b200ffSArkadiy Illarionov         if ( pImpl->aVersions.hasElements() )
1944fd069beeSJens-Heiner Rechtien         {
1945dcd5dee8SAlbert Thuswaldner             // Search for the version fits the comment
194604724c97SAndrea Gelmini             // The versions are numbered starting with 1, versions with
1947dcd5dee8SAlbert Thuswaldner             // negative versions numbers are counted backwards from the
1948dcd5dee8SAlbert Thuswaldner             // current version
19495f0ddb2dSMike Kaganski             short nVersion = pVersion->GetValue();
1950fd069beeSJens-Heiner Rechtien             if ( nVersion<0 )
195148db069fSStephan Bergmann                 nVersion = static_cast<short>(pImpl->aVersions.getLength()) + nVersion;
19525f0ddb2dSMike Kaganski             else // nVersion > 0; pVersion->GetValue() != 0 was the condition to this block
1953fd069beeSJens-Heiner Rechtien                 nVersion--;
1954fd069beeSJens-Heiner Rechtien 
1955ce22935aSMike Kaganski             const util::RevisionTag& rTag = pImpl->aVersions[nVersion];
1956fd069beeSJens-Heiner Rechtien             {
1957dcd5dee8SAlbert Thuswaldner                 // Open SubStorage for all versions
1958ca5c9591SNoel Grandin                 uno::Reference < embed::XStorage > xSub = pImpl->xStorage->openStorageElement( u"Versions"_ustr,
1959762dd2b1SKurt Zenker                         embed::ElementModes::READ );
1960fd069beeSJens-Heiner Rechtien 
1961dcd5dee8SAlbert Thuswaldner                 DBG_ASSERT( xSub.is(), "Version list, but no Versions!" );
1962fd069beeSJens-Heiner Rechtien 
1963dcd5dee8SAlbert Thuswaldner                 // There the version is stored as packed Stream
1964b5181a5eSVladimir Glazounov                 uno::Reference < io::XStream > xStr = xSub->openStreamElement( rTag.Identifier, embed::ElementModes::READ );
19650d5b5411STakeshi Abe                 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( xStr ));
1966de8caac6SNoel Grandin                 if ( pStream && pStream->GetError() == ERRCODE_NONE )
1967fd069beeSJens-Heiner Rechtien                 {
1968dcd5dee8SAlbert Thuswaldner                     // Unpack Stream  in TempDir
19694b95451fSNoel Grandin                     const OUString aTmpName = ::utl::CreateTempURL();
1970fd069beeSJens-Heiner Rechtien                     SvFileStream    aTmpStream( aTmpName, SFX_STREAM_READWRITE );
1971fd069beeSJens-Heiner Rechtien 
197215535e32SNoel Grandin                     pStream->ReadStream( aTmpStream );
19730d5b5411STakeshi Abe                     pStream.reset();
1974fd069beeSJens-Heiner Rechtien                     aTmpStream.Close();
1975fd069beeSJens-Heiner Rechtien 
1976dcd5dee8SAlbert Thuswaldner                     // Open data as Storage
19775e32815aSXisco Fauli                     pImpl->m_nStorOpenMode = SFX_STREAM_READONLY;
19785e32815aSXisco Fauli                     pImpl->xStorage = comphelper::OStorageHelper::GetStorageFromURL( aTmpName, embed::ElementModes::READ );
19795e32815aSXisco Fauli                     pImpl->bStorageBasedOnInStream = false;
19801946794aSLuboš Luňák                     OUString aTemp;
1981236714e8SStephan Bergmann                     osl::FileBase::getSystemPathFromFileURL( aTmpName, aTemp );
19825be98ebaSJens-Heiner Rechtien                     SetPhysicalName_Impl( aTemp );
19839ed9cd09SMathias Bauer 
19845e32815aSXisco Fauli                     pImpl->bIsTemp = true;
1985f5dd4faeSMike Kaganski                     GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, true ) );
1986b5181a5eSVladimir Glazounov                     // TODO/MBA
19875e32815aSXisco Fauli                     pImpl->aVersions.realloc(0);
1988fd069beeSJens-Heiner Rechtien                 }
1989fd069beeSJens-Heiner Rechtien                 else
1990df8a15d8SKohei Yoshida                     bResetStorage = true;
1991fd069beeSJens-Heiner Rechtien             }
1992fd069beeSJens-Heiner Rechtien         }
1993fd069beeSJens-Heiner Rechtien         else
1994df8a15d8SKohei Yoshida             bResetStorage = true;
1995fd069beeSJens-Heiner Rechtien     }
1996fd069beeSJens-Heiner Rechtien 
1997ea400a20SMathias Bauer     if ( bResetStorage )
1998fd069beeSJens-Heiner Rechtien     {
19995e32815aSXisco Fauli         pImpl->xStorage.clear();
20003b347664SMichael Stahl         pImpl->m_xODFDecryptedInnerPackageStream.clear();
20013b347664SMichael Stahl         pImpl->m_xODFEncryptedOuterStorage.clear();
20025e32815aSXisco Fauli         if ( pImpl->m_pInStream )
2003ff1f6a5fSNoel Grandin             pImpl->m_pInStream->Seek( 0 );
2004fd069beeSJens-Heiner Rechtien     }
2005fd069beeSJens-Heiner Rechtien 
20065e32815aSXisco Fauli     pImpl->bIsStorage = pImpl->xStorage.is();
20075e32815aSXisco Fauli     return pImpl->xStorage;
20089635faf2SRüdiger Timm }
20099635faf2SRüdiger Timm 
GetScriptingStorageToSign_Impl()20101580c31fSNoel Grandin const uno::Reference<embed::XStorage> & SfxMedium::GetScriptingStorageToSign_Impl()
20113b347664SMichael Stahl {
20123b347664SMichael Stahl     // this was set when it was initially loaded
20133b347664SMichael Stahl     if (pImpl->m_bODFWholesomeEncryption)
20143b347664SMichael Stahl     {
20153b347664SMichael Stahl         // (partial) scripting signature can only be in inner storage!
20163b347664SMichael Stahl         // Note: a "PackageFormat" storage like pImpl->xStorage doesn't work
20173b347664SMichael Stahl         // (even if it's not encrypted) because it hides the "META-INF" dir.
20183b347664SMichael Stahl         // This "ZipFormat" storage is used only read-only; a writable one is
20193b347664SMichael Stahl         // created manually in SignContents_Impl().
20203b347664SMichael Stahl         if (!pImpl->m_xODFDecryptedInnerZipStorage.is())
20213b347664SMichael Stahl         {
20223b347664SMichael Stahl             GetStorage(false);
20233b347664SMichael Stahl             // don't care about xStorage here because Zip is readonly
20243b347664SMichael Stahl             SAL_WARN_IF(!pImpl->m_xODFDecryptedInnerPackageStream.is(), "sfx.doc", "no inner package stream?");
20253b347664SMichael Stahl             if (pImpl->m_xODFDecryptedInnerPackageStream.is())
20263b347664SMichael Stahl             {
20273b347664SMichael Stahl                 pImpl->m_xODFDecryptedInnerZipStorage =
20283b347664SMichael Stahl                     ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
20293b347664SMichael Stahl                         ZIP_STORAGE_FORMAT_STRING,
203074746380SMike Kaganski                         pImpl->m_xODFDecryptedInnerPackageStream->getInputStream(), {},
20314981c0e7SMike Kaganski                         IsRepairPackage());
20323b347664SMichael Stahl             }
20333b347664SMichael Stahl         }
20343b347664SMichael Stahl         return pImpl->m_xODFDecryptedInnerZipStorage;
20353b347664SMichael Stahl     }
20363b347664SMichael Stahl     else
20373b347664SMichael Stahl     {
20383b347664SMichael Stahl         return GetZipStorageToSign_Impl(true);
20393b347664SMichael Stahl     }
20403b347664SMichael Stahl }
20410ce0c369SAlexander Wilms 
20423b347664SMichael Stahl // note: currently nobody who calls this with "false" writes into an ODF
20433b347664SMichael Stahl // storage that is returned here, that is only for OOXML
GetZipStorageToSign_Impl(bool bReadOnly)2044a967c8f6SNoel Grandin uno::Reference< embed::XStorage > const & SfxMedium::GetZipStorageToSign_Impl( bool bReadOnly )
2045083d2f57SVladimir Glazounov {
2046ed774e9fSNoel Grandin     if ( !GetErrorIgnoreWarning() && !pImpl->m_xZipStorage.is() )
2047083d2f57SVladimir Glazounov     {
2048083d2f57SVladimir Glazounov         GetMedium_Impl();
2049083d2f57SVladimir Glazounov 
2050083d2f57SVladimir Glazounov         try
2051083d2f57SVladimir Glazounov         {
2052ac49eeddSIvo Hinkelmann             // we can not sign document if there is no stream
2053ac49eeddSIvo Hinkelmann             // should it be possible at all?
20545e32815aSXisco Fauli             if ( !bReadOnly && pImpl->xStream.is() )
2055083d2f57SVladimir Glazounov             {
205674746380SMike Kaganski                 pImpl->m_xZipStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
205774746380SMike Kaganski                     ZIP_STORAGE_FORMAT_STRING, pImpl->xStream, css::embed::ElementModes::READWRITE,
20584981c0e7SMike Kaganski                     {}, IsRepairPackage());
2059083d2f57SVladimir Glazounov             }
20605e32815aSXisco Fauli             else if ( pImpl->xInputStream.is() )
2061083d2f57SVladimir Glazounov             {
206274746380SMike Kaganski                 pImpl->m_xZipStorage
206374746380SMike Kaganski                     = ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
20644981c0e7SMike Kaganski                         ZIP_STORAGE_FORMAT_STRING, pImpl->xInputStream, {}, IsRepairPackage());
2065083d2f57SVladimir Glazounov             }
2066083d2f57SVladimir Glazounov         }
20676c89e69bSCaolán McNamara         catch( const uno::Exception& )
2068083d2f57SVladimir Glazounov         {
2069d38cb53eSMichael Stahl             SAL_WARN( "sfx.doc", "No possibility to get readonly version of storage from medium!" );
2070083d2f57SVladimir Glazounov         }
2071083d2f57SVladimir Glazounov 
2072ed774e9fSNoel Grandin         if ( GetErrorIgnoreWarning() ) // do not remove warnings
2073083d2f57SVladimir Glazounov             ResetError();
2074083d2f57SVladimir Glazounov     }
2075083d2f57SVladimir Glazounov 
20765e32815aSXisco Fauli     return pImpl->m_xZipStorage;
2077083d2f57SVladimir Glazounov }
2078083d2f57SVladimir Glazounov 
20790ce0c369SAlexander Wilms 
CloseZipStorage_Impl()2080ac49eeddSIvo Hinkelmann void SfxMedium::CloseZipStorage_Impl()
2081083d2f57SVladimir Glazounov {
20825e32815aSXisco Fauli     if ( pImpl->m_xZipStorage.is() )
2083083d2f57SVladimir Glazounov     {
2084083d2f57SVladimir Glazounov         try {
20855e32815aSXisco Fauli             pImpl->m_xZipStorage->dispose();
20866c89e69bSCaolán McNamara         } catch( const uno::Exception& )
2087083d2f57SVladimir Glazounov         {}
2088083d2f57SVladimir Glazounov 
20895e32815aSXisco Fauli         pImpl->m_xZipStorage.clear();
2090083d2f57SVladimir Glazounov     }
20913b347664SMichael Stahl     pImpl->m_xODFDecryptedInnerZipStorage.clear();
2092083d2f57SVladimir Glazounov }
2093083d2f57SVladimir Glazounov 
CloseStorage()2094fd069beeSJens-Heiner Rechtien void SfxMedium::CloseStorage()
2095fd069beeSJens-Heiner Rechtien {
20965e32815aSXisco Fauli     if ( pImpl->xStorage.is() )
2097762dd2b1SKurt Zenker     {
2098476a6523SNoel Grandin         uno::Reference < lang::XComponent > xComp = pImpl->xStorage;
2099f117fe35SRüdiger Timm         // in the salvage mode the medium does not own the storage
21005e32815aSXisco Fauli         if ( pImpl->bDisposeStorage && !pImpl->m_bSalvageMode )
210142061706SPascal Junck         {
210242061706SPascal Junck             try {
2103762dd2b1SKurt Zenker                 xComp->dispose();
21046c89e69bSCaolán McNamara             } catch( const uno::Exception& )
210542061706SPascal Junck             {
2106d38cb53eSMichael Stahl                 SAL_WARN( "sfx.doc", "Medium's storage is already disposed!" );
210742061706SPascal Junck             }
210842061706SPascal Junck         }
210942061706SPascal Junck 
21105e32815aSXisco Fauli         pImpl->xStorage.clear();
21113b347664SMichael Stahl         pImpl->m_xODFDecryptedInnerPackageStream.clear();
21123b347664SMichael Stahl //        pImpl->m_xODFDecryptedInnerZipStorage.clear();
21133b347664SMichael Stahl         pImpl->m_xODFEncryptedOuterStorage.clear();
21145e32815aSXisco Fauli         pImpl->bStorageBasedOnInStream = false;
2115762dd2b1SKurt Zenker     }
2116762dd2b1SKurt Zenker 
21175e32815aSXisco Fauli     pImpl->m_bTriedStorage = false;
21185e32815aSXisco Fauli     pImpl->bIsStorage = false;
2119fd069beeSJens-Heiner Rechtien }
2120fd069beeSJens-Heiner Rechtien 
CanDisposeStorage_Impl(bool bDisposeStorage)21215fe7ecc0SNoel Grandin void SfxMedium::CanDisposeStorage_Impl( bool bDisposeStorage )
2122762dd2b1SKurt Zenker {
21235e32815aSXisco Fauli     pImpl->bDisposeStorage = bDisposeStorage;
2124762dd2b1SKurt Zenker }
2125762dd2b1SKurt Zenker 
WillDisposeStorageOnClose_Impl()21265fe7ecc0SNoel Grandin bool SfxMedium::WillDisposeStorageOnClose_Impl()
212720e8efb0SVladimir Glazounov {
21285e32815aSXisco Fauli     return pImpl->bDisposeStorage;
212920e8efb0SVladimir Glazounov }
213020e8efb0SVladimir Glazounov 
GetOpenMode() const213111f2a588SKohei Yoshida StreamMode SfxMedium::GetOpenMode() const
213211f2a588SKohei Yoshida {
21335e32815aSXisco Fauli     return pImpl->m_nStorOpenMode;
213411f2a588SKohei Yoshida }
213511f2a588SKohei Yoshida 
SetOpenMode(StreamMode nStorOpen,bool bDontClose)2136fd069beeSJens-Heiner Rechtien void SfxMedium::SetOpenMode( StreamMode nStorOpen,
21375fe7ecc0SNoel Grandin                              bool bDontClose )
2138fd069beeSJens-Heiner Rechtien {
21395e32815aSXisco Fauli     if ( pImpl->m_nStorOpenMode != nStorOpen )
2140fd069beeSJens-Heiner Rechtien     {
21415e32815aSXisco Fauli         pImpl->m_nStorOpenMode = nStorOpen;
2142fd069beeSJens-Heiner Rechtien 
2143fd069beeSJens-Heiner Rechtien         if( !bDontClose )
21441d100003SJens-Heiner Rechtien         {
21455e32815aSXisco Fauli             if ( pImpl->xStorage.is() )
21461d100003SJens-Heiner Rechtien                 CloseStorage();
21471d100003SJens-Heiner Rechtien 
21481d100003SJens-Heiner Rechtien             CloseStreams_Impl();
21491d100003SJens-Heiner Rechtien         }
2150fd069beeSJens-Heiner Rechtien     }
2151fd069beeSJens-Heiner Rechtien }
2152fd069beeSJens-Heiner Rechtien 
21530ce0c369SAlexander Wilms 
UseBackupToRestore_Impl(::ucbhelper::Content & aOriginalContent,const Reference<css::ucb::XCommandEnvironment> & xComEnv)21545fe7ecc0SNoel Grandin bool SfxMedium::UseBackupToRestore_Impl( ::ucbhelper::Content& aOriginalContent,
2155913a2d36SNoel Grandin                                             const Reference< css::ucb::XCommandEnvironment >& xComEnv )
2156762dd2b1SKurt Zenker {
2157762dd2b1SKurt Zenker     try
2158762dd2b1SKurt Zenker     {
21595e32815aSXisco Fauli         ::ucbhelper::Content aTransactCont( pImpl->m_aBackupURL, xComEnv, comphelper::getProcessComponentContext() );
2160762dd2b1SKurt Zenker 
2161762dd2b1SKurt Zenker         Reference< XInputStream > aOrigInput = aTransactCont.openStream();
2162df8a15d8SKohei Yoshida         aOriginalContent.writeStream( aOrigInput, true );
2163df8a15d8SKohei Yoshida         return true;
2164762dd2b1SKurt Zenker     }
21656c89e69bSCaolán McNamara     catch( const Exception& )
2166762dd2b1SKurt Zenker     {
2167762dd2b1SKurt Zenker         // in case of failure here the backup file should not be removed
2168762dd2b1SKurt Zenker         // TODO/LATER: a message should be used to let user know about the backup
21695e32815aSXisco Fauli         pImpl->m_bRemoveBackup = false;
2170762dd2b1SKurt Zenker         // TODO/LATER: needs a specific error code
21715e32815aSXisco Fauli         pImpl->m_eError = ERRCODE_IO_GENERAL;
2172762dd2b1SKurt Zenker     }
2173762dd2b1SKurt Zenker 
2174df8a15d8SKohei Yoshida     return false;
2175762dd2b1SKurt Zenker }
2176762dd2b1SKurt Zenker 
21770ce0c369SAlexander Wilms 
StorageCommit_Impl()21785fe7ecc0SNoel Grandin bool SfxMedium::StorageCommit_Impl()
2179762dd2b1SKurt Zenker {
218050b4cbe9SKohei Yoshida     bool bResult = false;
2181913a2d36SNoel Grandin     Reference< css::ucb::XCommandEnvironment > xDummyEnv;
21825d88f117SIvo Hinkelmann     ::ucbhelper::Content aOriginalContent;
2183762dd2b1SKurt Zenker 
21845e32815aSXisco Fauli     if ( pImpl->xStorage.is() )
2185762dd2b1SKurt Zenker     {
2186ed774e9fSNoel Grandin         if ( !GetErrorIgnoreWarning() )
2187762dd2b1SKurt Zenker         {
21885e32815aSXisco Fauli             uno::Reference < embed::XTransactedObject > xTrans( pImpl->xStorage, uno::UNO_QUERY );
2189762dd2b1SKurt Zenker             if ( xTrans.is() )
2190762dd2b1SKurt Zenker             {
2191762dd2b1SKurt Zenker                 try
2192762dd2b1SKurt Zenker                 {
2193762dd2b1SKurt Zenker                     xTrans->commit();
2194ac49eeddSIvo Hinkelmann                     CloseZipStorage_Impl();
2195df8a15d8SKohei Yoshida                     bResult = true;
2196762dd2b1SKurt Zenker                 }
21976c89e69bSCaolán McNamara                 catch ( const embed::UseBackupException& aBackupExc )
2198762dd2b1SKurt Zenker                 {
2199ac49eeddSIvo Hinkelmann                     // since the temporary file is created always now, the scenario is close to be impossible
22005e32815aSXisco Fauli                     if ( !pImpl->pTempFile )
2201762dd2b1SKurt Zenker                     {
22028c8f2a52SNoel Grandin                         OSL_ENSURE( !pImpl->m_aBackupURL.isEmpty(), "No backup on storage commit!" );
22035e32815aSXisco Fauli                         if ( !pImpl->m_aBackupURL.isEmpty()
2204bfde4866SNoel Grandin                             && ::ucbhelper::Content::create( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ),
22059ac86f48SStephan Bergmann                                                         xDummyEnv, comphelper::getProcessComponentContext(),
2206762dd2b1SKurt Zenker                                                         aOriginalContent ) )
2207762dd2b1SKurt Zenker                         {
2208762dd2b1SKurt Zenker                             // use backup to restore the file
2209762dd2b1SKurt Zenker                             // the storage has already disconnected from original location
2210e96f63f6SOliver Bolte                             CloseAndReleaseStreams_Impl();
2211762dd2b1SKurt Zenker                             if ( !UseBackupToRestore_Impl( aOriginalContent, xDummyEnv ) )
2212762dd2b1SKurt Zenker                             {
2213762dd2b1SKurt Zenker                                 // connect the medium to the temporary file of the storage
22145e32815aSXisco Fauli                                 pImpl->aContent = ::ucbhelper::Content();
22155e32815aSXisco Fauli                                 pImpl->m_aName = aBackupExc.TemporaryFileURL;
22168c8f2a52SNoel Grandin                                 OSL_ENSURE( !pImpl->m_aName.isEmpty(), "The exception _must_ contain the temporary URL!" );
2217762dd2b1SKurt Zenker                             }
2218762dd2b1SKurt Zenker                         }
22199084c11fSMichael Stahl                     }
2220762dd2b1SKurt Zenker 
2221ed774e9fSNoel Grandin                     if (!GetErrorIgnoreWarning())
22229e4d84daSCaolán McNamara                         SetError(ERRCODE_IO_GENERAL);
2223762dd2b1SKurt Zenker                 }
22246c89e69bSCaolán McNamara                 catch ( const uno::Exception& )
2225762dd2b1SKurt Zenker                 {
2226762dd2b1SKurt Zenker                     //TODO/LATER: improve error handling
22279e4d84daSCaolán McNamara                     SetError(ERRCODE_IO_GENERAL);
2228762dd2b1SKurt Zenker                 }
2229762dd2b1SKurt Zenker             }
2230762dd2b1SKurt Zenker         }
2231762dd2b1SKurt Zenker     }
2232762dd2b1SKurt Zenker 
2233762dd2b1SKurt Zenker     return bResult;
2234762dd2b1SKurt Zenker }
2235762dd2b1SKurt Zenker 
22360ce0c369SAlexander Wilms 
TransactedTransferForFS_Impl(const INetURLObject & aSource,const INetURLObject & aDest,const Reference<css::ucb::XCommandEnvironment> & xComEnv)223738c23520SNoel Grandin void SfxMedium::TransactedTransferForFS_Impl( const INetURLObject& aSource,
22385be98ebaSJens-Heiner Rechtien                                                  const INetURLObject& aDest,
2239913a2d36SNoel Grandin                                                  const Reference< css::ucb::XCommandEnvironment >& xComEnv )
22405be98ebaSJens-Heiner Rechtien {
2241913a2d36SNoel Grandin     Reference< css::ucb::XCommandEnvironment > xDummyEnv;
22425d88f117SIvo Hinkelmann     ::ucbhelper::Content aOriginalContent;
22435be98ebaSJens-Heiner Rechtien 
2244c175c2beSVladimir Glazounov     try
2245c175c2beSVladimir Glazounov     {
2246bfde4866SNoel Grandin         aOriginalContent = ::ucbhelper::Content( aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xComEnv, comphelper::getProcessComponentContext() );
2247c175c2beSVladimir Glazounov     }
2248913a2d36SNoel Grandin     catch ( const css::ucb::CommandAbortedException& )
2249c175c2beSVladimir Glazounov     {
22505e32815aSXisco Fauli         pImpl->m_eError = ERRCODE_ABORT;
2251c175c2beSVladimir Glazounov     }
2252913a2d36SNoel Grandin     catch ( const css::ucb::CommandFailedException& )
2253c175c2beSVladimir Glazounov     {
22545e32815aSXisco Fauli         pImpl->m_eError = ERRCODE_ABORT;
2255c175c2beSVladimir Glazounov     }
2256913a2d36SNoel Grandin     catch (const css::ucb::ContentCreationException& ex)
2257c175c2beSVladimir Glazounov     {
22585e32815aSXisco Fauli         pImpl->m_eError = ERRCODE_IO_GENERAL;
2259c175c2beSVladimir Glazounov         if (
2260913a2d36SNoel Grandin             (ex.eError == css::ucb::ContentCreationError_NO_CONTENT_PROVIDER    ) ||
2261913a2d36SNoel Grandin             (ex.eError == css::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
2262c175c2beSVladimir Glazounov            )
2263c175c2beSVladimir Glazounov         {
22645e32815aSXisco Fauli             pImpl->m_eError = ERRCODE_IO_NOTEXISTSPATH;
2265c175c2beSVladimir Glazounov         }
2266c175c2beSVladimir Glazounov     }
2267913a2d36SNoel Grandin     catch (const css::uno::Exception&)
2268c175c2beSVladimir Glazounov     {
22695e32815aSXisco Fauli        pImpl->m_eError = ERRCODE_IO_GENERAL;
2270c175c2beSVladimir Glazounov     }
22715be98ebaSJens-Heiner Rechtien 
2272536a6d6cSNoel Grandin     if( pImpl->m_eError && !pImpl->m_eError.IsWarning() )
2273536a6d6cSNoel Grandin         return;
2274536a6d6cSNoel Grandin 
22755e32815aSXisco Fauli     if ( pImpl->xStorage.is() )
22761d100003SJens-Heiner Rechtien         CloseStorage();
22771d100003SJens-Heiner Rechtien 
22781d100003SJens-Heiner Rechtien     CloseStreams_Impl();
22791d100003SJens-Heiner Rechtien 
22805d88f117SIvo Hinkelmann     ::ucbhelper::Content aTempCont;
2281bfde4866SNoel Grandin     if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDummyEnv, comphelper::getProcessComponentContext(), aTempCont ) )
22825be98ebaSJens-Heiner Rechtien     {
228350b4cbe9SKohei Yoshida         bool bTransactStarted = false;
2284f5dd4faeSMike Kaganski         const SfxBoolItem* pOverWrite = GetItemSet().GetItem<SfxBoolItem>(SID_OVERWRITE, false);
2285fa135fd0SNoel Grandin         bool bOverWrite = !pOverWrite || pOverWrite->GetValue();
228646da549aSNoel         bool bResult = false;
22875be98ebaSJens-Heiner Rechtien 
22885be98ebaSJens-Heiner Rechtien         try
22895be98ebaSJens-Heiner Rechtien         {
2290a62878ffSAndreas Heinisch             // tdf#60237 - if the OverWrite property of the MediaDescriptor is set to false,
2291a62878ffSAndreas Heinisch             // try to write the file before trying to rename or copy it
2292a62878ffSAndreas Heinisch             if (!(bOverWrite
2293a62878ffSAndreas Heinisch                   && ::utl::UCBContentHelper::IsDocument(
2294a62878ffSAndreas Heinisch                       aDest.GetMainURL(INetURLObject::DecodeMechanism::NONE))))
2295a62878ffSAndreas Heinisch             {
2296a62878ffSAndreas Heinisch                 Reference< XInputStream > aTempInput = aTempCont.openStream();
2297a62878ffSAndreas Heinisch                 aOriginalContent.writeStream( aTempInput, bOverWrite );
2298a62878ffSAndreas Heinisch                 bResult = true;
2299a62878ffSAndreas Heinisch             } else {
23002157a353SMiklos Vajna                 OUString aSourceMainURL = aSource.GetMainURL(INetURLObject::DecodeMechanism::NONE);
23012157a353SMiklos Vajna                 OUString aDestMainURL = aDest.GetMainURL(INetURLObject::DecodeMechanism::NONE);
2302fb04780cSMiklos Vajna 
2303fb04780cSMiklos Vajna                 sal_uInt64 nAttributes = GetDefaultFileAttributes(aDestMainURL);
2304603b63b4SMike Kaganski                 if (IsFileMovable(aDest)
2305c9343988SMike Kaganski                     && osl::File::replace(aSourceMainURL, aDestMainURL) == osl::FileBase::E_None)
2306fb04780cSMiklos Vajna                 {
2307fb04780cSMiklos Vajna                     if (nAttributes)
2308fb04780cSMiklos Vajna                         // Adjust attributes, source might be created with
2309fb04780cSMiklos Vajna                         // the osl_File_OpenFlag_Private flag.
2310fb04780cSMiklos Vajna                         osl::File::setAttributes(aDestMainURL, nAttributes);
23112157a353SMiklos Vajna                     bResult = true;
2312fb04780cSMiklos Vajna                 }
23132157a353SMiklos Vajna                 else
23142157a353SMiklos Vajna                 {
23155e32815aSXisco Fauli                     if( pImpl->m_aBackupURL.isEmpty() )
23165be98ebaSJens-Heiner Rechtien                         DoInternalBackup_Impl( aOriginalContent );
23175be98ebaSJens-Heiner Rechtien 
23185e32815aSXisco Fauli                     if( !pImpl->m_aBackupURL.isEmpty() )
23195be98ebaSJens-Heiner Rechtien                     {
23205be98ebaSJens-Heiner Rechtien                         Reference< XInputStream > aTempInput = aTempCont.openStream();
2321df8a15d8SKohei Yoshida                         bTransactStarted = true;
2322ca5c9591SNoel Grandin                         aOriginalContent.setPropertyValue( u"Size"_ustr, uno::Any( sal_Int64(0) ) );
23235be98ebaSJens-Heiner Rechtien                         aOriginalContent.writeStream( aTempInput, bOverWrite );
2324df8a15d8SKohei Yoshida                         bResult = true;
23255be98ebaSJens-Heiner Rechtien                     }
23265be98ebaSJens-Heiner Rechtien                     else
23275be98ebaSJens-Heiner Rechtien                     {
23285e32815aSXisco Fauli                         pImpl->m_eError = ERRCODE_SFX_CANTCREATEBACKUP;
23295be98ebaSJens-Heiner Rechtien                     }
23305be98ebaSJens-Heiner Rechtien                 }
23315be98ebaSJens-Heiner Rechtien             }
23322157a353SMiklos Vajna         }
2333913a2d36SNoel Grandin         catch ( const css::ucb::CommandAbortedException& )
23345be98ebaSJens-Heiner Rechtien         {
23355e32815aSXisco Fauli             pImpl->m_eError = ERRCODE_ABORT;
23365be98ebaSJens-Heiner Rechtien         }
2337913a2d36SNoel Grandin         catch ( const css::ucb::CommandFailedException& )
23385be98ebaSJens-Heiner Rechtien         {
23395e32815aSXisco Fauli             pImpl->m_eError = ERRCODE_ABORT;
23405be98ebaSJens-Heiner Rechtien         }
2341913a2d36SNoel Grandin         catch ( const css::ucb::InteractiveIOException& r )
23425be98ebaSJens-Heiner Rechtien         {
23435be98ebaSJens-Heiner Rechtien             if ( r.Code == IOErrorCode_ACCESS_DENIED )
23445e32815aSXisco Fauli                 pImpl->m_eError = ERRCODE_IO_ACCESSDENIED;
23455be98ebaSJens-Heiner Rechtien             else if ( r.Code == IOErrorCode_NOT_EXISTING )
23465e32815aSXisco Fauli                 pImpl->m_eError = ERRCODE_IO_NOTEXISTS;
23475be98ebaSJens-Heiner Rechtien             else if ( r.Code == IOErrorCode_CANT_READ )
23485e32815aSXisco Fauli                 pImpl->m_eError = ERRCODE_IO_CANTREAD;
23495be98ebaSJens-Heiner Rechtien             else
23505e32815aSXisco Fauli                 pImpl->m_eError = ERRCODE_IO_GENERAL;
23515be98ebaSJens-Heiner Rechtien         }
2352a62878ffSAndreas Heinisch         // tdf#60237 - if the file is already present, raise the appropriate error
2353a62878ffSAndreas Heinisch         catch (const css::ucb::NameClashException& )
2354a62878ffSAndreas Heinisch         {
2355a62878ffSAndreas Heinisch             pImpl->m_eError = ERRCODE_IO_ALREADYEXISTS;
2356a62878ffSAndreas Heinisch         }
2357913a2d36SNoel Grandin         catch ( const css::uno::Exception& )
23585be98ebaSJens-Heiner Rechtien         {
23595e32815aSXisco Fauli             pImpl->m_eError = ERRCODE_IO_GENERAL;
23605be98ebaSJens-Heiner Rechtien         }
23615be98ebaSJens-Heiner Rechtien 
23625be98ebaSJens-Heiner Rechtien         if ( bResult )
23635be98ebaSJens-Heiner Rechtien         {
23645e32815aSXisco Fauli             if ( pImpl->pTempFile )
2365c175c2beSVladimir Glazounov             {
23665e32815aSXisco Fauli                 pImpl->pTempFile->EnableKillingFile();
2367e4c40331SNoel Grandin                 pImpl->pTempFile.reset();
2368c175c2beSVladimir Glazounov             }
23695be98ebaSJens-Heiner Rechtien         }
237025a997c1SMatt K         else if ( bTransactStarted && pImpl->m_eError != ERRCODE_ABORT )
23715be98ebaSJens-Heiner Rechtien         {
2372762dd2b1SKurt Zenker             UseBackupToRestore_Impl( aOriginalContent, xDummyEnv );
23735be98ebaSJens-Heiner Rechtien         }
23745be98ebaSJens-Heiner Rechtien     }
23755be98ebaSJens-Heiner Rechtien     else
23765e32815aSXisco Fauli         pImpl->m_eError = ERRCODE_IO_CANTREAD;
23775be98ebaSJens-Heiner Rechtien }
23785be98ebaSJens-Heiner Rechtien 
23790ce0c369SAlexander Wilms 
TryDirectTransfer(const OUString & aURL,SfxItemSet const & aTargetSet)23807ed17807SNoel Grandin bool SfxMedium::TryDirectTransfer( const OUString& aURL, SfxItemSet const & aTargetSet )
23812f9a8226SOliver Bolte {
2382ed774e9fSNoel Grandin     if ( GetErrorIgnoreWarning() )
2383df8a15d8SKohei Yoshida         return false;
23842f9a8226SOliver Bolte 
23852f9a8226SOliver Bolte     // if the document had no password it should be stored without password
23862f9a8226SOliver Bolte     // if the document had password it should be stored with the same password
23872f9a8226SOliver Bolte     // otherwise the stream copying can not be done
2388f5dd4faeSMike Kaganski     const SfxStringItem* pNewPassItem = aTargetSet.GetItem(SID_PASSWORD, false);
2389f5dd4faeSMike Kaganski     const SfxStringItem* pOldPassItem = GetItemSet().GetItem(SID_PASSWORD, false);
23902f9a8226SOliver Bolte     if ( ( !pNewPassItem && !pOldPassItem )
239145739fadSCaolán McNamara       || ( pNewPassItem && pOldPassItem && pNewPassItem->GetValue() == pOldPassItem->GetValue() ) )
23922f9a8226SOliver Bolte     {
23932f9a8226SOliver Bolte         // the filter must be the same
2394f5dd4faeSMike Kaganski         const SfxStringItem* pNewFilterItem = aTargetSet.GetItem(SID_FILTER_NAME, false);
2395f5dd4faeSMike Kaganski         const SfxStringItem* pOldFilterItem = GetItemSet().GetItem(SID_FILTER_NAME, false);
239645739fadSCaolán McNamara         if ( pNewFilterItem && pOldFilterItem && pNewFilterItem->GetValue() == pOldFilterItem->GetValue() )
23972f9a8226SOliver Bolte         {
23982f9a8226SOliver Bolte             // get the input stream and copy it
23992f9a8226SOliver Bolte             // in case of success return true
24002f9a8226SOliver Bolte             uno::Reference< io::XInputStream > xInStream = GetInputStream();
24012f9a8226SOliver Bolte 
24022f9a8226SOliver Bolte             ResetError();
24032f9a8226SOliver Bolte             if ( xInStream.is() )
24042f9a8226SOliver Bolte             {
24052f9a8226SOliver Bolte                 try
24062f9a8226SOliver Bolte                 {
24072f9a8226SOliver Bolte                     uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
24082f9a8226SOliver Bolte                     sal_Int64 nPos = 0;
24092f9a8226SOliver Bolte                     if ( xSeek.is() )
24102f9a8226SOliver Bolte                     {
24112f9a8226SOliver Bolte                         nPos = xSeek->getPosition();
24122f9a8226SOliver Bolte                         xSeek->seek( 0 );
24132f9a8226SOliver Bolte                     }
24142f9a8226SOliver Bolte 
2415913a2d36SNoel Grandin                     uno::Reference < css::ucb::XCommandEnvironment > xEnv;
24169ac86f48SStephan Bergmann                     ::ucbhelper::Content aTargetContent( aURL, xEnv, comphelper::getProcessComponentContext() );
24172f9a8226SOliver Bolte 
24182f9a8226SOliver Bolte                     InsertCommandArgument aInsertArg;
24190c6e2689SCaolán McNamara                     aInsertArg.Data = std::move(xInStream);
2420adeefc62SJan Holesovsky                     const SfxBoolItem* pOverWrite = aTargetSet.GetItem<SfxBoolItem>(SID_OVERWRITE, false);
2421fa135fd0SNoel Grandin                     if ( pOverWrite && !pOverWrite->GetValue() ) // argument says: never overwrite
2422df8a15d8SKohei Yoshida                         aInsertArg.ReplaceExisting = false;
24232f9a8226SOliver Bolte                     else
2424df8a15d8SKohei Yoshida                         aInsertArg.ReplaceExisting = true; // default is overwrite existing files
24252f9a8226SOliver Bolte 
24262f9a8226SOliver Bolte                     Any aCmdArg;
24272f9a8226SOliver Bolte                     aCmdArg <<= aInsertArg;
2428ca5c9591SNoel Grandin                     aTargetContent.executeCommand( u"insert"_ustr,
24292f9a8226SOliver Bolte                                                     aCmdArg );
24302f9a8226SOliver Bolte 
24312f9a8226SOliver Bolte                     if ( xSeek.is() )
24322f9a8226SOliver Bolte                         xSeek->seek( nPos );
24332f9a8226SOliver Bolte 
2434df8a15d8SKohei Yoshida                     return true;
24352f9a8226SOliver Bolte                 }
24366c89e69bSCaolán McNamara                 catch( const uno::Exception& )
24372f9a8226SOliver Bolte                 {}
24382f9a8226SOliver Bolte             }
24392f9a8226SOliver Bolte         }
24402f9a8226SOliver Bolte     }
24412f9a8226SOliver Bolte 
2442df8a15d8SKohei Yoshida     return false;
24432f9a8226SOliver Bolte }
24445be98ebaSJens-Heiner Rechtien 
24450ce0c369SAlexander Wilms 
Transfer_Impl()2446fd069beeSJens-Heiner Rechtien void SfxMedium::Transfer_Impl()
2447fd069beeSJens-Heiner Rechtien {
2448c175c2beSVladimir Glazounov     // The transfer is required only in two cases: either if there is a temporary file or if there is a salvage item
24491946794aSLuboš Luňák     OUString aNameURL;
24505e32815aSXisco Fauli     if ( pImpl->pTempFile )
24515e32815aSXisco Fauli         aNameURL = pImpl->pTempFile->GetURL();
24525e32815aSXisco Fauli     else if ( !pImpl->m_aLogicName.isEmpty() && pImpl->m_bSalvageMode )
2453f343dc80SRüdiger Timm     {
2454da40cac5SAndrea Gelmini         // makes sense only in case logic name is set
24555e32815aSXisco Fauli         if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aNameURL )
2456236714e8SStephan Bergmann              != osl::FileBase::E_None )
2457d38cb53eSMichael Stahl             SAL_WARN( "sfx.doc", "The medium name is not convertible!" );
2458f343dc80SRüdiger Timm     }
2459f343dc80SRüdiger Timm 
2460536a6d6cSNoel Grandin     if ( aNameURL.isEmpty() || ( pImpl->m_eError && !pImpl->m_eError.IsWarning() ) )
2461536a6d6cSNoel Grandin         return;
2462536a6d6cSNoel Grandin 
24636479c881STor Lillqvist     SAL_INFO( "sfx.doc", "SfxMedium::Transfer_Impl, copying to target" );
246497de8bf5SOliver Bolte 
2465913a2d36SNoel Grandin     Reference < css::ucb::XCommandEnvironment > xEnv;
2466aa1c95f4SMikhail Voitenko     Reference< XOutputStream > rOutStream;
2467aa1c95f4SMikhail Voitenko 
2468aa1c95f4SMikhail Voitenko     // in case an output stream is provided from outside and the URL is correct
2469aa1c95f4SMikhail Voitenko     // commit to the stream
24705e32815aSXisco Fauli     if (pImpl->m_aLogicName.startsWith("private:stream"))
2471aa1c95f4SMikhail Voitenko     {
24727b88567cSPascal Junck         // TODO/LATER: support storing to SID_STREAM
2473e4c40331SNoel Grandin         const SfxUnoAnyItem* pOutStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_OUTPUTSTREAM, false);
2474aa1c95f4SMikhail Voitenko         if( pOutStreamItem && ( pOutStreamItem->GetValue() >>= rOutStream ) )
2475aa1c95f4SMikhail Voitenko         {
24765e32815aSXisco Fauli             if ( pImpl->xStorage.is() )
24771d100003SJens-Heiner Rechtien                 CloseStorage();
24781d100003SJens-Heiner Rechtien 
24791d100003SJens-Heiner Rechtien             CloseStreams_Impl();
2480aa1c95f4SMikhail Voitenko 
2481f343dc80SRüdiger Timm             INetURLObject aSource( aNameURL );
24825d88f117SIvo Hinkelmann             ::ucbhelper::Content aTempCont;
2483bfde4866SNoel Grandin             if( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext(), aTempCont ) )
2484aa1c95f4SMikhail Voitenko             {
2485aa1c95f4SMikhail Voitenko                 try
2486aa1c95f4SMikhail Voitenko                 {
2487aa1c95f4SMikhail Voitenko                     sal_Int32 nRead;
2488aa1c95f4SMikhail Voitenko                     sal_Int32 nBufferSize = 32767;
2489aa1c95f4SMikhail Voitenko                     Sequence < sal_Int8 > aSequence ( nBufferSize );
2490aa1c95f4SMikhail Voitenko                     Reference< XInputStream > aTempInput = aTempCont.openStream();
2491aa1c95f4SMikhail Voitenko 
2492aa1c95f4SMikhail Voitenko                     do
2493aa1c95f4SMikhail Voitenko                     {
2494aa1c95f4SMikhail Voitenko                         nRead = aTempInput->readBytes ( aSequence, nBufferSize );
2495aa1c95f4SMikhail Voitenko                         if ( nRead < nBufferSize )
2496aa1c95f4SMikhail Voitenko                         {
2497aa1c95f4SMikhail Voitenko                             Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead );
2498aa1c95f4SMikhail Voitenko                             rOutStream->writeBytes ( aTempBuf );
2499aa1c95f4SMikhail Voitenko                         }
2500aa1c95f4SMikhail Voitenko                         else
2501aa1c95f4SMikhail Voitenko                             rOutStream->writeBytes ( aSequence );
2502aa1c95f4SMikhail Voitenko                     }
2503aa1c95f4SMikhail Voitenko                     while ( nRead == nBufferSize );
2504aa1c95f4SMikhail Voitenko 
2505aa1c95f4SMikhail Voitenko                     // remove temporary file
25065e32815aSXisco Fauli                     if ( pImpl->pTempFile )
2507f343dc80SRüdiger Timm                     {
25085e32815aSXisco Fauli                         pImpl->pTempFile->EnableKillingFile();
2509e4c40331SNoel Grandin                         pImpl->pTempFile.reset();
2510aa1c95f4SMikhail Voitenko                     }
2511f343dc80SRüdiger Timm                 }
25126c89e69bSCaolán McNamara                 catch( const Exception& )
2513aa1c95f4SMikhail Voitenko                 {}
2514aa1c95f4SMikhail Voitenko             }
2515aa1c95f4SMikhail Voitenko         }
2516aa1c95f4SMikhail Voitenko         else
2517aa1c95f4SMikhail Voitenko         {
2518d38cb53eSMichael Stahl             SAL_WARN( "sfx.doc", "Illegal Output stream parameter!" );
25199e4d84daSCaolán McNamara             SetError(ERRCODE_IO_GENERAL);
2520aa1c95f4SMikhail Voitenko         }
2521aa1c95f4SMikhail Voitenko 
2522aa1c95f4SMikhail Voitenko         // free the reference
25235e32815aSXisco Fauli         if ( pImpl->m_pSet )
25245e32815aSXisco Fauli             pImpl->m_pSet->ClearItem( SID_OUTPUTSTREAM );
2525aa1c95f4SMikhail Voitenko 
2526aa1c95f4SMikhail Voitenko         return;
2527aa1c95f4SMikhail Voitenko     }
2528aa1c95f4SMikhail Voitenko 
2529a73d45b8SMathias Bauer     GetContent();
25305e32815aSXisco Fauli     if ( !pImpl->aContent.get().is() )
2531503660faSMathias Bauer     {
25325e32815aSXisco Fauli         pImpl->m_eError = ERRCODE_IO_NOTEXISTS;
2533fd069beeSJens-Heiner Rechtien         return;
2534503660faSMathias Bauer     }
2535fd069beeSJens-Heiner Rechtien 
2536a73d45b8SMathias Bauer     INetURLObject aDest( GetURLObject() );
2537565070aaSMikhail Voitenko 
2538565070aaSMikhail Voitenko     // source is the temp file written so far
2539f343dc80SRüdiger Timm     INetURLObject aSource( aNameURL );
2540565070aaSMikhail Voitenko 
2541b22e3121SMikhail Voitenko     // a special case, an interaction handler should be used for
2542b22e3121SMikhail Voitenko     // authentication in case it is available
2543913a2d36SNoel Grandin     Reference< css::ucb::XCommandEnvironment > xComEnv;
254420132d64SJaume Pujantell     bool bForceInteractionHandler = GetURLObject().isAnyKnownWebDAVScheme();
254520132d64SJaume Pujantell     Reference< css::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler(bForceInteractionHandler);
25465be98ebaSJens-Heiner Rechtien     if (xInteractionHandler.is())
25475d88f117SIvo Hinkelmann         xComEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler,
2548913a2d36SNoel Grandin                                                   Reference< css::ucb::XProgressHandler >() );
254994e6cfc4SMikhail Voitenko 
2550bfde4866SNoel Grandin     OUString aDestURL( aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
2551966d20e3SCédric Bosdonnat 
25525da0dce1SStephan Bergmann     if ( comphelper::isFileUrl( aDestURL ) || !aDest.removeSegment() )
2553565070aaSMikhail Voitenko     {
25545be98ebaSJens-Heiner Rechtien         TransactedTransferForFS_Impl( aSource, aDest, xComEnv );
2555a0b5ba2eSMichael Meeks 
2556d03a7547SMiklos Vajna         if (!pImpl->m_bDisableFileSync)
2557d03a7547SMiklos Vajna         {
2558a0b5ba2eSMichael Meeks             // Hideous - no clean way to do this, so we re-open the file just to fsync it
2559a0b5ba2eSMichael Meeks             osl::File aFile( aDestURL );
2560a0b5ba2eSMichael Meeks             if ( aFile.open( osl_File_OpenFlag_Write ) == osl::FileBase::E_None )
2561a0b5ba2eSMichael Meeks             {
2562a0b5ba2eSMichael Meeks                 aFile.sync();
2563d38cb53eSMichael Stahl                 SAL_INFO( "sfx.doc", "fsync'd saved file '" << aDestURL << "'" );
2564a0b5ba2eSMichael Meeks                 aFile.close();
2565a0b5ba2eSMichael Meeks             }
2566565070aaSMikhail Voitenko         }
2567d03a7547SMiklos Vajna     }
2568c175c2beSVladimir Glazounov     else
2569fd069beeSJens-Heiner Rechtien     {
2570a73d45b8SMathias Bauer         // create content for the parent folder and call transfer on that content with the source content
2571a73d45b8SMathias Bauer         // and the destination file name as parameters
25725d88f117SIvo Hinkelmann         ::ucbhelper::Content aSourceContent;
25735d88f117SIvo Hinkelmann         ::ucbhelper::Content aTransferContent;
2574fd069beeSJens-Heiner Rechtien 
2575966d20e3SCédric Bosdonnat         ::ucbhelper::Content aDestContent;
2576119f0da5SCaolán McNamara         (void)::ucbhelper::Content::create( aDestURL, xComEnv, comphelper::getProcessComponentContext(), aDestContent );
25773f5c45b7SStephan Bergmann         // For checkin, we need the object URL, not the parent folder:
25781a926112SCédric Bosdonnat         if ( !IsInCheckIn( ) )
25791a926112SCédric Bosdonnat         {
25801a926112SCédric Bosdonnat             // Get the parent URL from the XChild if possible: why would the URL necessarily have
25811a926112SCédric Bosdonnat             // a hierarchical path? It's not always the case for CMIS.
2582913a2d36SNoel Grandin             Reference< css::container::XChild> xChild( aDestContent.get(), uno::UNO_QUERY );
25831946794aSLuboš Luňák             OUString sParentUrl;
2584966d20e3SCédric Bosdonnat             if ( xChild.is( ) )
2585966d20e3SCédric Bosdonnat             {
2586913a2d36SNoel Grandin                 Reference< css::ucb::XContent > xParent( xChild->getParent( ), uno::UNO_QUERY );
2587966d20e3SCédric Bosdonnat                 if ( xParent.is( ) )
2588966d20e3SCédric Bosdonnat                 {
2589966d20e3SCédric Bosdonnat                     sParentUrl = xParent->getIdentifier( )->getContentIdentifier();
2590966d20e3SCédric Bosdonnat                 }
2591966d20e3SCédric Bosdonnat             }
2592966d20e3SCédric Bosdonnat 
25933f5c45b7SStephan Bergmann             if ( sParentUrl.isEmpty() )
2594bfde4866SNoel Grandin                 aDestURL = aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE );
25953f5c45b7SStephan Bergmann                     // adjust to above aDest.removeSegment()
25961a926112SCédric Bosdonnat             else
25973f5c45b7SStephan Bergmann                 aDestURL = sParentUrl;
25981a926112SCédric Bosdonnat         }
2599966d20e3SCédric Bosdonnat 
2600966d20e3SCédric Bosdonnat         // LongName wasn't defined anywhere, only used here... get the Title instead
2601966d20e3SCédric Bosdonnat         // as it's less probably empty
26021946794aSLuboš Luňák         OUString aFileName;
26036fc8a486SMichael Stahl         OUString sObjectId;
26046fc8a486SMichael Stahl         try
26056fc8a486SMichael Stahl         {
2606ca5c9591SNoel Grandin             Any aAny = aDestContent.getPropertyValue(u"Title"_ustr);
2607966d20e3SCédric Bosdonnat             aAny >>= aFileName;
2608ca5c9591SNoel Grandin             aAny = aDestContent.getPropertyValue(u"ObjectId"_ustr);
2609ff8b445dSCao Cuong Ngo             aAny >>= sObjectId;
26106fc8a486SMichael Stahl         }
26116fc8a486SMichael Stahl         catch (uno::Exception const&)
26126fc8a486SMichael Stahl         {
26136fc8a486SMichael Stahl             SAL_INFO("sfx.doc", "exception while getting Title or ObjectId");
26146fc8a486SMichael Stahl         }
2615966d20e3SCédric Bosdonnat         if ( aFileName.isEmpty() )
2616bfde4866SNoel Grandin             aFileName = GetURLObject().getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
2617a73d45b8SMathias Bauer 
261821ac0defSSander Vesik         try
261921ac0defSSander Vesik         {
26203f5c45b7SStephan Bergmann             aTransferContent = ::ucbhelper::Content( aDestURL, xComEnv, comphelper::getProcessComponentContext() );
262121ac0defSSander Vesik         }
2622913a2d36SNoel Grandin         catch (const css::ucb::ContentCreationException& ex)
262321ac0defSSander Vesik         {
26245e32815aSXisco Fauli             pImpl->m_eError = ERRCODE_IO_GENERAL;
262521ac0defSSander Vesik             if (
2626913a2d36SNoel Grandin                 (ex.eError == css::ucb::ContentCreationError_NO_CONTENT_PROVIDER    ) ||
2627913a2d36SNoel Grandin                 (ex.eError == css::ucb::ContentCreationError_CONTENT_CREATION_FAILED)
262821ac0defSSander Vesik                )
262921ac0defSSander Vesik             {
26305e32815aSXisco Fauli                 pImpl->m_eError = ERRCODE_IO_NOTEXISTSPATH;
263121ac0defSSander Vesik             }
263221ac0defSSander Vesik         }
2633913a2d36SNoel Grandin         catch (const css::uno::Exception&)
263421ac0defSSander Vesik         {
26355e32815aSXisco Fauli             pImpl->m_eError = ERRCODE_IO_GENERAL;
263621ac0defSSander Vesik         }
263721ac0defSSander Vesik 
263852863266SNoel Grandin         if ( !pImpl->m_eError || pImpl->m_eError.IsWarning() )
2639a73d45b8SMathias Bauer         {
264044c8bcecSMathias Bauer             // free resources, otherwise the transfer may fail
26415e32815aSXisco Fauli             if ( pImpl->xStorage.is() )
26421d100003SJens-Heiner Rechtien                 CloseStorage();
26431d100003SJens-Heiner Rechtien 
26441d100003SJens-Heiner Rechtien             CloseStreams_Impl();
26451d100003SJens-Heiner Rechtien 
2646bfde4866SNoel Grandin             (void)::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext(), aSourceContent );
264725cd714cSMathias Bauer 
2648a73d45b8SMathias Bauer             // check for external parameters that may customize the handling of NameClash situations
2649f5dd4faeSMike Kaganski             const SfxBoolItem* pOverWrite = GetItemSet().GetItem<SfxBoolItem>(SID_OVERWRITE, false);
2650a73d45b8SMathias Bauer             sal_Int32 nNameClash;
2651fd069beeSJens-Heiner Rechtien             if ( pOverWrite && !pOverWrite->GetValue() )
2652a73d45b8SMathias Bauer                 // argument says: never overwrite
2653a73d45b8SMathias Bauer                 nNameClash = NameClash::ERROR;
2654fd069beeSJens-Heiner Rechtien             else
2655a73d45b8SMathias Bauer                 // default is overwrite existing files
2656a73d45b8SMathias Bauer                 nNameClash = NameClash::OVERWRITE;
2657a73d45b8SMathias Bauer 
2658a73d45b8SMathias Bauer             try
2659fd069beeSJens-Heiner Rechtien             {
26605e32815aSXisco Fauli                 OUString aMimeType = pImpl->getFilterMimeType();
2661d198a822SNoel Grandin                 ::ucbhelper::InsertOperation eOperation = ::ucbhelper::InsertOperation::Copy;
26621a926112SCédric Bosdonnat                 bool bMajor = false;
26631946794aSLuboš Luňák                 OUString sComment;
26641a926112SCédric Bosdonnat                 if ( IsInCheckIn( ) )
26651a926112SCédric Bosdonnat                 {
2666d198a822SNoel Grandin                     eOperation = ::ucbhelper::InsertOperation::Checkin;
2667f5dd4faeSMike Kaganski                     const SfxBoolItem* pMajor = GetItemSet().GetItem<SfxBoolItem>(SID_DOCINFO_MAJOR, false);
26681a926112SCédric Bosdonnat                     bMajor = pMajor && pMajor->GetValue( );
2669f5dd4faeSMike Kaganski                     const SfxStringItem* pComments = GetItemSet().GetItem(SID_DOCINFO_COMMENTS, false);
26701a926112SCédric Bosdonnat                     if ( pComments )
26711a926112SCédric Bosdonnat                         sComment = pComments->GetValue( );
26721a926112SCédric Bosdonnat                 }
26731946794aSLuboš Luňák                 OUString sResultURL;
267453491f8aSNoel Grandin                 aTransferContent.transferContent(
26754c82edfbSGiuseppe Castagno                     aSourceContent, eOperation,
26764c82edfbSGiuseppe Castagno                     aFileName, nNameClash, aMimeType, bMajor, sComment,
26774c82edfbSGiuseppe Castagno                     &sResultURL, sObjectId );
26784c82edfbSGiuseppe Castagno 
267953491f8aSNoel Grandin                 if ( !sResultURL.isEmpty( ) )  // Likely to happen only for checkin
26801a926112SCédric Bosdonnat                     SwitchDocumentToFile( sResultURL );
26814c82edfbSGiuseppe Castagno                 try
26824c82edfbSGiuseppe Castagno                 {
26834c82edfbSGiuseppe Castagno                     if ( GetURLObject().isAnyKnownWebDAVScheme() &&
2684d198a822SNoel Grandin                          eOperation == ::ucbhelper::InsertOperation::Copy )
26854c82edfbSGiuseppe Castagno                     {
26864c82edfbSGiuseppe Castagno                         // tdf#95272 try to re-issue a lock command when a new file is created.
26874c82edfbSGiuseppe Castagno                         // This may be needed because some WebDAV servers fail to implement the
26884c82edfbSGiuseppe Castagno                         // 'LOCK on unallocated reference', see issue comment:
26894c82edfbSGiuseppe Castagno                         // <https://bugs.documentfoundation.org/show_bug.cgi?id=95792#c8>
26904c82edfbSGiuseppe Castagno                         // and specification at:
26914c82edfbSGiuseppe Castagno                         // <http://tools.ietf.org/html/rfc4918#section-7.3>
26924c82edfbSGiuseppe Castagno                         // If the WebDAV resource is already locked by this LO instance, nothing will
26934c82edfbSGiuseppe Castagno                         // happen, e.g. the LOCK method will not be sent to the server.
269445839115SNoel Grandin                         ::ucbhelper::Content aLockContent( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), xComEnv, comphelper::getProcessComponentContext() );
26954c82edfbSGiuseppe Castagno                         aLockContent.lock();
26964c82edfbSGiuseppe Castagno                     }
26974c82edfbSGiuseppe Castagno                 }
26985aa942f3SNoel Grandin                 catch ( css::uno::Exception & )
26994c82edfbSGiuseppe Castagno                 {
27005aa942f3SNoel Grandin                     TOOLS_WARN_EXCEPTION( "sfx.doc", "LOCK not working while re-issuing it" );
27014c82edfbSGiuseppe Castagno                 }
2702a73d45b8SMathias Bauer             }
2703913a2d36SNoel Grandin             catch ( const css::ucb::CommandAbortedException& )
2704a73d45b8SMathias Bauer             {
27055e32815aSXisco Fauli                 pImpl->m_eError = ERRCODE_ABORT;
2706a73d45b8SMathias Bauer             }
2707913a2d36SNoel Grandin             catch ( const css::ucb::CommandFailedException& )
2708a73d45b8SMathias Bauer             {
27095e32815aSXisco Fauli                 pImpl->m_eError = ERRCODE_ABORT;
2710a73d45b8SMathias Bauer             }
2711913a2d36SNoel Grandin             catch ( const css::ucb::InteractiveIOException& r )
2712a73d45b8SMathias Bauer             {
2713a73d45b8SMathias Bauer                 if ( r.Code == IOErrorCode_ACCESS_DENIED )
27145e32815aSXisco Fauli                     pImpl->m_eError = ERRCODE_IO_ACCESSDENIED;
2715a73d45b8SMathias Bauer                 else if ( r.Code == IOErrorCode_NOT_EXISTING )
27165e32815aSXisco Fauli                     pImpl->m_eError = ERRCODE_IO_NOTEXISTS;
2717a73d45b8SMathias Bauer                 else if ( r.Code == IOErrorCode_CANT_READ )
27185e32815aSXisco Fauli                     pImpl->m_eError = ERRCODE_IO_CANTREAD;
2719a73d45b8SMathias Bauer                 else
27205e32815aSXisco Fauli                     pImpl->m_eError = ERRCODE_IO_GENERAL;
2721a73d45b8SMathias Bauer             }
2722913a2d36SNoel Grandin             catch ( const css::uno::Exception& )
2723a73d45b8SMathias Bauer             {
27245e32815aSXisco Fauli                 pImpl->m_eError = ERRCODE_IO_GENERAL;
2725fd069beeSJens-Heiner Rechtien             }
2726fd069beeSJens-Heiner Rechtien 
2727298fc104SMikhail Voitenko             // do not switch from temporary file in case of nonfile protocol
2728fd069beeSJens-Heiner Rechtien         }
272944c8bcecSMathias Bauer     }
2730c175c2beSVladimir Glazounov 
273152863266SNoel Grandin     if ( ( !pImpl->m_eError || pImpl->m_eError.IsWarning() ) && !pImpl->pTempFile )
2732c175c2beSVladimir Glazounov     {
2733c175c2beSVladimir Glazounov         // without a TempFile the physical and logical name should be the same after successful transfer
2734236714e8SStephan Bergmann         if (osl::FileBase::getSystemPathFromFileURL(
2735bfde4866SNoel Grandin               GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), pImpl->m_aName )
2736236714e8SStephan Bergmann             != osl::FileBase::E_None)
2737236714e8SStephan Bergmann         {
27385e32815aSXisco Fauli             pImpl->m_aName.clear();
2739236714e8SStephan Bergmann         }
27405e32815aSXisco Fauli         pImpl->m_bSalvageMode = false;
2741c175c2beSVladimir Glazounov     }
2742fd069beeSJens-Heiner Rechtien }
2743fd069beeSJens-Heiner Rechtien 
27440ce0c369SAlexander Wilms 
DoInternalBackup_Impl(const::ucbhelper::Content & aOriginalContent,std::u16string_view aPrefix,std::u16string_view aExtension,const OUString & aDestDir)27455d88f117SIvo Hinkelmann void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent,
27461927b519SNoel Grandin                                        std::u16string_view aPrefix,
2747898ba5beSNoel Grandin                                        std::u16string_view aExtension,
27486a080679SNorbert Thiebaud                                        const OUString& aDestDir )
27495be98ebaSJens-Heiner Rechtien {
27505e32815aSXisco Fauli     if ( !pImpl->m_aBackupURL.isEmpty() )
27514f03108dSVladimir Glazounov         return; // the backup was done already
27525be98ebaSJens-Heiner Rechtien 
27534b95451fSNoel Grandin     ::utl::TempFileNamed aTransactTemp( aPrefix, true, aExtension, &aDestDir );
27545be98ebaSJens-Heiner Rechtien 
27555be98ebaSJens-Heiner Rechtien     INetURLObject aBackObj( aTransactTemp.GetURL() );
2756bfde4866SNoel Grandin     OUString aBackupName = aBackObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
27575be98ebaSJens-Heiner Rechtien 
2758913a2d36SNoel Grandin     Reference < css::ucb::XCommandEnvironment > xDummyEnv;
27595d88f117SIvo Hinkelmann     ::ucbhelper::Content aBackupCont;
27609ac86f48SStephan Bergmann     if( ::ucbhelper::Content::create( aDestDir, xDummyEnv, comphelper::getProcessComponentContext(), aBackupCont ) )
27615be98ebaSJens-Heiner Rechtien     {
27625be98ebaSJens-Heiner Rechtien         try
27635be98ebaSJens-Heiner Rechtien         {
27645e32815aSXisco Fauli             OUString sMimeType = pImpl->getFilterMimeType();
276553491f8aSNoel Grandin             aBackupCont.transferContent( aOriginalContent,
2766d198a822SNoel Grandin                                             ::ucbhelper::InsertOperation::Copy,
27675be98ebaSJens-Heiner Rechtien                                             aBackupName,
276875bc673bSCédric Bosdonnat                                             NameClash::OVERWRITE,
276953491f8aSNoel Grandin                                             sMimeType );
2770bfde4866SNoel Grandin             pImpl->m_aBackupURL = aBackObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
27715e32815aSXisco Fauli             pImpl->m_bRemoveBackup = true;
27725be98ebaSJens-Heiner Rechtien         }
27736c89e69bSCaolán McNamara         catch( const Exception& )
27745be98ebaSJens-Heiner Rechtien         {}
27755be98ebaSJens-Heiner Rechtien     }
27764f03108dSVladimir Glazounov 
27775e32815aSXisco Fauli     if ( pImpl->m_aBackupURL.isEmpty() )
27783385b0daSStephan Bergmann         aTransactTemp.EnableKillingFile();
27794f03108dSVladimir Glazounov }
27804f03108dSVladimir Glazounov 
27810ce0c369SAlexander Wilms 
DoInternalBackup_Impl(const::ucbhelper::Content & aOriginalContent)27825d88f117SIvo Hinkelmann void SfxMedium::DoInternalBackup_Impl( const ::ucbhelper::Content& aOriginalContent )
27834f03108dSVladimir Glazounov {
27845e32815aSXisco Fauli     if ( !pImpl->m_aBackupURL.isEmpty() )
27854f03108dSVladimir Glazounov         return; // the backup was done already
27864f03108dSVladimir Glazounov 
27871946794aSLuboš Luňák     OUString aFileName =  GetURLObject().getName( INetURLObject::LAST_SEGMENT,
27884f03108dSVladimir Glazounov                                                         true,
2789bfde4866SNoel Grandin                                                         INetURLObject::DecodeMechanism::NONE );
27904f03108dSVladimir Glazounov 
27914f03108dSVladimir Glazounov     sal_Int32 nPrefixLen = aFileName.lastIndexOf( '.' );
27926a080679SNorbert Thiebaud     OUString aPrefix = ( nPrefixLen == -1 ) ? aFileName : aFileName.copy( 0, nPrefixLen );
27936a080679SNorbert Thiebaud     OUString aExtension = ( nPrefixLen == -1 ) ? OUString() : aFileName.copy( nPrefixLen );
27946a080679SNorbert Thiebaud     OUString aBakDir = SvtPathOptions().GetBackupPath();
27954f03108dSVladimir Glazounov 
2796ecdd9d1aSCaolán McNamara     // create content for the parent folder ( = backup folder )
2797ecdd9d1aSCaolán McNamara     ::ucbhelper::Content  aContent;
2798913a2d36SNoel Grandin     Reference < css::ucb::XCommandEnvironment > xEnv;
279968dea1c1SCaolán McNamara     if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
28004f03108dSVladimir Glazounov         DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aBakDir );
28014f03108dSVladimir Glazounov 
2802536a6d6cSNoel Grandin     if ( !pImpl->m_aBackupURL.isEmpty() )
2803536a6d6cSNoel Grandin         return;
2804536a6d6cSNoel Grandin 
28054a9ac82cSAndrea Gelmini     // the copying to the backup catalog failed ( for example because
28064f03108dSVladimir Glazounov     // of using an encrypted partition as target catalog )
28074f03108dSVladimir Glazounov     // since the user did not specify to make backup explicitly
28084f03108dSVladimir Glazounov     // office should try to make backup in another place,
28094f03108dSVladimir Glazounov     // target catalog does not look bad for this case ( and looks
28104f03108dSVladimir Glazounov     // to be the only way for encrypted partitions )
28114f03108dSVladimir Glazounov 
28124f03108dSVladimir Glazounov     INetURLObject aDest = GetURLObject();
28134f03108dSVladimir Glazounov     if ( aDest.removeSegment() )
2814bfde4866SNoel Grandin         DoInternalBackup_Impl( aOriginalContent, aPrefix, aExtension, aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
28154f03108dSVladimir Glazounov }
28165be98ebaSJens-Heiner Rechtien 
28175be98ebaSJens-Heiner Rechtien 
DoBackup_Impl(bool bForceUsingBackupPath)281809d3e887SJustin Luth void SfxMedium::DoBackup_Impl(bool bForceUsingBackupPath)
2819fd069beeSJens-Heiner Rechtien {
28205be98ebaSJens-Heiner Rechtien     // source file name is the logical name of this medium
28215be98ebaSJens-Heiner Rechtien     INetURLObject aSource( GetURLObject() );
28225be98ebaSJens-Heiner Rechtien 
28235be98ebaSJens-Heiner Rechtien     // there is nothing to backup in case source file does not exist
2824bfde4866SNoel Grandin     if ( !::utl::UCBContentHelper::IsDocument( aSource.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
28255be98ebaSJens-Heiner Rechtien         return;
28265be98ebaSJens-Heiner Rechtien 
282750b4cbe9SKohei Yoshida     bool        bSuccess = false;
282809d3e887SJustin Luth     bool bOnErrorRetryUsingBackupPath = false;
2829fd069beeSJens-Heiner Rechtien 
2830a73d45b8SMathias Bauer     // get path for backups
283109d3e887SJustin Luth     OUString aBakDir;
283209d3e887SJustin Luth     if (!bForceUsingBackupPath
283309d3e887SJustin Luth         && officecfg::Office::Common::Save::Document::BackupIntoDocumentFolder::get())
283409d3e887SJustin Luth     {
283509d3e887SJustin Luth         aBakDir = aSource.GetPartBeforeLastName();
283609d3e887SJustin Luth         bOnErrorRetryUsingBackupPath = true;
283709d3e887SJustin Luth     }
283809d3e887SJustin Luth     else
283909d3e887SJustin Luth         aBakDir = SvtPathOptions().GetBackupPath();
2840f9e78cd4SNoel Grandin     if( !aBakDir.isEmpty() )
2841fd069beeSJens-Heiner Rechtien     {
2842a73d45b8SMathias Bauer         // create content for the parent folder ( = backup folder )
28435d88f117SIvo Hinkelmann         ::ucbhelper::Content  aContent;
2844913a2d36SNoel Grandin         Reference < css::ucb::XCommandEnvironment > xEnv;
284568dea1c1SCaolán McNamara         if( ::utl::UCBContentHelper::ensureFolder(comphelper::getProcessComponentContext(), xEnv, aBakDir, aContent) )
28465be98ebaSJens-Heiner Rechtien         {
2847a73d45b8SMathias Bauer             // save as ".bak" file
2848a73d45b8SMathias Bauer             INetURLObject aDest( aBakDir );
2849fd069beeSJens-Heiner Rechtien             aDest.insertName( aSource.getName() );
2850b6f31295SJustin Luth             const OUString sExt
2851ca5c9591SNoel Grandin                 = aSource.hasExtension() ? aSource.getExtension() + ".bak" : u"bak"_ustr;
2852b6f31295SJustin Luth             aDest.setExtension(sExt);
2853bfde4866SNoel Grandin             OUString aFileName = aDest.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
2854fd069beeSJens-Heiner Rechtien 
2855a73d45b8SMathias Bauer             // create a content for the source file
28565d88f117SIvo Hinkelmann             ::ucbhelper::Content aSourceContent;
2857bfde4866SNoel Grandin             if ( ::ucbhelper::Content::create( aSource.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xEnv, comphelper::getProcessComponentContext(), aSourceContent ) )
2858fd069beeSJens-Heiner Rechtien             {
2859a73d45b8SMathias Bauer                 try
2860fd069beeSJens-Heiner Rechtien                 {
2861a73d45b8SMathias Bauer                     // do the transfer ( copy source file to backup dir )
28625e32815aSXisco Fauli                     OUString sMimeType = pImpl->getFilterMimeType();
286353491f8aSNoel Grandin                     aContent.transferContent( aSourceContent,
2864d198a822SNoel Grandin                                                         ::ucbhelper::InsertOperation::Copy,
28655be98ebaSJens-Heiner Rechtien                                                         aFileName,
286675bc673bSCédric Bosdonnat                                                         NameClash::OVERWRITE,
286775bc673bSCédric Bosdonnat                                                         sMimeType );
2868bfde4866SNoel Grandin                     pImpl->m_aBackupURL = aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE );
28695e32815aSXisco Fauli                     pImpl->m_bRemoveBackup = false;
287053491f8aSNoel Grandin                     bSuccess = true;
2871fd069beeSJens-Heiner Rechtien                 }
2872913a2d36SNoel Grandin                 catch ( const css::uno::Exception& )
2873fd069beeSJens-Heiner Rechtien                 {
2874fd069beeSJens-Heiner Rechtien                 }
2875fd069beeSJens-Heiner Rechtien             }
2876fd069beeSJens-Heiner Rechtien         }
28775be98ebaSJens-Heiner Rechtien     }
2878fd069beeSJens-Heiner Rechtien 
2879fd069beeSJens-Heiner Rechtien     if ( !bSuccess )
28805be98ebaSJens-Heiner Rechtien     {
288109d3e887SJustin Luth         // in case a webdav server prevents file creation, or a partition is full, or whatever...
288209d3e887SJustin Luth         if (bOnErrorRetryUsingBackupPath)
288309d3e887SJustin Luth             return DoBackup_Impl(/*bForceUsingBackupPath=*/true);
288409d3e887SJustin Luth 
28855e32815aSXisco Fauli         pImpl->m_eError = ERRCODE_SFX_CANTCREATEBACKUP;
2886fd069beeSJens-Heiner Rechtien     }
28875be98ebaSJens-Heiner Rechtien }
28885be98ebaSJens-Heiner Rechtien 
28890ce0c369SAlexander Wilms 
ClearBackup_Impl()28905be98ebaSJens-Heiner Rechtien void SfxMedium::ClearBackup_Impl()
28915be98ebaSJens-Heiner Rechtien {
28925e32815aSXisco Fauli     if( pImpl->m_bRemoveBackup )
28935be98ebaSJens-Heiner Rechtien     {
2894135171a9SRüdiger Timm         // currently a document is always stored in a new medium,
2895135171a9SRüdiger Timm         // thus if a backup can not be removed the backup URL should not be cleaned
28965e32815aSXisco Fauli         if ( !pImpl->m_aBackupURL.isEmpty() )
2897135171a9SRüdiger Timm         {
28985e32815aSXisco Fauli             if ( ::utl::UCBContentHelper::Kill( pImpl->m_aBackupURL ) )
2899135171a9SRüdiger Timm             {
29005e32815aSXisco Fauli                 pImpl->m_bRemoveBackup = false;
29015e32815aSXisco Fauli                 pImpl->m_aBackupURL.clear();
29025be98ebaSJens-Heiner Rechtien             }
2903135171a9SRüdiger Timm             else
2904135171a9SRüdiger Timm             {
29055be98ebaSJens-Heiner Rechtien 
2906d38cb53eSMichael Stahl                 SAL_WARN( "sfx.doc", "Couldn't remove backup file!");
2907135171a9SRüdiger Timm             }
2908135171a9SRüdiger Timm         }
2909135171a9SRüdiger Timm     }
2910135171a9SRüdiger Timm     else
29115e32815aSXisco Fauli         pImpl->m_aBackupURL.clear();
29125be98ebaSJens-Heiner Rechtien }
2913fd069beeSJens-Heiner Rechtien 
29140ce0c369SAlexander Wilms 
GetLockingStream_Impl()291589fd6a8fSMikhail Voitenko void SfxMedium::GetLockingStream_Impl()
291689fd6a8fSMikhail Voitenko {
2917536a6d6cSNoel Grandin     if ( GetURLObject().GetProtocol() != INetProtocol::File
2918536a6d6cSNoel Grandin          || pImpl->m_xLockingStream.is() )
2919536a6d6cSNoel Grandin         return;
2920536a6d6cSNoel Grandin 
2921e4c40331SNoel Grandin     const SfxUnoAnyItem* pWriteStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_STREAM, false);
292289fd6a8fSMikhail Voitenko     if ( pWriteStreamItem )
29235e32815aSXisco Fauli         pWriteStreamItem->GetValue() >>= pImpl->m_xLockingStream;
292489fd6a8fSMikhail Voitenko 
2925536a6d6cSNoel Grandin     if ( pImpl->m_xLockingStream.is() )
2926536a6d6cSNoel Grandin         return;
2927536a6d6cSNoel Grandin 
292889fd6a8fSMikhail Voitenko     // open the original document
292989fd6a8fSMikhail Voitenko     uno::Sequence< beans::PropertyValue > xProps;
2930f5dd4faeSMike Kaganski     TransformItems( SID_OPENDOC, GetItemSet(), xProps );
293124cad6a6SStephan Bergmann     utl::MediaDescriptor aMedium( xProps );
293289fd6a8fSMikhail Voitenko 
293389fd6a8fSMikhail Voitenko     aMedium.addInputStreamOwnLock();
293489fd6a8fSMikhail Voitenko 
293589fd6a8fSMikhail Voitenko     uno::Reference< io::XInputStream > xInputStream;
29362ab40e9eSNoel Grandin     aMedium[utl::MediaDescriptor::PROP_STREAM] >>= pImpl->m_xLockingStream;
29372ab40e9eSNoel Grandin     aMedium[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream;
293889fd6a8fSMikhail Voitenko 
29395e32815aSXisco Fauli     if ( !pImpl->pTempFile && pImpl->m_aName.isEmpty() )
294089fd6a8fSMikhail Voitenko     {
2941da40cac5SAndrea Gelmini         // the medium is still based on the original file, it makes sense to initialize the streams
29425e32815aSXisco Fauli         if ( pImpl->m_xLockingStream.is() )
29435e32815aSXisco Fauli             pImpl->xStream = pImpl->m_xLockingStream;
294489fd6a8fSMikhail Voitenko 
294589fd6a8fSMikhail Voitenko         if ( xInputStream.is() )
29466f1508f4SCaolán McNamara             pImpl->xInputStream = std::move(xInputStream);
294789fd6a8fSMikhail Voitenko 
29485e32815aSXisco Fauli         if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
29495e32815aSXisco Fauli             pImpl->xInputStream = pImpl->xStream->getInputStream();
295089fd6a8fSMikhail Voitenko     }
295189fd6a8fSMikhail Voitenko }
295289fd6a8fSMikhail Voitenko 
29530ce0c369SAlexander Wilms 
GetMedium_Impl()2954fd069beeSJens-Heiner Rechtien void SfxMedium::GetMedium_Impl()
2955fd069beeSJens-Heiner Rechtien {
2956536a6d6cSNoel Grandin     if ( pImpl->m_pInStream
2957536a6d6cSNoel Grandin         && (!pImpl->bIsTemp || pImpl->xInputStream.is() || pImpl->m_xInputStreamToLoadFrom.is() || pImpl->xStream.is() || pImpl->m_xLockingStream.is() ) )
2958536a6d6cSNoel Grandin         return;
2959536a6d6cSNoel Grandin 
29605e32815aSXisco Fauli     pImpl->bDownloadDone = false;
2961913a2d36SNoel Grandin     Reference< css::task::XInteractionHandler > xInteractionHandler = GetInteractionHandler();
2962fc3a7d9cSMathias Bauer 
2963762dd2b1SKurt Zenker     //TODO/MBA: need support for SID_STREAM
2964e4c40331SNoel Grandin     const SfxUnoAnyItem* pWriteStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_STREAM, false);
2965e4c40331SNoel Grandin     const SfxUnoAnyItem* pInStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_INPUTSTREAM, false);
2966762dd2b1SKurt Zenker     if ( pWriteStreamItem )
2967fd069beeSJens-Heiner Rechtien     {
29685e32815aSXisco Fauli         pWriteStreamItem->GetValue() >>= pImpl->xStream;
2969762dd2b1SKurt Zenker 
2970762dd2b1SKurt Zenker         if ( pInStreamItem )
29715e32815aSXisco Fauli             pInStreamItem->GetValue() >>= pImpl->xInputStream;
2972762dd2b1SKurt Zenker 
29735e32815aSXisco Fauli         if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
29745e32815aSXisco Fauli             pImpl->xInputStream = pImpl->xStream->getInputStream();
2975762dd2b1SKurt Zenker     }
2976762dd2b1SKurt Zenker     else if ( pInStreamItem )
2977762dd2b1SKurt Zenker     {
29785e32815aSXisco Fauli         pInStreamItem->GetValue() >>= pImpl->xInputStream;
2979fd069beeSJens-Heiner Rechtien     }
2980fd069beeSJens-Heiner Rechtien     else
2981fd069beeSJens-Heiner Rechtien     {
2982762dd2b1SKurt Zenker         uno::Sequence < beans::PropertyValue > xProps;
29831946794aSLuboš Luňák         OUString aFileName;
29845e32815aSXisco Fauli         if (!pImpl->m_aName.isEmpty())
29857165de29SMathias Bauer         {
29865e32815aSXisco Fauli             if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aFileName )
2987236714e8SStephan Bergmann                  != osl::FileBase::E_None )
298885cd316fSOliver Bolte             {
2989d38cb53eSMichael Stahl                 SAL_WARN( "sfx.doc", "Physical name not convertible!");
29907165de29SMathias Bauer             }
299185cd316fSOliver Bolte         }
29927165de29SMathias Bauer         else
2993762dd2b1SKurt Zenker             aFileName = GetName();
2994762dd2b1SKurt Zenker 
2995fe23d400SKurt Zenker         // in case the temporary file exists the streams should be initialized from it,
2996fe23d400SKurt Zenker         // but the original MediaDescriptor should not be changed
29975e32815aSXisco Fauli         bool bFromTempFile = ( pImpl->pTempFile != nullptr );
2998fe23d400SKurt Zenker 
2999fe23d400SKurt Zenker         if ( !bFromTempFile )
3000fe23d400SKurt Zenker         {
3001f5dd4faeSMike Kaganski             GetItemSet().Put( SfxStringItem( SID_FILE_NAME, aFileName ) );
30025e32815aSXisco Fauli             if( !(pImpl->m_nStorOpenMode & StreamMode::WRITE) )
3003f5dd4faeSMike Kaganski                 GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, true ) );
3004003a170aSKurt Zenker             if (xInteractionHandler.is())
3005f5dd4faeSMike Kaganski                 GetItemSet().Put( SfxUnoAnyItem( SID_INTERACTIONHANDLER, Any(xInteractionHandler) ) );
3006fe23d400SKurt Zenker         }
3007fe23d400SKurt Zenker 
30085e32815aSXisco Fauli         if ( pImpl->m_xInputStreamToLoadFrom.is() )
3009fe23d400SKurt Zenker         {
30105e32815aSXisco Fauli             pImpl->xInputStream = pImpl->m_xInputStreamToLoadFrom;
30115e32815aSXisco Fauli             if (pImpl->m_bInputStreamIsReadOnly)
3012f5dd4faeSMike Kaganski                 GetItemSet().Put( SfxBoolItem( SID_DOC_READONLY, true ) );
3013fe23d400SKurt Zenker         }
3014fe23d400SKurt Zenker         else
3015fe23d400SKurt Zenker         {
3016f5dd4faeSMike Kaganski             TransformItems( SID_OPENDOC, GetItemSet(), xProps );
301724cad6a6SStephan Bergmann             utl::MediaDescriptor aMedium( xProps );
3018fe23d400SKurt Zenker 
30195e32815aSXisco Fauli             if ( pImpl->m_xLockingStream.is() && !bFromTempFile )
302089fd6a8fSMikhail Voitenko             {
302189fd6a8fSMikhail Voitenko                 // the medium is not based on the temporary file, so the original stream can be used
30225e32815aSXisco Fauli                 pImpl->xStream = pImpl->m_xLockingStream;
302389fd6a8fSMikhail Voitenko             }
302489fd6a8fSMikhail Voitenko             else
302589fd6a8fSMikhail Voitenko             {
3026fe23d400SKurt Zenker                 if ( bFromTempFile )
3027fe23d400SKurt Zenker                 {
30282ab40e9eSNoel Grandin                     aMedium[utl::MediaDescriptor::PROP_URL] <<= aFileName;
30292ab40e9eSNoel Grandin                     aMedium.erase( utl::MediaDescriptor::PROP_READONLY );
3030762dd2b1SKurt Zenker                     aMedium.addInputStream();
30312058774bSVladimir Glazounov                 }
30326d64afb3SStephan Bergmann                 else if ( GetURLObject().GetProtocol() == INetProtocol::File )
30332058774bSVladimir Glazounov                 {
30342058774bSVladimir Glazounov                     // use the special locking approach only for file URLs
30353dfe5a3fSJens-Heiner Rechtien                     aMedium.addInputStreamOwnLock();
30362058774bSVladimir Glazounov                 }
30372058774bSVladimir Glazounov                 else
3038b4576f3dSGiuseppe Castagno                 {
30392eae33e8SAndrea Gelmini                     // add a check for protocol, if it's http or https or provide webdav then add
3040b4576f3dSGiuseppe Castagno                     // the interaction handler to be used by the authentication dialog
3041b4576f3dSGiuseppe Castagno                     if ( GetURLObject().isAnyKnownWebDAVScheme() )
3042b4576f3dSGiuseppe Castagno                     {
30432ab40e9eSNoel Grandin                         aMedium[utl::MediaDescriptor::PROP_AUTHENTICATIONHANDLER] <<= GetInteractionHandler( true );
3044b4576f3dSGiuseppe Castagno                     }
30452058774bSVladimir Glazounov                     aMedium.addInputStream();
3046b4576f3dSGiuseppe Castagno                 }
304796f1e7bbSVladimir Glazounov                 // the ReadOnly property set in aMedium is ignored
304896f1e7bbSVladimir Glazounov                 // the check is done in LockOrigFileOnDemand() for file and non-file URLs
3049762dd2b1SKurt Zenker 
3050762dd2b1SKurt Zenker                 //TODO/MBA: what happens if property is not there?!
30512ab40e9eSNoel Grandin                 aMedium[utl::MediaDescriptor::PROP_STREAM] >>= pImpl->xStream;
30522ab40e9eSNoel Grandin                 aMedium[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= pImpl->xInputStream;
305389fd6a8fSMikhail Voitenko             }
305489fd6a8fSMikhail Voitenko 
305589fd6a8fSMikhail Voitenko             GetContent();
30565e32815aSXisco Fauli             if ( !pImpl->xInputStream.is() && pImpl->xStream.is() )
30575e32815aSXisco Fauli                 pImpl->xInputStream = pImpl->xStream->getInputStream();
3058c25ed954SOliver Bolte         }
3059762dd2b1SKurt Zenker 
3060fe23d400SKurt Zenker         if ( !bFromTempFile )
3061fe23d400SKurt Zenker         {
3062762dd2b1SKurt Zenker             //TODO/MBA: need support for SID_STREAM
30635e32815aSXisco Fauli             if ( pImpl->xStream.is() )
3064f5dd4faeSMike Kaganski                 GetItemSet().Put( SfxUnoAnyItem( SID_STREAM, Any( pImpl->xStream ) ) );
3065762dd2b1SKurt Zenker 
3066f5dd4faeSMike Kaganski             GetItemSet().Put( SfxUnoAnyItem( SID_INPUTSTREAM, Any( pImpl->xInputStream ) ) );
30677165de29SMathias Bauer         }
3068fe23d400SKurt Zenker     }
30697165de29SMathias Bauer 
3070762dd2b1SKurt Zenker     //TODO/MBA: ErrorHandling - how to transport error from MediaDescriptor
3071ed774e9fSNoel Grandin     if ( !GetErrorIgnoreWarning() && !pImpl->xStream.is() && !pImpl->xInputStream.is() )
30729e4d84daSCaolán McNamara         SetError(ERRCODE_IO_ACCESSDENIED);
3073c4da372eSMathias Bauer 
3074ed774e9fSNoel Grandin     if ( !GetErrorIgnoreWarning() && !pImpl->m_pInStream )
30757b88567cSPascal Junck     {
30765e32815aSXisco Fauli         if ( pImpl->xStream.is() )
30775e32815aSXisco Fauli             pImpl->m_pInStream = utl::UcbStreamHelper::CreateStream( pImpl->xStream );
30785e32815aSXisco Fauli         else if ( pImpl->xInputStream.is() )
30795e32815aSXisco Fauli             pImpl->m_pInStream = utl::UcbStreamHelper::CreateStream( pImpl->xInputStream );
30807b88567cSPascal Junck     }
30817b88567cSPascal Junck 
30825e32815aSXisco Fauli     pImpl->bDownloadDone = true;
30835e32815aSXisco Fauli     pImpl->aDoneLink.ClearPendingCall();
3084d9e322d6SNoel Grandin     ErrCodeMsg nError = GetErrorIgnoreWarning();
3085d37df8fdSMike Kaganski     sal_uIntPtr nErrorCode = sal_uInt32(nError.GetCode());
3086d37df8fdSMike Kaganski     pImpl->aDoneLink.Call( reinterpret_cast<void*>(nErrorCode) );
30872d2337a3SMathias Bauer }
3088fd069beeSJens-Heiner Rechtien 
IsRemote() const3089cbc1176cSCaolán McNamara bool SfxMedium::IsRemote() const
3090fd069beeSJens-Heiner Rechtien {
30915e32815aSXisco Fauli     return pImpl->m_bRemote;
3092fd069beeSJens-Heiner Rechtien }
3093fd069beeSJens-Heiner Rechtien 
SetUpdatePickList(bool bVal)30945fe7ecc0SNoel Grandin void SfxMedium::SetUpdatePickList(bool bVal)
3095fd069beeSJens-Heiner Rechtien {
30965e32815aSXisco Fauli     pImpl->bUpdatePickList = bVal;
3097fd069beeSJens-Heiner Rechtien }
30980ce0c369SAlexander Wilms 
IsUpdatePickList() const30995fe7ecc0SNoel Grandin bool SfxMedium::IsUpdatePickList() const
3100fd069beeSJens-Heiner Rechtien {
31015e32815aSXisco Fauli     return pImpl->bUpdatePickList;
3102fd069beeSJens-Heiner Rechtien }
3103f9ac1ab1SKohei Yoshida 
SetLongName(const OUString & rName)3104f9ac1ab1SKohei Yoshida void SfxMedium::SetLongName(const OUString &rName)
3105f9ac1ab1SKohei Yoshida {
31065e32815aSXisco Fauli     pImpl->m_aLongName = rName;
3107f9ac1ab1SKohei Yoshida }
3108f9ac1ab1SKohei Yoshida 
GetLongName() const3109f9ac1ab1SKohei Yoshida const OUString& SfxMedium::GetLongName() const
3110f9ac1ab1SKohei Yoshida {
31115e32815aSXisco Fauli     return pImpl->m_aLongName;
3112f9ac1ab1SKohei Yoshida }
3113fd069beeSJens-Heiner Rechtien 
SetDoneLink(const Link<void *,void> & rLink)31147b096a6dSNoel Grandin void SfxMedium::SetDoneLink( const Link<void*,void>& rLink )
3115fd069beeSJens-Heiner Rechtien {
31165e32815aSXisco Fauli     pImpl->aDoneLink = rLink;
3117fd069beeSJens-Heiner Rechtien }
3118fd069beeSJens-Heiner Rechtien 
Download(const Link<void *,void> & aLink)31197b096a6dSNoel Grandin void SfxMedium::Download( const Link<void*,void>& aLink )
3120fd069beeSJens-Heiner Rechtien {
3121fd069beeSJens-Heiner Rechtien     SetDoneLink( aLink );
3122fd069beeSJens-Heiner Rechtien     GetInStream();
31235e32815aSXisco Fauli     if ( pImpl->m_pInStream && !aLink.IsSet() )
3124fd069beeSJens-Heiner Rechtien     {
3125c880d3e3SNoel Grandin         while( !pImpl->bDownloadDone && !Application::IsQuit())
3126fd069beeSJens-Heiner Rechtien             Application::Yield();
3127fd069beeSJens-Heiner Rechtien     }
3128fd069beeSJens-Heiner Rechtien }
3129fd069beeSJens-Heiner Rechtien 
31300ce0c369SAlexander Wilms 
3131f6536f4dSMichael Stahl /**
3132f6536f4dSMichael Stahl     Sets m_aLogicName to a valid URL and if available sets
3133f6536f4dSMichael Stahl     the physical name m_aName to the file name.
3134fd069beeSJens-Heiner Rechtien  */
Init_Impl()3135f6536f4dSMichael Stahl void SfxMedium::Init_Impl()
3136fd069beeSJens-Heiner Rechtien {
3137aa1c95f4SMikhail Voitenko     Reference< XOutputStream > rOutStream;
3138984b2bbbSRüdiger Timm 
3139984b2bbbSRüdiger Timm     // TODO/LATER: handle lifetime of storages
31405e32815aSXisco Fauli     pImpl->bDisposeStorage = false;
3141fd069beeSJens-Heiner Rechtien 
3142e4c40331SNoel Grandin     const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_DOC_SALVAGE, false);
314345739fadSCaolán McNamara     if ( pSalvageItem && pSalvageItem->GetValue().isEmpty() )
314427527fb1SAndreas Schlüns     {
314528034eafSStephan Bergmann         pSalvageItem = nullptr;
31465e32815aSXisco Fauli         pImpl->m_pSet->ClearItem( SID_DOC_SALVAGE );
314727527fb1SAndreas Schlüns     }
314827527fb1SAndreas Schlüns 
31495e32815aSXisco Fauli     if (!pImpl->m_aLogicName.isEmpty())
3150fd069beeSJens-Heiner Rechtien     {
31515e32815aSXisco Fauli         INetURLObject aUrl( pImpl->m_aLogicName );
31520042696fSMathias Bauer         INetProtocol eProt = aUrl.GetProtocol();
315354e87df1SStephan Bergmann         if ( eProt == INetProtocol::NotValid )
3154fd069beeSJens-Heiner Rechtien         {
315522c7aa82SStephan Bergmann             SAL_WARN( "sfx.doc", "URL <" << pImpl->m_aLogicName << "> with unknown protocol" );
3156fd069beeSJens-Heiner Rechtien         }
3157fd069beeSJens-Heiner Rechtien         else
3158fd069beeSJens-Heiner Rechtien         {
3159b5181a5eSVladimir Glazounov             if ( aUrl.HasMark() )
3160b5181a5eSVladimir Glazounov             {
316195eb0888SMatt K                 std::unique_lock<std::recursive_mutex> chkEditLock;
316295eb0888SMatt K                 if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
316395eb0888SMatt K                     chkEditLock = std::unique_lock<std::recursive_mutex>(
316495eb0888SMatt K                         *(pImpl->m_pCheckEditableWorkerMutex));
3165bfde4866SNoel Grandin                 pImpl->m_aLogicName = aUrl.GetURLNoMark( INetURLObject::DecodeMechanism::NONE );
316695eb0888SMatt K                 if (chkEditLock.owns_lock())
316795eb0888SMatt K                     chkEditLock.unlock();
3168f5dd4faeSMike Kaganski                 GetItemSet().Put( SfxStringItem( SID_JUMPMARK, aUrl.GetMark() ) );
3169b5181a5eSVladimir Glazounov             }
3170b5181a5eSVladimir Glazounov 
3171060e6431SMathias Bauer             // try to convert the URL into a physical name - but never change a physical name
3172060e6431SMathias Bauer             // physical name may be set if the logical name is changed after construction
31735e32815aSXisco Fauli             if ( pImpl->m_aName.isEmpty() )
3174bfde4866SNoel Grandin                 osl::FileBase::getSystemPathFromFileURL( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), pImpl->m_aName );
31753c62fbcdSCaolán McNamara             else
31763c62fbcdSCaolán McNamara             {
3177060e6431SMathias Bauer                 DBG_ASSERT( pSalvageItem, "Suspicious change of logical name!" );
3178fd069beeSJens-Heiner Rechtien             }
3179fd069beeSJens-Heiner Rechtien         }
3180fd1055e5SJens-Heiner Rechtien     }
3181fd069beeSJens-Heiner Rechtien 
318208385a62SMike Kaganski     if ( pSalvageItem )
3183c175c2beSVladimir Glazounov     {
318495eb0888SMatt K         std::unique_lock<std::recursive_mutex> chkEditLock;
318595eb0888SMatt K         if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
318695eb0888SMatt K             chkEditLock
318795eb0888SMatt K                 = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
31885e32815aSXisco Fauli         pImpl->m_aLogicName = pSalvageItem->GetValue();
3189e4c40331SNoel Grandin         pImpl->m_pURLObj.reset();
319095eb0888SMatt K         if (chkEditLock.owns_lock())
319195eb0888SMatt K             chkEditLock.unlock();
31925e32815aSXisco Fauli         pImpl->m_bSalvageMode = true;
3193c175c2beSVladimir Glazounov     }
3194aa1c95f4SMikhail Voitenko 
3195aa1c95f4SMikhail Voitenko     // in case output stream is by mistake here
3196aa1c95f4SMikhail Voitenko     // clear the reference
3197e4c40331SNoel Grandin     const SfxUnoAnyItem* pOutStreamItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_OUTPUTSTREAM, false);
3198aa1c95f4SMikhail Voitenko     if( pOutStreamItem
3199aa1c95f4SMikhail Voitenko      && ( !( pOutStreamItem->GetValue() >>= rOutStream )
32005e32815aSXisco Fauli           || !pImpl->m_aLogicName.startsWith("private:stream")) )
3201aa1c95f4SMikhail Voitenko     {
32025e32815aSXisco Fauli         pImpl->m_pSet->ClearItem( SID_OUTPUTSTREAM );
32038c8f2a52SNoel Grandin         SAL_WARN( "sfx.doc", "Unexpected Output stream parameter!" );
3204aa1c95f4SMikhail Voitenko     }
3205aa1c95f4SMikhail Voitenko 
32065e32815aSXisco Fauli     if (!pImpl->m_aLogicName.isEmpty())
3207414f4799SOliver Bolte     {
3208414f4799SOliver Bolte         // if the logic name is set it should be set in MediaDescriptor as well
3209e4c40331SNoel Grandin         const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3210414f4799SOliver Bolte         if ( !pFileNameItem )
3211414f4799SOliver Bolte         {
3212414f4799SOliver Bolte             // let the ItemSet be created if necessary
3213f5dd4faeSMike Kaganski             GetItemSet().Put(
3214c44f1e7eSKohei Yoshida                 SfxStringItem(
3215bfde4866SNoel Grandin                     SID_FILE_NAME, INetURLObject( pImpl->m_aLogicName ).GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
3216414f4799SOliver Bolte         }
3217414f4799SOliver Bolte     }
3218414f4799SOliver Bolte 
3219fd069beeSJens-Heiner Rechtien     SetIsRemote_Impl();
3220a199cad8SStephan Bergmann 
3221a199cad8SStephan Bergmann     osl::DirectoryItem item;
3222a199cad8SStephan Bergmann     if (osl::DirectoryItem::get(GetName(), item) == osl::FileBase::E_None) {
3223a199cad8SStephan Bergmann         osl::FileStatus stat(osl_FileStatus_Mask_Attributes);
3224a199cad8SStephan Bergmann         if (item.getFileStatus(stat) == osl::FileBase::E_None
3225a199cad8SStephan Bergmann             && stat.isValid(osl_FileStatus_Mask_Attributes))
3226a199cad8SStephan Bergmann         {
3227f9ab3136SMatt K             if ((stat.getAttributes() & osl_File_Attribute_ReadOnly) != 0)
322895eb0888SMatt K             {
32295e32815aSXisco Fauli                 pImpl->m_bOriginallyReadOnly = true;
3230a199cad8SStephan Bergmann             }
3231a199cad8SStephan Bergmann         }
3232a199cad8SStephan Bergmann     }
3233fd069beeSJens-Heiner Rechtien }
32340042696fSMathias Bauer 
32350ce0c369SAlexander Wilms 
SfxMedium()32365e32815aSXisco Fauli SfxMedium::SfxMedium() : pImpl(new SfxMedium_Impl)
3237fd069beeSJens-Heiner Rechtien {
3238fd069beeSJens-Heiner Rechtien     Init_Impl();
3239fd069beeSJens-Heiner Rechtien }
3240469c0743SMathias Bauer 
32410ce0c369SAlexander Wilms 
UseInteractionHandler(bool bUse)32425fe7ecc0SNoel Grandin void SfxMedium::UseInteractionHandler( bool bUse )
3243469c0743SMathias Bauer {
32445e32815aSXisco Fauli     pImpl->bAllowDefaultIntHdl = bUse;
3245469c0743SMathias Bauer }
3246469c0743SMathias Bauer 
32470ce0c369SAlexander Wilms 
3248913a2d36SNoel Grandin css::uno::Reference< css::task::XInteractionHandler >
GetInteractionHandler(bool bGetAlways)3249b4576f3dSGiuseppe Castagno SfxMedium::GetInteractionHandler( bool bGetAlways )
32500c2e3361SMikhail Voitenko {
3251820a2995SPedro Giffuni     // if interaction isn't allowed explicitly ... return empty reference!
32525e32815aSXisco Fauli     if ( !bGetAlways && !pImpl->bUseInteractionHandler )
3253913a2d36SNoel Grandin         return css::uno::Reference< css::task::XInteractionHandler >();
32545be98ebaSJens-Heiner Rechtien 
32555be98ebaSJens-Heiner Rechtien     // search a possible existing handler inside cached item set
32565e32815aSXisco Fauli     if ( pImpl->m_pSet )
32570c2e3361SMikhail Voitenko     {
3258913a2d36SNoel Grandin         css::uno::Reference< css::task::XInteractionHandler > xHandler;
3259e4c40331SNoel Grandin         const SfxUnoAnyItem* pHandler = SfxItemSet::GetItem<SfxUnoAnyItem>(pImpl->m_pSet.get(), SID_INTERACTIONHANDLER, false);
32605be98ebaSJens-Heiner Rechtien         if ( pHandler && (pHandler->GetValue() >>= xHandler) && xHandler.is() )
32615be98ebaSJens-Heiner Rechtien             return xHandler;
32625be98ebaSJens-Heiner Rechtien     }
32635be98ebaSJens-Heiner Rechtien 
3264820a2995SPedro Giffuni     // if default interaction isn't allowed explicitly ... return empty reference!
32655e32815aSXisco Fauli     if ( !bGetAlways && !pImpl->bAllowDefaultIntHdl )
3266913a2d36SNoel Grandin         return css::uno::Reference< css::task::XInteractionHandler >();
3267ea10aa3bSJens-Heiner Rechtien 
3268e2f97dccSIvan Timofeev     // otherwise return cached default handler ... if it exist.
32695e32815aSXisco Fauli     if ( pImpl->xInteraction.is() )
32705e32815aSXisco Fauli         return pImpl->xInteraction;
3271ea10aa3bSJens-Heiner Rechtien 
32725be98ebaSJens-Heiner Rechtien     // create default handler and cache it!
3273ed0b12f4SNoel Grandin     const Reference< uno::XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
32745e32815aSXisco Fauli     pImpl->xInteraction.set(
327528034eafSStephan Bergmann         task::InteractionHandler::createWithParent(xContext, nullptr), UNO_QUERY_THROW );
32765e32815aSXisco Fauli     return pImpl->xInteraction;
32770c2e3361SMikhail Voitenko }
32780c2e3361SMikhail Voitenko 
SetFilter(const std::shared_ptr<const SfxFilter> & pFilter)32794cbcec9eSNoel Grandin void SfxMedium::SetFilter( const std::shared_ptr<const SfxFilter>& pFilter )
3280fd069beeSJens-Heiner Rechtien {
32815e32815aSXisco Fauli     pImpl->m_pFilter = pFilter;
3282fd069beeSJens-Heiner Rechtien }
3283e0986b32SMikhail Voytenko 
GetFilter() const3284523036daSNoel Grandin const std::shared_ptr<const SfxFilter>& SfxMedium::GetFilter() const
3285e8853ab7SKohei Yoshida {
32865e32815aSXisco Fauli     return pImpl->m_pFilter;
3287e8853ab7SKohei Yoshida }
3288e8853ab7SKohei Yoshida 
CreatePasswordToModifyHash(std::u16string_view aPasswd,bool bWriter)3289b24a4d25SNoel Grandin sal_uInt32 SfxMedium::CreatePasswordToModifyHash( std::u16string_view aPasswd, bool bWriter )
3290e0986b32SMikhail Voytenko {
3291b1ec4b2cSMikhail Voytenko     sal_uInt32 nHash = 0;
3292e0986b32SMikhail Voytenko 
3293b24a4d25SNoel Grandin     if ( !aPasswd.empty() )
3294e0986b32SMikhail Voytenko     {
3295b1ec4b2cSMikhail Voytenko         if ( bWriter )
3296e0986b32SMikhail Voytenko         {
3297b1ec4b2cSMikhail Voytenko             nHash = ::comphelper::DocPasswordHelper::GetWordHashAsUINT32( aPasswd );
3298b1ec4b2cSMikhail Voytenko         }
3299b1ec4b2cSMikhail Voytenko         else
3300b1ec4b2cSMikhail Voytenko         {
33017dce1c9fSJulien Nabet             rtl_TextEncoding nEncoding = osl_getThreadTextEncoding();
3302e0986b32SMikhail Voytenko             nHash = ::comphelper::DocPasswordHelper::GetXLHashAsUINT16( aPasswd, nEncoding );
3303e0986b32SMikhail Voytenko         }
3304b1ec4b2cSMikhail Voytenko     }
3305e0986b32SMikhail Voytenko 
3306e0986b32SMikhail Voytenko     return nHash;
3307e0986b32SMikhail Voytenko }
3308e0986b32SMikhail Voytenko 
33090ce0c369SAlexander Wilms 
Close(bool bInDestruction)3310c0d372d7SNoel Grandin void SfxMedium::Close(bool bInDestruction)
3311fd069beeSJens-Heiner Rechtien {
33125e32815aSXisco Fauli     if ( pImpl->xStorage.is() )
3313fd069beeSJens-Heiner Rechtien     {
3314fd069beeSJens-Heiner Rechtien         CloseStorage();
3315fd069beeSJens-Heiner Rechtien     }
3316fd069beeSJens-Heiner Rechtien 
3317c0d372d7SNoel Grandin     CloseStreams_Impl(bInDestruction);
33182058774bSVladimir Glazounov 
3319df8a15d8SKohei Yoshida     UnlockFile( false );
3320762dd2b1SKurt Zenker }
3321fd069beeSJens-Heiner Rechtien 
CloseAndRelease()3322664ae670SRüdiger Timm void SfxMedium::CloseAndRelease()
3323664ae670SRüdiger Timm {
33245e32815aSXisco Fauli     if ( pImpl->xStorage.is() )
3325664ae670SRüdiger Timm     {
3326664ae670SRüdiger Timm         CloseStorage();
3327664ae670SRüdiger Timm     }
3328664ae670SRüdiger Timm 
3329e96f63f6SOliver Bolte     CloseAndReleaseStreams_Impl();
33302058774bSVladimir Glazounov 
3331df8a15d8SKohei Yoshida     UnlockFile( true );
33322058774bSVladimir Glazounov }
33332058774bSVladimir Glazounov 
DisableUnlockWebDAV(bool bDisableUnlockWebDAV)3334b4576f3dSGiuseppe Castagno void SfxMedium::DisableUnlockWebDAV( bool bDisableUnlockWebDAV )
3335b4576f3dSGiuseppe Castagno {
33365e32815aSXisco Fauli     pImpl->m_bDisableUnlockWebDAV = bDisableUnlockWebDAV;
3337b4576f3dSGiuseppe Castagno }
3338b4576f3dSGiuseppe Castagno 
DisableFileSync(bool bDisableFileSync)3339d03a7547SMiklos Vajna void SfxMedium::DisableFileSync(bool bDisableFileSync)
3340d03a7547SMiklos Vajna {
3341d03a7547SMiklos Vajna     pImpl->m_bDisableFileSync = bDisableFileSync;
3342d03a7547SMiklos Vajna }
3343d03a7547SMiklos Vajna 
UnlockFile(bool bReleaseLockStream)33445fe7ecc0SNoel Grandin void SfxMedium::UnlockFile( bool bReleaseLockStream )
33452058774bSVladimir Glazounov {
3346a8c3c673STor Lillqvist #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
33473ee3e794STor Lillqvist     (void) bReleaseLockStream;
33483ee3e794STor Lillqvist #else
3349b4576f3dSGiuseppe Castagno     // check if webdav
3350b4576f3dSGiuseppe Castagno     if ( GetURLObject().isAnyKnownWebDAVScheme() )
3351b4576f3dSGiuseppe Castagno     {
3352297be63cSKatarina Behrens         // do nothing if WebDAV locking if disabled
3353297be63cSKatarina Behrens         // (shouldn't happen because we already skipped locking,
3354297be63cSKatarina Behrens         // see LockOrigFileOnDemand, but just in case ...)
3355297be63cSKatarina Behrens         if (!IsWebDAVLockingUsed())
3356297be63cSKatarina Behrens             return;
3357297be63cSKatarina Behrens 
33585e32815aSXisco Fauli         if ( pImpl->m_bLocked )
3359b4576f3dSGiuseppe Castagno         {
3360b4576f3dSGiuseppe Castagno             // an interaction handler should be used for authentication, if needed
3361b4576f3dSGiuseppe Castagno             try {
3362913a2d36SNoel Grandin                 uno::Reference< css::task::XInteractionHandler > xHandler = GetInteractionHandler( true );
3363913a2d36SNoel Grandin                 uno::Reference< css::ucb::XCommandEnvironment > xComEnv = new ::ucbhelper::CommandEnvironment( xHandler,
3364913a2d36SNoel Grandin                                                                Reference< css::ucb::XProgressHandler >() );
3365bfde4866SNoel Grandin                 ucbhelper::Content aContentToUnlock( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ), xComEnv, comphelper::getProcessComponentContext());
33665e32815aSXisco Fauli                 pImpl->m_bLocked = false;
3367b4576f3dSGiuseppe Castagno                 //check if WebDAV unlock was explicitly disabled
33685e32815aSXisco Fauli                 if ( !pImpl->m_bDisableUnlockWebDAV )
3369b4576f3dSGiuseppe Castagno                     aContentToUnlock.unlock();
3370b4576f3dSGiuseppe Castagno             }
3371b4576f3dSGiuseppe Castagno             catch ( uno::Exception& )
3372b4576f3dSGiuseppe Castagno             {
3373889dc7bfSNoel Grandin                 TOOLS_WARN_EXCEPTION( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
3374b4576f3dSGiuseppe Castagno             }
3375b4576f3dSGiuseppe Castagno         }
3376b4576f3dSGiuseppe Castagno         return;
3377b4576f3dSGiuseppe Castagno     }
3378b4576f3dSGiuseppe Castagno 
33795e32815aSXisco Fauli     if ( pImpl->m_xLockingStream.is() )
338089fd6a8fSMikhail Voitenko     {
338189fd6a8fSMikhail Voitenko         if ( bReleaseLockStream )
338289fd6a8fSMikhail Voitenko         {
338389fd6a8fSMikhail Voitenko             try
338489fd6a8fSMikhail Voitenko             {
33855e32815aSXisco Fauli                 uno::Reference< io::XInputStream > xInStream = pImpl->m_xLockingStream->getInputStream();
33865e32815aSXisco Fauli                 uno::Reference< io::XOutputStream > xOutStream = pImpl->m_xLockingStream->getOutputStream();
338789fd6a8fSMikhail Voitenko                 if ( xInStream.is() )
338889fd6a8fSMikhail Voitenko                     xInStream->closeInput();
338989fd6a8fSMikhail Voitenko                 if ( xOutStream.is() )
339089fd6a8fSMikhail Voitenko                     xOutStream->closeOutput();
339189fd6a8fSMikhail Voitenko             }
33926c89e69bSCaolán McNamara             catch( const uno::Exception& )
339389fd6a8fSMikhail Voitenko             {}
339489fd6a8fSMikhail Voitenko         }
339589fd6a8fSMikhail Voitenko 
33965e32815aSXisco Fauli         pImpl->m_xLockingStream.clear();
339789fd6a8fSMikhail Voitenko     }
339889fd6a8fSMikhail Voitenko 
3399536a6d6cSNoel Grandin     if ( !pImpl->m_bLocked )
3400536a6d6cSNoel Grandin         return;
3401536a6d6cSNoel Grandin 
3402ef79b9c5SMike Kaganski     try
3403ef79b9c5SMike Kaganski     {
34046ca3b364SJuergen Funk         ::svt::DocumentLockFile aLockFile(pImpl->m_aLogicName);
34056ca3b364SJuergen Funk 
34062058774bSVladimir Glazounov         try
34072058774bSVladimir Glazounov         {
34085e32815aSXisco Fauli             pImpl->m_bLocked = false;
34093dfe5a3fSJens-Heiner Rechtien             // TODO/LATER: A warning could be shown in case the file is not the own one
34103dfe5a3fSJens-Heiner Rechtien             aLockFile.RemoveFile();
34112058774bSVladimir Glazounov         }
34126ca3b364SJuergen Funk         catch (const io::WrongFormatException&)
34136ca3b364SJuergen Funk         {
34146ca3b364SJuergen Funk             // erase the empty or corrupt file
34156ca3b364SJuergen Funk             aLockFile.RemoveFileDirectly();
34166ca3b364SJuergen Funk         }
34176ca3b364SJuergen Funk     }
34186c89e69bSCaolán McNamara     catch( const uno::Exception& )
34192058774bSVladimir Glazounov     {}
342041dc917bSTamás Zolnai 
3421f659ec61SNoel Grandin     if(!pImpl->m_bMSOLockFileCreated)
3422f659ec61SNoel Grandin         return;
3423f659ec61SNoel Grandin 
3424ef79b9c5SMike Kaganski     try
3425ef79b9c5SMike Kaganski     {
342641dc917bSTamás Zolnai         ::svt::MSODocumentLockFile aMSOLockFile(pImpl->m_aLogicName);
342741dc917bSTamás Zolnai 
342841dc917bSTamás Zolnai         try
342941dc917bSTamás Zolnai         {
343041dc917bSTamás Zolnai             pImpl->m_bLocked = false;
343141dc917bSTamás Zolnai             // TODO/LATER: A warning could be shown in case the file is not the own one
343241dc917bSTamás Zolnai             aMSOLockFile.RemoveFile();
343341dc917bSTamás Zolnai         }
343441dc917bSTamás Zolnai         catch (const io::WrongFormatException&)
343541dc917bSTamás Zolnai         {
343641dc917bSTamás Zolnai             // erase the empty or corrupt file
343741dc917bSTamás Zolnai             aMSOLockFile.RemoveFileDirectly();
343841dc917bSTamás Zolnai         }
343941dc917bSTamás Zolnai     }
344041dc917bSTamás Zolnai     catch( const uno::Exception& )
344141dc917bSTamás Zolnai     {}
344241dc917bSTamás Zolnai     pImpl->m_bMSOLockFileCreated = false;
34433ee3e794STor Lillqvist #endif
3444e96f63f6SOliver Bolte }
3445e96f63f6SOliver Bolte 
CloseAndReleaseStreams_Impl()3446e96f63f6SOliver Bolte void SfxMedium::CloseAndReleaseStreams_Impl()
3447664ae670SRüdiger Timm {
3448ac49eeddSIvo Hinkelmann     CloseZipStorage_Impl();
3449e96f63f6SOliver Bolte 
34505e32815aSXisco Fauli     uno::Reference< io::XInputStream > xInToClose = pImpl->xInputStream;
3451e96f63f6SOliver Bolte     uno::Reference< io::XOutputStream > xOutToClose;
34525e32815aSXisco Fauli     if ( pImpl->xStream.is() )
345389fd6a8fSMikhail Voitenko     {
34545e32815aSXisco Fauli         xOutToClose = pImpl->xStream->getOutputStream();
3455e96f63f6SOliver Bolte 
345689fd6a8fSMikhail Voitenko         // if the locking stream is closed here the related member should be cleaned
34575e32815aSXisco Fauli         if ( pImpl->xStream == pImpl->m_xLockingStream )
34585e32815aSXisco Fauli             pImpl->m_xLockingStream.clear();
345989fd6a8fSMikhail Voitenko     }
346089fd6a8fSMikhail Voitenko 
34610ed38fb7SAndrea Gelmini     // The probably existing SvStream wrappers should be closed first
3462e96f63f6SOliver Bolte     CloseStreams_Impl();
3463e96f63f6SOliver Bolte 
3464f761aef4SIvo Hinkelmann     // in case of salvage mode the storage is based on the streams
3465536a6d6cSNoel Grandin     if ( pImpl->m_bSalvageMode )
3466536a6d6cSNoel Grandin         return;
3467536a6d6cSNoel Grandin 
3468e96f63f6SOliver Bolte     try
3469e96f63f6SOliver Bolte     {
3470e96f63f6SOliver Bolte         if ( xInToClose.is() )
3471e96f63f6SOliver Bolte             xInToClose->closeInput();
3472e96f63f6SOliver Bolte         if ( xOutToClose.is() )
3473e96f63f6SOliver Bolte             xOutToClose->closeOutput();
3474664ae670SRüdiger Timm     }
34756c89e69bSCaolán McNamara     catch ( const uno::Exception& )
3476664ae670SRüdiger Timm     {
3477664ae670SRüdiger Timm     }
3478664ae670SRüdiger Timm }
3479664ae670SRüdiger Timm 
34800ce0c369SAlexander Wilms 
CloseStreams_Impl(bool bInDestruction)3481c0d372d7SNoel Grandin void SfxMedium::CloseStreams_Impl(bool bInDestruction)
3482762dd2b1SKurt Zenker {
3483c0d372d7SNoel Grandin     CloseInStream_Impl(bInDestruction);
3484fd069beeSJens-Heiner Rechtien     CloseOutStream_Impl();
34857165de29SMathias Bauer 
34865e32815aSXisco Fauli     if ( pImpl->m_pSet )
34875e32815aSXisco Fauli         pImpl->m_pSet->ClearItem( SID_CONTENT );
34882b800085SJens-Heiner Rechtien 
34895e32815aSXisco Fauli     pImpl->aContent = ::ucbhelper::Content();
3490fd069beeSJens-Heiner Rechtien }
3491fd069beeSJens-Heiner Rechtien 
34920ce0c369SAlexander Wilms 
SetIsRemote_Impl()3493fd069beeSJens-Heiner Rechtien void SfxMedium::SetIsRemote_Impl()
3494fd069beeSJens-Heiner Rechtien {
3495c25ed954SOliver Bolte     INetURLObject aObj( GetName() );
3496fd069beeSJens-Heiner Rechtien     switch( aObj.GetProtocol() )
3497fd069beeSJens-Heiner Rechtien     {
349854e87df1SStephan Bergmann         case INetProtocol::Ftp:
349954e87df1SStephan Bergmann         case INetProtocol::Http:
350054e87df1SStephan Bergmann         case INetProtocol::Https:
35015e32815aSXisco Fauli             pImpl->m_bRemote = true;
35023faf775cSKohei Yoshida         break;
3503fd069beeSJens-Heiner Rechtien         default:
35045e32815aSXisco Fauli             pImpl->m_bRemote = GetName().startsWith("private:msgid");
3505fd069beeSJens-Heiner Rechtien             break;
3506fd069beeSJens-Heiner Rechtien     }
3507fd069beeSJens-Heiner Rechtien 
3508dcd5dee8SAlbert Thuswaldner     // As files that are written to the remote transmission must also be able
3509dcd5dee8SAlbert Thuswaldner     // to be read.
35105e32815aSXisco Fauli     if (pImpl->m_bRemote)
35115e32815aSXisco Fauli         pImpl->m_nStorOpenMode |= StreamMode::READ;
3512fd069beeSJens-Heiner Rechtien }
3513fd069beeSJens-Heiner Rechtien 
3514fd069beeSJens-Heiner Rechtien 
SetName(const OUString & aNameP,bool bSetOrigURL)35155fe7ecc0SNoel Grandin void SfxMedium::SetName( const OUString& aNameP, bool bSetOrigURL )
3516fd069beeSJens-Heiner Rechtien {
35175e32815aSXisco Fauli     if (pImpl->aOrigURL.isEmpty())
35185e32815aSXisco Fauli         pImpl->aOrigURL = pImpl->m_aLogicName;
3519fd069beeSJens-Heiner Rechtien     if( bSetOrigURL )
35205e32815aSXisco Fauli         pImpl->aOrigURL = aNameP;
352195eb0888SMatt K     std::unique_lock<std::recursive_mutex> chkEditLock;
352295eb0888SMatt K     if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
352395eb0888SMatt K         chkEditLock = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
35245e32815aSXisco Fauli     pImpl->m_aLogicName = aNameP;
3525e4c40331SNoel Grandin     pImpl->m_pURLObj.reset();
352695eb0888SMatt K     if (chkEditLock.owns_lock())
352795eb0888SMatt K         chkEditLock.unlock();
35285e32815aSXisco Fauli     pImpl->aContent = ::ucbhelper::Content();
35290042696fSMathias Bauer     Init_Impl();
3530fd069beeSJens-Heiner Rechtien }
3531fd069beeSJens-Heiner Rechtien 
35320ce0c369SAlexander Wilms 
GetOrigURL() const3533d1cc0071SKohei Yoshida const OUString& SfxMedium::GetOrigURL() const
3534fd069beeSJens-Heiner Rechtien {
35355e32815aSXisco Fauli     return pImpl->aOrigURL.isEmpty() ? pImpl->m_aLogicName : pImpl->aOrigURL;
3536fd069beeSJens-Heiner Rechtien }
3537fd069beeSJens-Heiner Rechtien 
35380ce0c369SAlexander Wilms 
SetPhysicalName_Impl(const OUString & rNameP)35391946794aSLuboš Luňák void SfxMedium::SetPhysicalName_Impl( const OUString& rNameP )
3540fd069beeSJens-Heiner Rechtien {
35415e32815aSXisco Fauli     if ( rNameP != pImpl->m_aName )
3542060e6431SMathias Bauer     {
3543e4c40331SNoel Grandin         pImpl->pTempFile.reset();
3544fd069beeSJens-Heiner Rechtien 
35455e32815aSXisco Fauli         if ( !pImpl->m_aName.isEmpty() || !rNameP.isEmpty() )
35465e32815aSXisco Fauli             pImpl->aContent = ::ucbhelper::Content();
3547060e6431SMathias Bauer 
35485e32815aSXisco Fauli         pImpl->m_aName = rNameP;
35495e32815aSXisco Fauli         pImpl->m_bTriedStorage = false;
35505e32815aSXisco Fauli         pImpl->bIsStorage = false;
3551060e6431SMathias Bauer     }
3552fd069beeSJens-Heiner Rechtien }
3553fd069beeSJens-Heiner Rechtien 
ReOpen()3554fd069beeSJens-Heiner Rechtien void SfxMedium::ReOpen()
3555fd069beeSJens-Heiner Rechtien {
35565e32815aSXisco Fauli     bool bUseInteractionHandler = pImpl->bUseInteractionHandler;
35575e32815aSXisco Fauli     pImpl->bUseInteractionHandler = false;
3558762dd2b1SKurt Zenker     GetMedium_Impl();
35595e32815aSXisco Fauli     pImpl->bUseInteractionHandler = bUseInteractionHandler;
3560fd069beeSJens-Heiner Rechtien }
356197726fb1SRüdiger Timm 
CompleteReOpen()356297726fb1SRüdiger Timm void SfxMedium::CompleteReOpen()
356397726fb1SRüdiger Timm {
356497726fb1SRüdiger Timm     // do not use temporary file for reopen and in case of success throw the temporary file away
35655e32815aSXisco Fauli     bool bUseInteractionHandler = pImpl->bUseInteractionHandler;
35665e32815aSXisco Fauli     pImpl->bUseInteractionHandler = false;
356797726fb1SRüdiger Timm 
35684a5ab800SMichael Meeks     std::unique_ptr<MediumTempFile> pTmpFile;
35695e32815aSXisco Fauli     if ( pImpl->pTempFile )
357097726fb1SRüdiger Timm     {
3571146f98e7SNoel Grandin         pTmpFile = std::move(pImpl->pTempFile);
35725e32815aSXisco Fauli         pImpl->m_aName.clear();
357397726fb1SRüdiger Timm     }
357497726fb1SRüdiger Timm 
357597726fb1SRüdiger Timm     GetMedium_Impl();
357697726fb1SRüdiger Timm 
3577ed774e9fSNoel Grandin     if ( GetErrorIgnoreWarning() )
357897726fb1SRüdiger Timm     {
35795e32815aSXisco Fauli         if ( pImpl->pTempFile )
358097726fb1SRüdiger Timm         {
35815e32815aSXisco Fauli             pImpl->pTempFile->EnableKillingFile();
3582e4c40331SNoel Grandin             pImpl->pTempFile.reset();
358397726fb1SRüdiger Timm         }
3584146f98e7SNoel Grandin         pImpl->pTempFile = std::move( pTmpFile );
35855e32815aSXisco Fauli         if ( pImpl->pTempFile )
35865e32815aSXisco Fauli             pImpl->m_aName = pImpl->pTempFile->GetFileName();
358797726fb1SRüdiger Timm     }
358891101dc0SCaolán McNamara     else if (pTmpFile)
358997726fb1SRüdiger Timm     {
3590e5da350eSNoel Grandin         pTmpFile->EnableKillingFile();
3591146f98e7SNoel Grandin         pTmpFile.reset();
359297726fb1SRüdiger Timm     }
359397726fb1SRüdiger Timm 
35945e32815aSXisco Fauli     pImpl->bUseInteractionHandler = bUseInteractionHandler;
359597726fb1SRüdiger Timm }
359697726fb1SRüdiger Timm 
SfxMedium(const OUString & rName,StreamMode nOpenMode,std::shared_ptr<const SfxFilter> pFilter,const std::shared_ptr<SfxItemSet> & pInSet)3597cc4dbe47SNoel Grandin SfxMedium::SfxMedium(const OUString &rName, StreamMode nOpenMode, std::shared_ptr<const SfxFilter> pFilter, const std::shared_ptr<SfxItemSet>& pInSet) :
35985e32815aSXisco Fauli     pImpl(new SfxMedium_Impl)
3599fd069beeSJens-Heiner Rechtien {
3600cc4dbe47SNoel Grandin     pImpl->m_pSet = pInSet;
360117a2c9e8SNoel Grandin     pImpl->m_pFilter = std::move(pFilter);
36025e32815aSXisco Fauli     pImpl->m_aLogicName = rName;
36035e32815aSXisco Fauli     pImpl->m_nStorOpenMode = nOpenMode;
3604fd069beeSJens-Heiner Rechtien     Init_Impl();
3605fd069beeSJens-Heiner Rechtien }
360620a7b521SOliver Bolte 
SfxMedium(const OUString & rName,const OUString & rReferer,StreamMode nOpenMode,std::shared_ptr<const SfxFilter> pFilter,const std::shared_ptr<SfxItemSet> & pInSet)3607cc4dbe47SNoel Grandin SfxMedium::SfxMedium(const OUString &rName, const OUString &rReferer, StreamMode nOpenMode, std::shared_ptr<const SfxFilter> pFilter, const std::shared_ptr<SfxItemSet>& pInSet) :
36085e32815aSXisco Fauli     pImpl(new SfxMedium_Impl)
3609f0a9ca24SStephan Bergmann {
3610cc4dbe47SNoel Grandin     pImpl->m_pSet = pInSet;
3611f5dd4faeSMike Kaganski     SfxItemSet& s = GetItemSet();
3612f5dd4faeSMike Kaganski     if (s.GetItem(SID_REFERER) == nullptr) {
3613f5dd4faeSMike Kaganski         s.Put(SfxStringItem(SID_REFERER, rReferer));
3614f0a9ca24SStephan Bergmann     }
361517a2c9e8SNoel Grandin     pImpl->m_pFilter = std::move(pFilter);
36165e32815aSXisco Fauli     pImpl->m_aLogicName = rName;
36175e32815aSXisco Fauli     pImpl->m_nStorOpenMode = nOpenMode;
3618f0a9ca24SStephan Bergmann     Init_Impl();
3619f0a9ca24SStephan Bergmann }
3620f0a9ca24SStephan Bergmann 
SfxMedium(const uno::Sequence<beans::PropertyValue> & aArgs)362127246395SKohei Yoshida SfxMedium::SfxMedium( const uno::Sequence<beans::PropertyValue>& aArgs ) :
36225e32815aSXisco Fauli     pImpl(new SfxMedium_Impl)
362320a7b521SOliver Bolte {
3624d92aa2f4SNorbert Thiebaud     SfxAllItemSet *pParams = new SfxAllItemSet( SfxGetpApp()->GetPool() );
3625e4c40331SNoel Grandin     pImpl->m_pSet.reset( pParams );
362620a7b521SOliver Bolte     TransformParameters( SID_OPENDOC, aArgs, *pParams );
3627d7687578SMiklos Vajna     SetArgs(aArgs);
362820a7b521SOliver Bolte 
36290552a09bSKohei Yoshida     OUString aFilterProvider, aFilterName;
3630746f8a08SKohei Yoshida     {
363151b995b9SNoel Grandin         const SfxStringItem* pItem = nullptr;
363251b995b9SNoel Grandin         if ((pItem = pImpl->m_pSet->GetItemIfSet(SID_FILTER_PROVIDER)))
363351b995b9SNoel Grandin             aFilterProvider = pItem->GetValue();
36340552a09bSKohei Yoshida 
363551b995b9SNoel Grandin         if ((pItem = pImpl->m_pSet->GetItemIfSet(SID_FILTER_NAME)))
363651b995b9SNoel Grandin             aFilterName = pItem->GetValue();
3637746f8a08SKohei Yoshida     }
3638746f8a08SKohei Yoshida 
3639746f8a08SKohei Yoshida     if (aFilterProvider.isEmpty())
3640746f8a08SKohei Yoshida     {
3641746f8a08SKohei Yoshida         // This is a conventional filter type.
36425e32815aSXisco Fauli         pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4FilterName( aFilterName );
3643746f8a08SKohei Yoshida     }
3644746f8a08SKohei Yoshida     else
3645746f8a08SKohei Yoshida     {
3646746f8a08SKohei Yoshida         // This filter is from an external provider such as orcus.
3647a5e25556SNoel Grandin         pImpl->m_pCustomFilter = std::make_shared<SfxFilter>(aFilterProvider, aFilterName);
36485e32815aSXisco Fauli         pImpl->m_pFilter = pImpl->m_pCustomFilter;
3649746f8a08SKohei Yoshida     }
365020a7b521SOliver Bolte 
3651e4c40331SNoel Grandin     const SfxStringItem* pSalvageItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_DOC_SALVAGE, false);
365220a7b521SOliver Bolte     if( pSalvageItem )
365320a7b521SOliver Bolte     {
365420a7b521SOliver Bolte         // QUESTION: there is some treatment of Salvage in Init_Impl; align!
365545739fadSCaolán McNamara         if ( !pSalvageItem->GetValue().isEmpty() )
365620a7b521SOliver Bolte         {
36571156f981SCaolán McNamara             // if a URL is provided in SalvageItem that means that the FileName refers to a temporary file
365820a7b521SOliver Bolte             // that must be copied here
365920a7b521SOliver Bolte 
3660e4c40331SNoel Grandin             const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3661e68b9cafSRelease Engineers             if (!pFileNameItem) throw uno::RuntimeException();
36621946794aSLuboš Luňák             OUString aNewTempFileURL = SfxMedium::CreateTempCopyWithExt( pFileNameItem->GetValue() );
3663e24a27b4SOlivier Hallot             if ( !aNewTempFileURL.isEmpty() )
366420a7b521SOliver Bolte             {
36655e32815aSXisco Fauli                 pImpl->m_pSet->Put( SfxStringItem( SID_FILE_NAME, aNewTempFileURL ) );
36665e32815aSXisco Fauli                 pImpl->m_pSet->ClearItem( SID_INPUTSTREAM );
36675e32815aSXisco Fauli                 pImpl->m_pSet->ClearItem( SID_STREAM );
36685e32815aSXisco Fauli                 pImpl->m_pSet->ClearItem( SID_CONTENT );
366920a7b521SOliver Bolte             }
367020a7b521SOliver Bolte             else
367120a7b521SOliver Bolte             {
36728c8f2a52SNoel Grandin                 SAL_WARN( "sfx.doc", "Can not create a new temporary file for crash recovery!" );
367320a7b521SOliver Bolte             }
367420a7b521SOliver Bolte         }
367520a7b521SOliver Bolte     }
367620a7b521SOliver Bolte 
3677e4c40331SNoel Grandin     const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
367820a7b521SOliver Bolte     if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
3679191c0a9eSStephan Bergmann         pImpl->m_bOriginallyLoadedReadOnly = true;
368020a7b521SOliver Bolte 
3681e4c40331SNoel Grandin     const SfxStringItem* pFileNameItem = SfxItemSet::GetItem<SfxStringItem>(pImpl->m_pSet.get(), SID_FILE_NAME, false);
3682e68b9cafSRelease Engineers     if (!pFileNameItem) throw uno::RuntimeException();
36835e32815aSXisco Fauli     pImpl->m_aLogicName = pFileNameItem->GetValue();
3684191c0a9eSStephan Bergmann     pImpl->m_nStorOpenMode = pImpl->m_bOriginallyLoadedReadOnly
3685191c0a9eSStephan Bergmann         ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
368620a7b521SOliver Bolte     Init_Impl();
368720a7b521SOliver Bolte }
368820a7b521SOliver Bolte 
SetArgs(const uno::Sequence<beans::PropertyValue> & rArgs)3689037cd13aSMiklos Vajna void SfxMedium::SetArgs(const uno::Sequence<beans::PropertyValue>& rArgs)
3690037cd13aSMiklos Vajna {
3691d7687578SMiklos Vajna     comphelper::SequenceAsHashMap aArgsMap(rArgs);
3692bd1c60bcSShardul Vikram Singh     aArgsMap.erase(u"Stream"_ustr);
3693bd1c60bcSShardul Vikram Singh     aArgsMap.erase(u"InputStream"_ustr);
3694bd1c60bcSShardul Vikram Singh 
3695d7687578SMiklos Vajna     pImpl->m_aArgs = aArgsMap.getAsConstPropertyValueList();
3696037cd13aSMiklos Vajna }
3697037cd13aSMiklos Vajna 
GetArgs() const3698c83166ceSNoel const uno::Sequence<beans::PropertyValue> & SfxMedium::GetArgs() const { return pImpl->m_aArgs; }
369920a7b521SOliver Bolte 
SfxMedium(const uno::Reference<embed::XStorage> & rStor,const OUString & rBaseURL,const std::shared_ptr<SfxItemSet> & p)3700cc4dbe47SNoel Grandin SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const OUString& rBaseURL, const std::shared_ptr<SfxItemSet>& p ) :
37015e32815aSXisco Fauli     pImpl(new SfxMedium_Impl)
3702fd069beeSJens-Heiner Rechtien {
37034deddf20SKohei Yoshida     OUString aType = SfxFilter::GetTypeFromStorage(rStor);
37045e32815aSXisco Fauli     pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4EA( aType );
37055e32815aSXisco Fauli     DBG_ASSERT( pImpl->m_pFilter, "No Filter for storage found!" );
37067c1f86d2SSven Jacobi 
37077c1f86d2SSven Jacobi     Init_Impl();
37085e32815aSXisco Fauli     pImpl->xStorage = rStor;
37095e32815aSXisco Fauli     pImpl->bDisposeStorage = false;
3710984b2bbbSRüdiger Timm 
3711984b2bbbSRüdiger Timm     // always take BaseURL first, could be overwritten by ItemSet
3712f5dd4faeSMike Kaganski     GetItemSet().Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
3713984b2bbbSRüdiger Timm     if ( p )
3714f5dd4faeSMike Kaganski         GetItemSet().Put( *p );
3715fd069beeSJens-Heiner Rechtien }
371655eaa949SMathias Bauer 
37170ce0c369SAlexander Wilms 
SfxMedium(const uno::Reference<embed::XStorage> & rStor,const OUString & rBaseURL,const OUString & rTypeName,const std::shared_ptr<SfxItemSet> & p)3718cc4dbe47SNoel Grandin SfxMedium::SfxMedium( const uno::Reference < embed::XStorage >& rStor, const OUString& rBaseURL, const OUString &rTypeName, const std::shared_ptr<SfxItemSet>& p ) :
37195e32815aSXisco Fauli     pImpl(new SfxMedium_Impl)
3720caaeb0a0SMichael Meeks {
37215e32815aSXisco Fauli     pImpl->m_pFilter = SfxGetpApp()->GetFilterMatcher().GetFilter4EA( rTypeName );
37225e32815aSXisco Fauli     DBG_ASSERT( pImpl->m_pFilter, "No Filter for storage found!" );
3723caaeb0a0SMichael Meeks 
3724caaeb0a0SMichael Meeks     Init_Impl();
37255e32815aSXisco Fauli     pImpl->xStorage = rStor;
37265e32815aSXisco Fauli     pImpl->bDisposeStorage = false;
3727caaeb0a0SMichael Meeks 
3728caaeb0a0SMichael Meeks     // always take BaseURL first, could be overwritten by ItemSet
3729f5dd4faeSMike Kaganski     GetItemSet().Put( SfxStringItem( SID_DOC_BASEURL, rBaseURL ) );
3730caaeb0a0SMichael Meeks     if ( p )
3731f5dd4faeSMike Kaganski         GetItemSet().Put( *p );
3732caaeb0a0SMichael Meeks }
3733caaeb0a0SMichael Meeks 
373495eb0888SMatt K // NOTE: should only be called on main thread
~SfxMedium()3735fd069beeSJens-Heiner Rechtien SfxMedium::~SfxMedium()
3736fd069beeSJens-Heiner Rechtien {
373795eb0888SMatt K     CancelCheckEditableEntry();
373895eb0888SMatt K 
3739135171a9SRüdiger Timm     // if there is a requirement to clean the backup this is the last possibility to do it
3740135171a9SRüdiger Timm     ClearBackup_Impl();
3741135171a9SRüdiger Timm 
3742c0d372d7SNoel Grandin     Close(/*bInDestruction*/true);
3743fd069beeSJens-Heiner Rechtien 
3744c77a5343SMike Kaganski     ReleaseEmbeddedFonts();
3745c77a5343SMike Kaganski 
3746536a6d6cSNoel Grandin     if( !pImpl->bIsTemp || pImpl->m_aName.isEmpty() )
3747536a6d6cSNoel Grandin         return;
3748536a6d6cSNoel Grandin 
37491946794aSLuboš Luňák     OUString aTemp;
37505e32815aSXisco Fauli     if ( osl::FileBase::getFileURLFromSystemPath( pImpl->m_aName, aTemp )
3751236714e8SStephan Bergmann          != osl::FileBase::E_None )
375285cd316fSOliver Bolte     {
3753d38cb53eSMichael Stahl         SAL_WARN( "sfx.doc", "Physical name not convertible!");
375485cd316fSOliver Bolte     }
37556a3ede4dSMathias Bauer 
3756fc3a7d9cSMathias Bauer     if ( !::utl::UCBContentHelper::Kill( aTemp ) )
375785cd316fSOliver Bolte     {
3758d38cb53eSMichael Stahl         SAL_WARN( "sfx.doc", "Couldn't remove temporary file!");
3759fd069beeSJens-Heiner Rechtien     }
376085cd316fSOliver Bolte }
3761fd069beeSJens-Heiner Rechtien 
ReleaseEmbeddedFonts()3762c77a5343SMike Kaganski void SfxMedium::ReleaseEmbeddedFonts()
3763c77a5343SMike Kaganski {
3764c77a5343SMike Kaganski     std::vector<std::pair<OUString, OUString>> toRelease(std::move(pImpl->m_aEmbeddedFonts));
3765c77a5343SMike Kaganski     toRelease.insert(toRelease.end(), pImpl->m_aEmbeddedFontsToActivate.begin(),
3766c77a5343SMike Kaganski                      pImpl->m_aEmbeddedFontsToActivate.end());
3767c77a5343SMike Kaganski     pImpl->m_aEmbeddedFontsToActivate.clear();
3768e8d0ab58SMike Kaganski     EmbeddedFontsManager::releaseFonts(toRelease);
3769c77a5343SMike Kaganski }
3770c77a5343SMike Kaganski 
GetName() const3771d1cc0071SKohei Yoshida const OUString& SfxMedium::GetName() const
3772d1cc0071SKohei Yoshida {
37735e32815aSXisco Fauli     return pImpl->m_aLogicName;
3774d1cc0071SKohei Yoshida }
3775d1cc0071SKohei Yoshida 
GetURLObject() const3776fd069beeSJens-Heiner Rechtien const INetURLObject& SfxMedium::GetURLObject() const
3777fd069beeSJens-Heiner Rechtien {
377895eb0888SMatt K     std::unique_lock<std::recursive_mutex> chkEditLock;
377995eb0888SMatt K     if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
378095eb0888SMatt K         chkEditLock = std::unique_lock<std::recursive_mutex>(*(pImpl->m_pCheckEditableWorkerMutex));
378195eb0888SMatt K 
37825e32815aSXisco Fauli     if (!pImpl->m_pURLObj)
3783fd069beeSJens-Heiner Rechtien     {
3784e4c40331SNoel Grandin         pImpl->m_pURLObj.reset( new INetURLObject( pImpl->m_aLogicName ) );
378539c3574bSNoel Grandin         pImpl->m_pURLObj->SetMark(u"");
3786fd069beeSJens-Heiner Rechtien     }
3787cc90d18bSMathias Bauer 
37885e32815aSXisco Fauli     return *pImpl->m_pURLObj;
3789fd069beeSJens-Heiner Rechtien }
3790cc90d18bSMathias Bauer 
SetExpired_Impl(const DateTime & rDateTime)3791fd069beeSJens-Heiner Rechtien void SfxMedium::SetExpired_Impl( const DateTime& rDateTime )
3792fd069beeSJens-Heiner Rechtien {
37935e32815aSXisco Fauli     pImpl->aExpireTime = rDateTime;
3794fd069beeSJens-Heiner Rechtien }
37950ce0c369SAlexander Wilms 
3796fd069beeSJens-Heiner Rechtien 
IsExpired() const37975fe7ecc0SNoel Grandin bool SfxMedium::IsExpired() const
3798fd069beeSJens-Heiner Rechtien {
37995e32815aSXisco Fauli     return pImpl->aExpireTime.IsValidAndGregorian() && pImpl->aExpireTime < DateTime( DateTime::SYSTEM );
3800fd069beeSJens-Heiner Rechtien }
38010ce0c369SAlexander Wilms 
3802fd069beeSJens-Heiner Rechtien 
GetLoadTargetFrame() const3803fd069beeSJens-Heiner Rechtien SfxFrame* SfxMedium::GetLoadTargetFrame() const
3804fd069beeSJens-Heiner Rechtien {
38055e32815aSXisco Fauli     return pImpl->wLoadTargetFrame;
3806fd069beeSJens-Heiner Rechtien }
38071e355662SKohei Yoshida 
setStreamToLoadFrom(const css::uno::Reference<css::io::XInputStream> & xInputStream,bool bIsReadOnly)3808913a2d36SNoel Grandin void SfxMedium::setStreamToLoadFrom(const css::uno::Reference<css::io::XInputStream>& xInputStream, bool bIsReadOnly )
38091e355662SKohei Yoshida {
38105e32815aSXisco Fauli     pImpl->m_xInputStreamToLoadFrom = xInputStream;
38115e32815aSXisco Fauli     pImpl->m_bInputStreamIsReadOnly = bIsReadOnly;
38121e355662SKohei Yoshida }
3813fd069beeSJens-Heiner Rechtien 
SetLoadTargetFrame(SfxFrame * pFrame)3814fd069beeSJens-Heiner Rechtien void SfxMedium::SetLoadTargetFrame(SfxFrame* pFrame )
3815fd069beeSJens-Heiner Rechtien {
38165e32815aSXisco Fauli     pImpl->wLoadTargetFrame = pFrame;
3817fd069beeSJens-Heiner Rechtien }
38180ce0c369SAlexander Wilms 
SetStorage_Impl(const uno::Reference<embed::XStorage> & xStorage)38193b347664SMichael Stahl void SfxMedium::SetStorage_Impl(const uno::Reference<embed::XStorage>& xStorage)
3820fd069beeSJens-Heiner Rechtien {
38213b347664SMichael Stahl     pImpl->xStorage = xStorage;
38223b347664SMichael Stahl     pImpl->m_bODFWholesomeEncryption = false;
3823fd069beeSJens-Heiner Rechtien }
38240ce0c369SAlexander Wilms 
SetInnerStorage_Impl(const uno::Reference<embed::XStorage> & xStorage)38253b347664SMichael Stahl void SfxMedium::SetInnerStorage_Impl(const uno::Reference<embed::XStorage>& xStorage)
38263b347664SMichael Stahl {
38273b347664SMichael Stahl     pImpl->xStorage = xStorage;
38283b347664SMichael Stahl     pImpl->m_bODFWholesomeEncryption = true;
38293b347664SMichael Stahl }
3830fd069beeSJens-Heiner Rechtien 
GetItemSet() const3831f5dd4faeSMike Kaganski SfxItemSet& SfxMedium::GetItemSet() const
3832fd069beeSJens-Heiner Rechtien {
38335e32815aSXisco Fauli     if (!pImpl->m_pSet)
3834a5e25556SNoel Grandin         pImpl->m_pSet = std::make_shared<SfxAllItemSet>( SfxGetpApp()->GetPool() );
3835f5dd4faeSMike Kaganski     return *pImpl->m_pSet;
3836fd069beeSJens-Heiner Rechtien }
38370ce0c369SAlexander Wilms 
3838fd069beeSJens-Heiner Rechtien 
GetHeaderAttributes_Impl()3839fd069beeSJens-Heiner Rechtien SvKeyValueIterator* SfxMedium::GetHeaderAttributes_Impl()
3840fd069beeSJens-Heiner Rechtien {
384149783285SNoel Grandin     if( !pImpl->xAttributes.is() )
38425be98ebaSJens-Heiner Rechtien     {
38435e32815aSXisco Fauli         pImpl->xAttributes = SvKeyValueIteratorRef( new SvKeyValueIterator );
38445be98ebaSJens-Heiner Rechtien 
38455be98ebaSJens-Heiner Rechtien         if ( GetContent().is() )
38465be98ebaSJens-Heiner Rechtien         {
38475be98ebaSJens-Heiner Rechtien             try
38485be98ebaSJens-Heiner Rechtien             {
3849ca5c9591SNoel Grandin                 Any aAny = pImpl->aContent.getPropertyValue(u"MediaType"_ustr);
38501946794aSLuboš Luňák                 OUString aContentType;
38515be98ebaSJens-Heiner Rechtien                 aAny >>= aContentType;
38525be98ebaSJens-Heiner Rechtien 
3853ca5c9591SNoel Grandin                 pImpl->xAttributes->Append( SvKeyValue( u"content-type"_ustr, aContentType ) );
38545be98ebaSJens-Heiner Rechtien             }
3855913a2d36SNoel Grandin             catch ( const css::uno::Exception& )
38565be98ebaSJens-Heiner Rechtien             {
38575be98ebaSJens-Heiner Rechtien             }
38585be98ebaSJens-Heiner Rechtien         }
38595be98ebaSJens-Heiner Rechtien     }
3860fd069beeSJens-Heiner Rechtien 
3861f004aa99SJacek Fraczek     return pImpl->xAttributes.get();
3862fd069beeSJens-Heiner Rechtien }
3863fd069beeSJens-Heiner Rechtien 
GetInputStream()3864a967c8f6SNoel Grandin css::uno::Reference< css::io::XInputStream > const &  SfxMedium::GetInputStream()
38659df731d6SMathias Bauer {
38665e32815aSXisco Fauli     if ( !pImpl->xInputStream.is() )
38679d170b09SMikhail Voitenko         GetMedium_Impl();
38685e32815aSXisco Fauli     return pImpl->xInputStream;
3869fd069beeSJens-Heiner Rechtien }
3870fd069beeSJens-Heiner Rechtien 
GetVersionList(bool _bNoReload)3871ce68ab34SIvo Hinkelmann const uno::Sequence < util::RevisionTag >& SfxMedium::GetVersionList( bool _bNoReload )
3872fd069beeSJens-Heiner Rechtien {
38738bce1a66SKurt Zenker     // if the medium has no name, then this medium should represent a new document and can have no version info
387425b200ffSArkadiy Illarionov     if ( ( !_bNoReload || !pImpl->m_bVersionsAlreadyLoaded ) && !pImpl->aVersions.hasElements() &&
38755e32815aSXisco Fauli          ( !pImpl->m_aName.isEmpty() || !pImpl->m_aLogicName.isEmpty() ) && GetStorage().is() )
3876fd069beeSJens-Heiner Rechtien     {
38778c31a6baSNoel Grandin         uno::Reference < document::XDocumentRevisionListPersistence > xReader =
38788c31a6baSNoel Grandin                 document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3879762dd2b1SKurt Zenker         try
3880fd069beeSJens-Heiner Rechtien         {
38815e32815aSXisco Fauli             pImpl->aVersions = xReader->load( GetStorage() );
3882322c7db2SDirk Völzke         }
38836c89e69bSCaolán McNamara         catch ( const uno::Exception& )
3884762dd2b1SKurt Zenker         {
3885b5181a5eSVladimir Glazounov         }
3886762dd2b1SKurt Zenker     }
3887fd069beeSJens-Heiner Rechtien 
38885e32815aSXisco Fauli     if ( !pImpl->m_bVersionsAlreadyLoaded )
38895e32815aSXisco Fauli         pImpl->m_bVersionsAlreadyLoaded = true;
3890ce68ab34SIvo Hinkelmann 
38915e32815aSXisco Fauli     return pImpl->aVersions;
3892fd069beeSJens-Heiner Rechtien }
3893fd069beeSJens-Heiner Rechtien 
GetVersionList(const uno::Reference<embed::XStorage> & xStorage)3894b5181a5eSVladimir Glazounov uno::Sequence < util::RevisionTag > SfxMedium::GetVersionList( const uno::Reference < embed::XStorage >& xStorage )
389523070c9fSMikhail Voitenko {
38968c31a6baSNoel Grandin     uno::Reference < document::XDocumentRevisionListPersistence > xReader =
38978c31a6baSNoel Grandin         document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3898b5181a5eSVladimir Glazounov     try
3899b5181a5eSVladimir Glazounov     {
3900b5181a5eSVladimir Glazounov         return xReader->load( xStorage );
3901b5181a5eSVladimir Glazounov     }
39026c89e69bSCaolán McNamara     catch ( const uno::Exception& )
3903b5181a5eSVladimir Glazounov     {
3904b5181a5eSVladimir Glazounov     }
390523070c9fSMikhail Voitenko 
3906b5181a5eSVladimir Glazounov     return uno::Sequence < util::RevisionTag >();
390723070c9fSMikhail Voitenko }
390823070c9fSMikhail Voitenko 
AddVersion_Impl(util::RevisionTag & rRevision)390938c23520SNoel Grandin void SfxMedium::AddVersion_Impl( util::RevisionTag& rRevision )
3910fd069beeSJens-Heiner Rechtien {
3911536a6d6cSNoel Grandin     if ( !GetStorage().is() )
3912536a6d6cSNoel Grandin         return;
3913536a6d6cSNoel Grandin 
3914dcd5dee8SAlbert Thuswaldner     // To determine a unique name for the stream
3915ef01fae2SMaciej Rumianowski     std::vector<sal_uInt32> aLongs;
39165e32815aSXisco Fauli     sal_Int32 nLength = pImpl->aVersions.getLength();
39170fa827dbSMike Kaganski     for (const auto& rVersion : pImpl->aVersions)
3918fd069beeSJens-Heiner Rechtien     {
39193e767973SNoel Grandin         sal_uInt32 nVer = static_cast<sal_uInt32>( o3tl::toInt32(rVersion.Identifier.subView(7)));
3920ef01fae2SMaciej Rumianowski         size_t n;
3921ef01fae2SMaciej Rumianowski         for ( n=0; n<aLongs.size(); ++n )
3922fd069beeSJens-Heiner Rechtien             if ( nVer<aLongs[n] )
3923fd069beeSJens-Heiner Rechtien                 break;
3924fd069beeSJens-Heiner Rechtien 
3925ef01fae2SMaciej Rumianowski         aLongs.insert( aLongs.begin()+n, nVer );
3926fd069beeSJens-Heiner Rechtien     }
3927fd069beeSJens-Heiner Rechtien 
39286271381bSStephan Bergmann     std::vector<sal_uInt32>::size_type nKey;
3929ef01fae2SMaciej Rumianowski     for ( nKey=0; nKey<aLongs.size(); ++nKey )
39306271381bSStephan Bergmann         if ( aLongs[nKey] > nKey+1 )
3931fd069beeSJens-Heiner Rechtien             break;
3932fd069beeSJens-Heiner Rechtien 
3933fdb37b71SCaolán McNamara     rRevision.Identifier = "Version" + OUString::number( nKey + 1 );
39345e32815aSXisco Fauli     pImpl->aVersions.realloc( nLength+1 );
3935ce22935aSMike Kaganski     pImpl->aVersions.getArray()[nLength] = rRevision;
393638c23520SNoel Grandin }
3937fd069beeSJens-Heiner Rechtien 
RemoveVersion_Impl(const OUString & rName)393838c23520SNoel Grandin void SfxMedium::RemoveVersion_Impl( const OUString& rName )
3939fd069beeSJens-Heiner Rechtien {
394025b200ffSArkadiy Illarionov     if ( !pImpl->aVersions.hasElements() )
394138c23520SNoel Grandin         return;
3942fd069beeSJens-Heiner Rechtien 
39438a017d25SMike Kaganski     auto pVersion = std::find_if(std::cbegin(pImpl->aVersions), std::cend(pImpl->aVersions),
394425b200ffSArkadiy Illarionov         [&rName](const auto& rVersion) { return rVersion.Identifier == rName; });
39458a017d25SMike Kaganski     if (pVersion != std::cend(pImpl->aVersions))
3946fd069beeSJens-Heiner Rechtien     {
39478a017d25SMike Kaganski         auto nIndex = static_cast<sal_Int32>(std::distance(std::cbegin(pImpl->aVersions), pVersion));
394825b200ffSArkadiy Illarionov         comphelper::removeElementAt(pImpl->aVersions, nIndex);
3949fd069beeSJens-Heiner Rechtien     }
3950fd069beeSJens-Heiner Rechtien }
3951fd069beeSJens-Heiner Rechtien 
TransferVersionList_Impl(SfxMedium const & rMedium)39527ed17807SNoel Grandin bool SfxMedium::TransferVersionList_Impl( SfxMedium const & rMedium )
3953fd069beeSJens-Heiner Rechtien {
395425b200ffSArkadiy Illarionov     if ( rMedium.pImpl->aVersions.hasElements() )
3955fd069beeSJens-Heiner Rechtien     {
39565e32815aSXisco Fauli         pImpl->aVersions = rMedium.pImpl->aVersions;
3957df8a15d8SKohei Yoshida         return true;
3958fd069beeSJens-Heiner Rechtien     }
3959fd069beeSJens-Heiner Rechtien 
3960df8a15d8SKohei Yoshida     return false;
3961fd069beeSJens-Heiner Rechtien }
3962fd069beeSJens-Heiner Rechtien 
SaveVersionList_Impl()3963435d6d50SNoel Grandin void SfxMedium::SaveVersionList_Impl()
3964fd069beeSJens-Heiner Rechtien {
3965536a6d6cSNoel Grandin     if ( !GetStorage().is() )
3966536a6d6cSNoel Grandin         return;
3967536a6d6cSNoel Grandin 
396825b200ffSArkadiy Illarionov     if ( !pImpl->aVersions.hasElements() )
396938c23520SNoel Grandin         return;
3970fd069beeSJens-Heiner Rechtien 
39718c31a6baSNoel Grandin     uno::Reference < document::XDocumentRevisionListPersistence > xWriter =
39728c31a6baSNoel Grandin              document::DocumentRevisionListPersistence::create( comphelper::getProcessComponentContext() );
3973b5181a5eSVladimir Glazounov     try
3974b5181a5eSVladimir Glazounov     {
39755e32815aSXisco Fauli         xWriter->store( GetStorage(), pImpl->aVersions );
3976322c7db2SDirk Völzke     }
39776c89e69bSCaolán McNamara     catch ( const uno::Exception& )
3978322c7db2SDirk Völzke     {
3979fd069beeSJens-Heiner Rechtien     }
3980fd069beeSJens-Heiner Rechtien }
3981fd069beeSJens-Heiner Rechtien 
IsReadOnly() const39826832d9f0SCaolán McNamara bool SfxMedium::IsReadOnly() const
3983fd069beeSJens-Heiner Rechtien {
398421bba18bSMike Kaganski     // Application-wide read-only mode first
398521bba18bSMike Kaganski     if (officecfg::Office::Common::Misc::ViewerAppMode::get())
398621bba18bSMike Kaganski         return true;
398721bba18bSMike Kaganski 
3988728ec860STor Lillqvist     // a) ReadOnly filter can't produce read/write contents!
39895e32815aSXisco Fauli     bool bReadOnly = pImpl->m_pFilter && (pImpl->m_pFilter->GetFilterFlags() & SfxFilterFlags::OPENREADONLY);
3990c8443d12SKurt Zenker 
3991c8443d12SKurt Zenker     // b) if filter allow read/write contents .. check open mode of the storage
3992c8443d12SKurt Zenker     if (!bReadOnly)
39937f8f277bSNoel Grandin         bReadOnly = !( GetOpenMode() & StreamMode::WRITE );
3994c8443d12SKurt Zenker 
3995c8443d12SKurt Zenker     // c) the API can force the readonly state!
3996fd069beeSJens-Heiner Rechtien     if (!bReadOnly)
3997fd069beeSJens-Heiner Rechtien     {
3998f5dd4faeSMike Kaganski         const SfxBoolItem* pItem = GetItemSet().GetItem(SID_DOC_READONLY, false);
3999fd069beeSJens-Heiner Rechtien         if (pItem)
4000fd069beeSJens-Heiner Rechtien             bReadOnly = pItem->GetValue();
4001fd069beeSJens-Heiner Rechtien     }
4002fd069beeSJens-Heiner Rechtien 
4003fdd24dabSMike Kaganski     // d) Embedded fonts may disallow editing
4004fdd24dabSMike Kaganski     if (!bReadOnly)
4005fdd24dabSMike Kaganski         bReadOnly = HasRestrictedFonts();
4006fdd24dabSMike Kaganski 
4007fd069beeSJens-Heiner Rechtien     return bReadOnly;
4008fd069beeSJens-Heiner Rechtien }
4009fd069beeSJens-Heiner Rechtien 
IsOriginallyReadOnly() const4010b9ecec7cSStephan Bergmann bool SfxMedium::IsOriginallyReadOnly() const
4011b9ecec7cSStephan Bergmann {
40125e32815aSXisco Fauli     return pImpl->m_bOriginallyReadOnly;
4013b9ecec7cSStephan Bergmann }
4014b9ecec7cSStephan Bergmann 
SetOriginallyReadOnly(bool val)401595eb0888SMatt K void SfxMedium::SetOriginallyReadOnly(bool val)
401695eb0888SMatt K {
401795eb0888SMatt K     pImpl->m_bOriginallyReadOnly = val;
401895eb0888SMatt K }
401995eb0888SMatt K 
IsOriginallyLoadedReadOnly() const4020191c0a9eSStephan Bergmann bool SfxMedium::IsOriginallyLoadedReadOnly() const
4021191c0a9eSStephan Bergmann {
4022191c0a9eSStephan Bergmann     return pImpl->m_bOriginallyLoadedReadOnly;
4023191c0a9eSStephan Bergmann }
40240ce0c369SAlexander Wilms 
HasRestrictedFonts() const4025fdd24dabSMike Kaganski bool SfxMedium::HasRestrictedFonts() const { return pImpl->hasRestrictedFonts; }
4026fdd24dabSMike Kaganski 
TransferEmbeddedFontsTo(SfxMedium & target)4027c77a5343SMike Kaganski void SfxMedium::TransferEmbeddedFontsTo(SfxMedium& target)
4028c77a5343SMike Kaganski {
4029fdd24dabSMike Kaganski     target.pImpl->hasRestrictedFonts = target.pImpl->hasRestrictedFonts || pImpl->hasRestrictedFonts;
4030c77a5343SMike Kaganski     target.pImpl->m_aEmbeddedFonts.insert(target.pImpl->m_aEmbeddedFonts.end(),
4031c77a5343SMike Kaganski                                           pImpl->m_aEmbeddedFonts.begin(),
4032c77a5343SMike Kaganski                                           pImpl->m_aEmbeddedFonts.end());
4033c77a5343SMike Kaganski     pImpl->m_aEmbeddedFonts.clear();
4034c77a5343SMike Kaganski     target.pImpl->m_aEmbeddedFontsToActivate.insert(target.pImpl->m_aEmbeddedFontsToActivate.end(),
4035c77a5343SMike Kaganski                                                     pImpl->m_aEmbeddedFontsToActivate.begin(),
4036c77a5343SMike Kaganski                                                     pImpl->m_aEmbeddedFontsToActivate.end());
4037c77a5343SMike Kaganski     pImpl->m_aEmbeddedFontsToActivate.clear();
4038c77a5343SMike Kaganski }
4039c77a5343SMike Kaganski 
AddEmbeddedFonts(const css::uno::Sequence<css::beans::StringPair> & fonts)4040badc9c68SMike Kaganski void SfxMedium::AddEmbeddedFonts(
4041badc9c68SMike Kaganski     const css::uno::Sequence<css::beans::StringPair>& fonts)
4042badc9c68SMike Kaganski {
4043badc9c68SMike Kaganski     for (const auto& [ name, url ] : fonts)
4044badc9c68SMike Kaganski         pImpl->m_aEmbeddedFontsToActivate.emplace_back(name, url);
4045badc9c68SMike Kaganski }
4046badc9c68SMike Kaganski 
activateEmbeddedFonts()4047badc9c68SMike Kaganski void SfxMedium::activateEmbeddedFonts()
4048badc9c68SMike Kaganski {
4049fdd24dabSMike Kaganski     bool bActivatedRestrictedFonts;
4050fdd24dabSMike Kaganski     EmbeddedFontsManager::activateFonts(pImpl->m_aEmbeddedFontsToActivate, IsReadOnly(),
4051fdd24dabSMike Kaganski                                        GetInteractionHandler(), bActivatedRestrictedFonts);
4052fdd24dabSMike Kaganski     pImpl->hasRestrictedFonts = pImpl->hasRestrictedFonts || bActivatedRestrictedFonts;
4053c77a5343SMike Kaganski     pImpl->m_aEmbeddedFonts.insert(pImpl->m_aEmbeddedFonts.end(),
4054c77a5343SMike Kaganski                                    pImpl->m_aEmbeddedFontsToActivate.begin(),
4055c77a5343SMike Kaganski                                    pImpl->m_aEmbeddedFontsToActivate.end());
4056c77a5343SMike Kaganski     pImpl->m_aEmbeddedFontsToActivate.clear();
4057badc9c68SMike Kaganski }
4058badc9c68SMike Kaganski 
SetWritableForUserOnly(const OUString & aURL)40595fe7ecc0SNoel Grandin bool SfxMedium::SetWritableForUserOnly( const OUString& aURL )
40605be98ebaSJens-Heiner Rechtien {
4061ac49eeddSIvo Hinkelmann     // UCB does not allow to allow write access only for the user,
4062ac49eeddSIvo Hinkelmann     // use osl API
406350b4cbe9SKohei Yoshida     bool bResult = false;
40645be98ebaSJens-Heiner Rechtien 
4065ac49eeddSIvo Hinkelmann     ::osl::DirectoryItem aDirItem;
4066ac49eeddSIvo Hinkelmann     if ( ::osl::DirectoryItem::get( aURL, aDirItem ) == ::osl::FileBase::E_None )
40675be98ebaSJens-Heiner Rechtien     {
4068b0b3e5fdSChristina Rossmanith         ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_Attributes );
4069ac49eeddSIvo Hinkelmann         if ( aDirItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None
4070b0b3e5fdSChristina Rossmanith           && aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) )
40715be98ebaSJens-Heiner Rechtien         {
4072ac49eeddSIvo Hinkelmann             sal_uInt64 nAttributes = aFileStatus.getAttributes();
40735be98ebaSJens-Heiner Rechtien 
40749cc6dfd9SChristina Rossmanith             nAttributes &= ~(osl_File_Attribute_OwnWrite |
40759cc6dfd9SChristina Rossmanith                              osl_File_Attribute_GrpWrite |
40769cc6dfd9SChristina Rossmanith                              osl_File_Attribute_OthWrite |
40779cc6dfd9SChristina Rossmanith                              osl_File_Attribute_ReadOnly);
407883bbcbcfSMuthu Subramanian             nAttributes |=  (osl_File_Attribute_OwnWrite |
407983bbcbcfSMuthu Subramanian                              osl_File_Attribute_OwnRead);
40805be98ebaSJens-Heiner Rechtien 
4081ac49eeddSIvo Hinkelmann             bResult = ( osl::File::setAttributes( aURL, nAttributes ) == ::osl::FileBase::E_None );
40825be98ebaSJens-Heiner Rechtien         }
40835be98ebaSJens-Heiner Rechtien     }
4084537027d2SOliver Bolte 
4085ac49eeddSIvo Hinkelmann     return bResult;
40865be98ebaSJens-Heiner Rechtien }
40875be98ebaSJens-Heiner Rechtien 
408827938e1bSMiklos Vajna namespace
408927938e1bSMiklos Vajna {
409027938e1bSMiklos Vajna /// Get the parent directory of a temporary file for output purposes.
GetLogicBase(const INetURLObject & rURL,std::unique_ptr<SfxMedium_Impl> const & pImpl)4091aaf7fe03SMiklos Vajna OUString GetLogicBase(const INetURLObject& rURL, std::unique_ptr<SfxMedium_Impl> const & pImpl)
409227938e1bSMiklos Vajna {
409327938e1bSMiklos Vajna     OUString aLogicBase;
409427938e1bSMiklos Vajna 
4095d8c92ff3STor Lillqvist #if HAVE_FEATURE_MACOSX_SANDBOX
409654c2e3c8STor Lillqvist     // In a sandboxed environment we don't want to attempt to create temporary files in the same
409754c2e3c8STor Lillqvist     // directory where the user has selected an output file to be stored. The sandboxed process has
409854c2e3c8STor Lillqvist     // permission only to create the specifically named output file in that directory.
40996fd24eaaSTor Lillqvist     (void) rURL;
4100d8c92ff3STor Lillqvist     (void) pImpl;
4101d8c92ff3STor Lillqvist #else
4102cf616121SSamuel Mehrbrodt     if (!officecfg::Office::Common::Misc::TempFileNextToLocalFile::get())
4103cf616121SSamuel Mehrbrodt         return aLogicBase;
410454c2e3c8STor Lillqvist 
41057cb59a86SMike Kaganski     if (!pImpl->m_bHasEmbeddedObjects // Embedded objects would mean a special base, ignore that.
41067cb59a86SMike Kaganski         && rURL.GetProtocol() == INetProtocol::File && !pImpl->m_pInStream)
410727938e1bSMiklos Vajna     {
410827938e1bSMiklos Vajna         // Try to create the temp file in the same directory when storing.
4109aaf7fe03SMiklos Vajna         INetURLObject aURL(rURL);
4110aaf7fe03SMiklos Vajna         aURL.removeSegment();
4111aaf7fe03SMiklos Vajna         aLogicBase = aURL.GetMainURL(INetURLObject::DecodeMechanism::WithCharset);
411227938e1bSMiklos Vajna     }
411327938e1bSMiklos Vajna 
411454c2e3c8STor Lillqvist #endif // !HAVE_FEATURE_MACOSX_SANDBOX
411554c2e3c8STor Lillqvist 
411627938e1bSMiklos Vajna     return aLogicBase;
411727938e1bSMiklos Vajna }
411827938e1bSMiklos Vajna }
41190ce0c369SAlexander Wilms 
CreateTempFile(bool bReplace)41205fe7ecc0SNoel Grandin void SfxMedium::CreateTempFile( bool bReplace )
4121fd069beeSJens-Heiner Rechtien {
41225e32815aSXisco Fauli     if ( pImpl->pTempFile )
4123b847cc0bSOliver Bolte     {
4124ac49eeddSIvo Hinkelmann         if ( !bReplace )
4125ac49eeddSIvo Hinkelmann             return;
4126ac49eeddSIvo Hinkelmann 
4127e4c40331SNoel Grandin         pImpl->pTempFile.reset();
41285e32815aSXisco Fauli         pImpl->m_aName.clear();
4129b847cc0bSOliver Bolte     }
41306f2dfafcSMathias Bauer 
4131aaf7fe03SMiklos Vajna     OUString aLogicBase = GetLogicBase(GetURLObject(), pImpl);
41324a5ab800SMichael Meeks     pImpl->pTempFile.reset(new MediumTempFile(&aLogicBase));
41335441ed51SJustin Luth     if (!aLogicBase.isEmpty() && pImpl->pTempFile->GetFileName().isEmpty())
41344a5ab800SMichael Meeks         pImpl->pTempFile.reset(new MediumTempFile(nullptr));
41355e32815aSXisco Fauli     pImpl->pTempFile->EnableKillingFile();
41365e32815aSXisco Fauli     pImpl->m_aName = pImpl->pTempFile->GetFileName();
41375e32815aSXisco Fauli     OUString aTmpURL = pImpl->pTempFile->GetURL();
41385e32815aSXisco Fauli     if ( pImpl->m_aName.isEmpty() || aTmpURL.isEmpty() )
4139aadbfeffSMathias Bauer     {
41409e4d84daSCaolán McNamara         SetError(ERRCODE_IO_CANTWRITE);
4141aadbfeffSMathias Bauer         return;
4142aadbfeffSMathias Bauer     }
4143fd069beeSJens-Heiner Rechtien 
41445e32815aSXisco Fauli     if ( !(pImpl->m_nStorOpenMode & StreamMode::TRUNC) )
4145ffdab958SMathias Bauer     {
414650b4cbe9SKohei Yoshida         bool bTransferSuccess = false;
41473ff6fe7aSMikhail Voitenko 
4148ac49eeddSIvo Hinkelmann         if ( GetContent().is()
41496d64afb3SStephan Bergmann           && GetURLObject().GetProtocol() == INetProtocol::File
4150bfde4866SNoel Grandin           && ::utl::UCBContentHelper::IsDocument( GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
4151ac49eeddSIvo Hinkelmann         {
4152ac49eeddSIvo Hinkelmann             // if there is already such a document, we should copy it
4153ac49eeddSIvo Hinkelmann             // if it is a file system use OS copy process
4154ac49eeddSIvo Hinkelmann             try
4155ac49eeddSIvo Hinkelmann             {
4156913a2d36SNoel Grandin                 uno::Reference< css::ucb::XCommandEnvironment > xComEnv;
4157ac49eeddSIvo Hinkelmann                 INetURLObject aTmpURLObj( aTmpURL );
41581946794aSLuboš Luňák                 OUString aFileName = aTmpURLObj.getName( INetURLObject::LAST_SEGMENT,
4159ac49eeddSIvo Hinkelmann                                                                 true,
4160bfde4866SNoel Grandin                                                                 INetURLObject::DecodeMechanism::WithCharset );
4161e24a27b4SOlivier Hallot                 if ( !aFileName.isEmpty() && aTmpURLObj.removeSegment() )
4162ac49eeddSIvo Hinkelmann                 {
4163bfde4866SNoel Grandin                     ::ucbhelper::Content aTargetContent( aTmpURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xComEnv, comphelper::getProcessComponentContext() );
41645e32815aSXisco Fauli                     OUString sMimeType = pImpl->getFilterMimeType();
416553491f8aSNoel Grandin                     aTargetContent.transferContent( pImpl->aContent, ::ucbhelper::InsertOperation::Copy, aFileName, NameClash::OVERWRITE, sMimeType );
4166ac49eeddSIvo Hinkelmann                     SetWritableForUserOnly( aTmpURL );
4167df8a15d8SKohei Yoshida                     bTransferSuccess = true;
4168ac49eeddSIvo Hinkelmann                 }
4169ac49eeddSIvo Hinkelmann             }
41706c89e69bSCaolán McNamara             catch( const uno::Exception& )
4171ac49eeddSIvo Hinkelmann             {}
4172ac49eeddSIvo Hinkelmann 
41733ff6fe7aSMikhail Voitenko             if ( bTransferSuccess )
4174ac49eeddSIvo Hinkelmann             {
4175ac49eeddSIvo Hinkelmann                 CloseOutStream();
4176ac49eeddSIvo Hinkelmann                 CloseInStream();
4177ac49eeddSIvo Hinkelmann             }
41783ff6fe7aSMikhail Voitenko         }
41793ff6fe7aSMikhail Voitenko 
41805e32815aSXisco Fauli         if ( !bTransferSuccess && pImpl->m_pInStream )
4181ac49eeddSIvo Hinkelmann         {
418264d624b6SAndrea Gelmini             // the case when there is no URL-access available or this is a remote protocol
4183ac49eeddSIvo Hinkelmann             // but there is an input stream
41846f2dfafcSMathias Bauer             GetOutStream();
41855e32815aSXisco Fauli             if ( pImpl->m_pOutStream )
41866f2dfafcSMathias Bauer             {
4187146f98e7SNoel Grandin                 std::unique_ptr<char[]> pBuf(new char [8192]);
418852863266SNoel Grandin                 ErrCode      nErr = ERRCODE_NONE;
4189b584c336SDirk Völzke 
41905e32815aSXisco Fauli                 pImpl->m_pInStream->Seek(0);
41915e32815aSXisco Fauli                 pImpl->m_pOutStream->Seek(0);
4192b584c336SDirk Völzke 
41932161d046SCaolán McNamara                 while( !pImpl->m_pInStream->eof() && nErr == ERRCODE_NONE )
4194b584c336SDirk Völzke                 {
4195146f98e7SNoel Grandin                     sal_uInt32 nRead = pImpl->m_pInStream->ReadBytes(pBuf.get(), 8192);
41965e32815aSXisco Fauli                     nErr = pImpl->m_pInStream->GetError();
4197146f98e7SNoel Grandin                     pImpl->m_pOutStream->WriteBytes( pBuf.get(), nRead );
41986f2dfafcSMathias Bauer                 }
41996f2dfafcSMathias Bauer 
4200df8a15d8SKohei Yoshida                 bTransferSuccess = true;
4201b584c336SDirk Völzke                 CloseInStream();
4202b584c336SDirk Völzke             }
4203fd069beeSJens-Heiner Rechtien             CloseOutStream_Impl();
4204ffdab958SMathias Bauer         }
4205ffdab958SMathias Bauer         else
420604a4f6ceSMikhail Voitenko         {
420704a4f6ceSMikhail Voitenko             // Quite strange design, but currently it is expected that in this case no transfer happens
420804a4f6ceSMikhail Voitenko             // TODO/LATER: get rid of this inconsistent part of the call design
4209df8a15d8SKohei Yoshida             bTransferSuccess = true;
4210ffdab958SMathias Bauer             CloseInStream();
4211ac49eeddSIvo Hinkelmann         }
4212b584c336SDirk Völzke 
42133ff6fe7aSMikhail Voitenko         if ( !bTransferSuccess )
42143ff6fe7aSMikhail Voitenko         {
42159e4d84daSCaolán McNamara             SetError(ERRCODE_IO_CANTWRITE);
42163ff6fe7aSMikhail Voitenko             return;
42173ff6fe7aSMikhail Voitenko         }
4218fd069beeSJens-Heiner Rechtien     }
4219b584c336SDirk Völzke 
4220b584c336SDirk Völzke     CloseStorage();
4221b584c336SDirk Völzke }
4222b584c336SDirk Völzke 
42230ce0c369SAlexander Wilms 
CreateTempFileNoCopy()4224b584c336SDirk Völzke void SfxMedium::CreateTempFileNoCopy()
4225b584c336SDirk Völzke {
4226ac49eeddSIvo Hinkelmann     // this call always replaces the existing temporary file
4227e4c40331SNoel Grandin     pImpl->pTempFile.reset();
4228b584c336SDirk Völzke 
4229aaf7fe03SMiklos Vajna     OUString aLogicBase = GetLogicBase(GetURLObject(), pImpl);
42304a5ab800SMichael Meeks     pImpl->pTempFile.reset(new MediumTempFile(&aLogicBase));
42315441ed51SJustin Luth     if (!aLogicBase.isEmpty() && pImpl->pTempFile->GetFileName().isEmpty())
42324a5ab800SMichael Meeks         pImpl->pTempFile.reset(new MediumTempFile(nullptr));
42335e32815aSXisco Fauli     pImpl->pTempFile->EnableKillingFile();
42345e32815aSXisco Fauli     pImpl->m_aName = pImpl->pTempFile->GetFileName();
42355e32815aSXisco Fauli     if ( pImpl->m_aName.isEmpty() )
4236aadbfeffSMathias Bauer     {
42379e4d84daSCaolán McNamara         SetError(ERRCODE_IO_CANTWRITE);
4238aadbfeffSMathias Bauer         return;
4239aadbfeffSMathias Bauer     }
4240b584c336SDirk Völzke 
4241b584c336SDirk Völzke     CloseOutStream_Impl();
4242fd069beeSJens-Heiner Rechtien     CloseStorage();
4243fd069beeSJens-Heiner Rechtien }
4244fd069beeSJens-Heiner Rechtien 
SignDocumentContentUsingCertificate(const css::uno::Reference<css::frame::XModel> & xModel,bool bHasValidDocumentSignature,svl::crypto::SigningContext & rSigningContext)4245c3f87022SMiklos Vajna bool SfxMedium::SignDocumentContentUsingCertificate(
4246c3f87022SMiklos Vajna     const css::uno::Reference<css::frame::XModel>& xModel, bool bHasValidDocumentSignature,
424712e50825SMiklos Vajna     svl::crypto::SigningContext& rSigningContext)
424823a23123STomaž Vajngerl {
424923a23123STomaž Vajngerl     bool bChanges = false;
425023a23123STomaž Vajngerl 
4251ed774e9fSNoel Grandin     if (IsOpen() || GetErrorIgnoreWarning())
425223a23123STomaž Vajngerl     {
425323a23123STomaž Vajngerl         SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
425423a23123STomaž Vajngerl         return bChanges;
425523a23123STomaž Vajngerl     }
425623a23123STomaž Vajngerl 
425723a23123STomaž Vajngerl     // The component should know if there was a valid document signature, since
425823a23123STomaž Vajngerl     // it should show a warning in this case
425923a23123STomaž Vajngerl     OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
426023a23123STomaž Vajngerl     uno::Reference< security::XDocumentDigitalSignatures > xSigner(
426123a23123STomaž Vajngerl         security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
426223a23123STomaž Vajngerl             comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
426319691c3bSStephan Bergmann     auto xModelSigner = dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get());
4264c3f87022SMiklos Vajna     if (!xModelSigner)
4265c3f87022SMiklos Vajna     {
4266c3f87022SMiklos Vajna         return bChanges;
4267c3f87022SMiklos Vajna     }
426823a23123STomaž Vajngerl 
426923a23123STomaž Vajngerl     uno::Reference< embed::XStorage > xWriteableZipStor;
427023a23123STomaž Vajngerl 
427123a23123STomaž Vajngerl     // we can reuse the temporary file if there is one already
427223a23123STomaž Vajngerl     CreateTempFile( false );
427323a23123STomaž Vajngerl     GetMedium_Impl();
427423a23123STomaž Vajngerl 
427523a23123STomaž Vajngerl     try
427623a23123STomaž Vajngerl     {
427723a23123STomaž Vajngerl         if ( !pImpl->xStream.is() )
427823a23123STomaž Vajngerl             throw uno::RuntimeException();
427923a23123STomaž Vajngerl 
428023a23123STomaž Vajngerl         bool bODF = GetFilter()->IsOwnFormat();
428123a23123STomaž Vajngerl         try
428223a23123STomaž Vajngerl         {
428323a23123STomaž Vajngerl             xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImpl->xStream );
428423a23123STomaž Vajngerl         }
42855aa942f3SNoel Grandin         catch (const io::IOException&)
428623a23123STomaž Vajngerl         {
428723a23123STomaž Vajngerl             if (bODF)
42885aa942f3SNoel Grandin             {
42895aa942f3SNoel Grandin                 TOOLS_WARN_EXCEPTION("sfx.doc", "ODF stream is not a zip storage");
42905aa942f3SNoel Grandin             }
429123a23123STomaž Vajngerl         }
429223a23123STomaž Vajngerl 
429323a23123STomaž Vajngerl         if ( !xWriteableZipStor.is() && bODF )
429423a23123STomaž Vajngerl             throw uno::RuntimeException();
429523a23123STomaž Vajngerl 
429623a23123STomaž Vajngerl         uno::Reference< embed::XStorage > xMetaInf;
4297ca5c9591SNoel Grandin         if (xWriteableZipStor.is() && xWriteableZipStor->hasByName(u"META-INF"_ustr))
429823a23123STomaž Vajngerl         {
429923a23123STomaž Vajngerl             xMetaInf = xWriteableZipStor->openStorageElement(
4300ca5c9591SNoel Grandin                                             u"META-INF"_ustr,
430123a23123STomaž Vajngerl                                             embed::ElementModes::READWRITE );
430223a23123STomaž Vajngerl             if ( !xMetaInf.is() )
430323a23123STomaž Vajngerl                 throw uno::RuntimeException();
430423a23123STomaž Vajngerl         }
430523a23123STomaž Vajngerl 
430623a23123STomaž Vajngerl         if (xMetaInf.is())
430723a23123STomaž Vajngerl         {
430823a23123STomaž Vajngerl             // ODF.
430923a23123STomaž Vajngerl             uno::Reference< io::XStream > xStream;
431023a23123STomaž Vajngerl             if (GetFilter() && GetFilter()->IsOwnFormat())
431123a23123STomaž Vajngerl                 xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW);
431223a23123STomaž Vajngerl 
4313c3f87022SMiklos Vajna             bool bSuccess = xModelSigner->SignModelWithCertificate(
431412e50825SMiklos Vajna                 xModel, rSigningContext, GetZipStorageToSign_Impl(), xStream);
431523a23123STomaž Vajngerl 
431623a23123STomaž Vajngerl             if (bSuccess)
431723a23123STomaž Vajngerl             {
431823a23123STomaž Vajngerl                 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
431923a23123STomaž Vajngerl                 xTransact->commit();
432023a23123STomaž Vajngerl                 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
432123a23123STomaž Vajngerl                 xTransact->commit();
432223a23123STomaž Vajngerl 
432323a23123STomaž Vajngerl                 // the temporary file has been written, commit it to the original file
432423a23123STomaž Vajngerl                 Commit();
432523a23123STomaž Vajngerl                 bChanges = true;
432623a23123STomaž Vajngerl             }
432723a23123STomaž Vajngerl         }
432823a23123STomaž Vajngerl         else if (xWriteableZipStor.is())
432923a23123STomaž Vajngerl         {
433023a23123STomaž Vajngerl             // OOXML.
433123a23123STomaž Vajngerl             uno::Reference<io::XStream> xStream;
433223a23123STomaž Vajngerl 
433323a23123STomaž Vajngerl                 // We need read-write to be able to add the signature relation.
4334c3f87022SMiklos Vajna             bool bSuccess = xModelSigner->SignModelWithCertificate(
433512e50825SMiklos Vajna                 xModel, rSigningContext, GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream);
433623a23123STomaž Vajngerl 
433723a23123STomaž Vajngerl             if (bSuccess)
433823a23123STomaž Vajngerl             {
433923a23123STomaž Vajngerl                 uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
434023a23123STomaž Vajngerl                 xTransact->commit();
434123a23123STomaž Vajngerl 
434223a23123STomaž Vajngerl                 // the temporary file has been written, commit it to the original file
434323a23123STomaž Vajngerl                 Commit();
434423a23123STomaž Vajngerl                 bChanges = true;
434523a23123STomaž Vajngerl             }
434623a23123STomaž Vajngerl         }
434723a23123STomaž Vajngerl         else
434823a23123STomaž Vajngerl         {
434923a23123STomaž Vajngerl             // Something not ZIP based: e.g. PDF.
435023a23123STomaž Vajngerl             std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | StreamMode::WRITE));
435123a23123STomaž Vajngerl             uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream));
4352c3f87022SMiklos Vajna             if (xModelSigner->SignModelWithCertificate(
435312e50825SMiklos Vajna                     xModel, rSigningContext, uno::Reference<embed::XStorage>(), xStream))
435423a23123STomaž Vajngerl                 bChanges = true;
435523a23123STomaž Vajngerl         }
435623a23123STomaž Vajngerl     }
435723a23123STomaž Vajngerl     catch ( const uno::Exception& )
435823a23123STomaž Vajngerl     {
4359f6536f4dSMichael Stahl         TOOLS_WARN_EXCEPTION("sfx.doc", "Couldn't use signing functionality!");
436023a23123STomaž Vajngerl     }
436123a23123STomaž Vajngerl 
436223a23123STomaž Vajngerl     CloseAndRelease();
436323a23123STomaž Vajngerl 
436423a23123STomaž Vajngerl     ResetError();
436523a23123STomaž Vajngerl 
436623a23123STomaž Vajngerl     return bChanges;
436723a23123STomaž Vajngerl }
436823a23123STomaž Vajngerl 
4369f6536f4dSMichael Stahl // note: this is the only function creating scripting signature
SignContents_Impl(weld::Window * pDialogParent,bool bSignScriptingContent,bool bHasValidDocumentSignature,SfxViewShell * pViewShell,const std::function<void (bool)> & rCallback,const OUString & aSignatureLineId,const Reference<XCertificate> & xCert,const Reference<XGraphic> & xValidGraphic,const Reference<XGraphic> & xInvalidGraphic,const OUString & aComment)4370de0bc0a2SMiklos Vajna void SfxMedium::SignContents_Impl(weld::Window* pDialogParent,
4371bb9481a4SCaolán McNamara                                   bool bSignScriptingContent,
4372bb9481a4SCaolán McNamara                                   bool bHasValidDocumentSignature,
4373c5743455SMiklos Vajna                                   SfxViewShell* pViewShell,
4374de0bc0a2SMiklos Vajna                                   const std::function<void(bool)>& rCallback,
43756499ea2fSSamuel Mehrbrodt                                   const OUString& aSignatureLineId,
437624eae7bdSNoel Grandin                                   const Reference<XCertificate>& xCert,
437724eae7bdSNoel Grandin                                   const Reference<XGraphic>& xValidGraphic,
437824eae7bdSNoel Grandin                                   const Reference<XGraphic>& xInvalidGraphic,
4379090e243cSSamuel Mehrbrodt                                   const OUString& aComment)
4380a0adf64dSKurt Zenker {
438150b4cbe9SKohei Yoshida     bool bChanges = false;
4382083d2f57SVladimir Glazounov 
4383ed774e9fSNoel Grandin     if (IsOpen() || GetErrorIgnoreWarning())
4384a0adf64dSKurt Zenker     {
4385c4409edbSSamuel Mehrbrodt         SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
4386de0bc0a2SMiklos Vajna         rCallback(bChanges);
4387de0bc0a2SMiklos Vajna         return;
4388c4409edbSSamuel Mehrbrodt     }
4389c4409edbSSamuel Mehrbrodt 
4390ac49eeddSIvo Hinkelmann     // The component should know if there was a valid document signature, since
4391ac49eeddSIvo Hinkelmann     // it should show a warning in this case
439213596e70SSamuel Mehrbrodt     OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
4393197a79e5SNoel Grandin     uno::Reference< security::XDocumentDigitalSignatures > xSigner(
4394197a79e5SNoel Grandin         security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
4395197a79e5SNoel Grandin             comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature ) );
4396bb9481a4SCaolán McNamara     if (pDialogParent)
4397bb9481a4SCaolán McNamara         xSigner->setParentWindow(pDialogParent->GetXWindow());
4398ac49eeddSIvo Hinkelmann 
4399ac49eeddSIvo Hinkelmann     uno::Reference< embed::XStorage > xWriteableZipStor;
4400039117ebSSamuel Mehrbrodt 
4401ac49eeddSIvo Hinkelmann     // we can reuse the temporary file if there is one already
4402df8a15d8SKohei Yoshida     CreateTempFile( false );
4403ac49eeddSIvo Hinkelmann     GetMedium_Impl();
4404083d2f57SVladimir Glazounov 
4405caff013bSMiklos Vajna     auto onSignDocumentContentFinished = [this, rCallback](bool bRet) {
4406caff013bSMiklos Vajna         CloseAndRelease();
4407caff013bSMiklos Vajna 
4408caff013bSMiklos Vajna         ResetError();
4409caff013bSMiklos Vajna 
4410caff013bSMiklos Vajna         rCallback(bRet);
4411caff013bSMiklos Vajna     };
4412caff013bSMiklos Vajna 
4413083d2f57SVladimir Glazounov     try
4414083d2f57SVladimir Glazounov     {
44155e32815aSXisco Fauli         if ( !pImpl->xStream.is() )
4416ac49eeddSIvo Hinkelmann             throw uno::RuntimeException();
4417ac49eeddSIvo Hinkelmann 
44184eed1d85SMiklos Vajna         bool bODF = GetFilter()->IsOwnFormat();
44194eed1d85SMiklos Vajna         try
44204eed1d85SMiklos Vajna         {
44213b347664SMichael Stahl             if (pImpl->m_bODFWholesomeEncryption && bSignScriptingContent)
44223b347664SMichael Stahl             {
44233b347664SMichael Stahl                 assert(pImpl->xStorage); // GetStorage was called above
44243b347664SMichael Stahl                 assert(pImpl->m_xODFDecryptedInnerPackageStream);
44253b347664SMichael Stahl                 xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
44263b347664SMichael Stahl                     ZIP_STORAGE_FORMAT_STRING, pImpl->m_xODFDecryptedInnerPackageStream);
44273b347664SMichael Stahl             }
44283b347664SMichael Stahl             else
44293b347664SMichael Stahl             {
44303b347664SMichael Stahl                 xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
44313b347664SMichael Stahl                     ZIP_STORAGE_FORMAT_STRING, pImpl->xStream );
44323b347664SMichael Stahl             }
44334eed1d85SMiklos Vajna         }
44345aa942f3SNoel Grandin         catch (const io::IOException&)
44354eed1d85SMiklos Vajna         {
44364eed1d85SMiklos Vajna             if (bODF)
44375aa942f3SNoel Grandin             {
44385aa942f3SNoel Grandin                 TOOLS_WARN_EXCEPTION("sfx.doc", "ODF stream is not a zip storage");
44395aa942f3SNoel Grandin             }
44404eed1d85SMiklos Vajna         }
44414eed1d85SMiklos Vajna 
44424eed1d85SMiklos Vajna         if ( !xWriteableZipStor.is() && bODF )
4443ac49eeddSIvo Hinkelmann             throw uno::RuntimeException();
4444ac49eeddSIvo Hinkelmann 
44458865a3b0SMiklos Vajna         uno::Reference< embed::XStorage > xMetaInf;
4446ca5c9591SNoel Grandin         if (xWriteableZipStor.is() && xWriteableZipStor->hasByName(u"META-INF"_ustr))
44478865a3b0SMiklos Vajna         {
44488865a3b0SMiklos Vajna             xMetaInf = xWriteableZipStor->openStorageElement(
4449ca5c9591SNoel Grandin                                             u"META-INF"_ustr,
4450ac49eeddSIvo Hinkelmann                                             embed::ElementModes::READWRITE );
4451083d2f57SVladimir Glazounov             if ( !xMetaInf.is() )
4452083d2f57SVladimir Glazounov                 throw uno::RuntimeException();
44538865a3b0SMiklos Vajna         }
4454083d2f57SVladimir Glazounov 
445507df95e7SMiklos Vajna         auto xModelSigner = dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get());
445607df95e7SMiklos Vajna         assert(xModelSigner);
445799337b02SSamuel Mehrbrodt         if ( bSignScriptingContent )
4458a0adf64dSKurt Zenker         {
4459ac49eeddSIvo Hinkelmann             // If the signature has already the document signature it will be removed
4460ac49eeddSIvo Hinkelmann             // after the scripting signature is inserted.
4461ac49eeddSIvo Hinkelmann             uno::Reference< io::XStream > xStream(
4462ac49eeddSIvo Hinkelmann                 xMetaInf->openStreamElement( xSigner->getScriptingContentSignatureDefaultStreamName(),
4463ac49eeddSIvo Hinkelmann                                                 embed::ElementModes::READWRITE ),
4464ac49eeddSIvo Hinkelmann                 uno::UNO_SET_THROW );
4465083d2f57SVladimir Glazounov 
44663b347664SMichael Stahl             // note: the storage passed here must be independent from the
44673b347664SMichael Stahl             // xWriteableZipStor because a writable storage can't have 2
44683b347664SMichael Stahl             // instances of sub-storage for the same directory open, but with
44693b347664SMichael Stahl             // independent storages it somehow works
447007df95e7SMiklos Vajna             xModelSigner->SignScriptingContentAsync(
447107df95e7SMiklos Vajna                 GetScriptingStorageToSign_Impl(), xStream,
447207df95e7SMiklos Vajna                 [this, xSigner, xMetaInf, xWriteableZipStor,
4473*16bd75a5SCaolán McNamara                  onSignDocumentContentFinished=std::move(onSignDocumentContentFinished)](bool bRet) {
4474ac49eeddSIvo Hinkelmann                 // remove the document signature if any
44751946794aSLuboš Luňák                 OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName();
4476e24a27b4SOlivier Hallot                 if ( !aDocSigName.isEmpty() && xMetaInf->hasByName( aDocSigName ) )
4477ac49eeddSIvo Hinkelmann                     xMetaInf->removeElement( aDocSigName );
4478a1f5b8b1SIvo Hinkelmann 
4479ac49eeddSIvo Hinkelmann                 uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
4480ac49eeddSIvo Hinkelmann                 xTransact->commit();
4481ac49eeddSIvo Hinkelmann                 xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
4482ac49eeddSIvo Hinkelmann                 xTransact->commit();
4483ac49eeddSIvo Hinkelmann 
44843b347664SMichael Stahl                 if (pImpl->m_bODFWholesomeEncryption)
44853b347664SMichael Stahl                 {   // manually copy the inner package to the outer one
4486c8d2e22eSNoel Grandin                     pImpl->m_xODFDecryptedInnerPackageStream->seek(0);
44873b347664SMichael Stahl                     uno::Reference<io::XStream> const xEncryptedPackage =
44883b347664SMichael Stahl                         pImpl->m_xODFEncryptedOuterStorage->openStreamElement(
4489ca5c9591SNoel Grandin                             u"encrypted-package"_ustr,
44903b347664SMichael Stahl                             embed::ElementModes::WRITE|embed::ElementModes::TRUNCATE);
44913b347664SMichael Stahl                     comphelper::OStorageHelper::CopyInputToOutput(pImpl->m_xODFDecryptedInnerPackageStream->getInputStream(), xEncryptedPackage->getOutputStream());
44923b347664SMichael Stahl                     xTransact.set(pImpl->m_xODFEncryptedOuterStorage, uno::UNO_QUERY_THROW);
44933b347664SMichael Stahl                     xTransact->commit(); // Commit() below won't do this
44943b347664SMichael Stahl                 }
44953b347664SMichael Stahl 
44963b347664SMichael Stahl                 assert(!pImpl->xStorage.is() // ensure this doesn't overwrite
44973b347664SMichael Stahl                     || !uno::Reference<util::XModifiable>(pImpl->xStorage, uno::UNO_QUERY_THROW)->isModified());
4498ac49eeddSIvo Hinkelmann                 // the temporary file has been written, commit it to the original file
4499083d2f57SVladimir Glazounov                 Commit();
450007df95e7SMiklos Vajna                 onSignDocumentContentFinished(bRet);
450107df95e7SMiklos Vajna             });
450207df95e7SMiklos Vajna             return;
4503083d2f57SVladimir Glazounov         }
4504a0adf64dSKurt Zenker         else
4505a0adf64dSKurt Zenker         {
4506e5a0209dSMiklos Vajna             // Signing the entire document.
45078865a3b0SMiklos Vajna             if (xMetaInf.is())
45088865a3b0SMiklos Vajna             {
45098865a3b0SMiklos Vajna                 // ODF.
4510ac699587SMiklos Vajna                 uno::Reference< io::XStream > xStream;
4511e5a0209dSMiklos Vajna                 uno::Reference< io::XStream > xScriptingStream;
4512ac699587SMiklos Vajna                 if (GetFilter() && GetFilter()->IsOwnFormat())
4513e5a0209dSMiklos Vajna                 {
4514e5a0209dSMiklos Vajna                     bool bImplicitScriptSign = officecfg::Office::Common::Security::Scripting::ImplicitScriptSign::get();
4515e5a0209dSMiklos Vajna                     if (comphelper::LibreOfficeKit::isActive())
4516e5a0209dSMiklos Vajna                     {
4517e5a0209dSMiklos Vajna                         bImplicitScriptSign = true;
4518e5a0209dSMiklos Vajna                     }
4519e5a0209dSMiklos Vajna 
4520e5a0209dSMiklos Vajna                     OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName();
4521e5a0209dSMiklos Vajna                     bool bHasSignatures = xMetaInf->hasByName(aDocSigName);
4522e5a0209dSMiklos Vajna 
4523e5a0209dSMiklos Vajna                     // C.f. DocumentSignatureHelper::CreateElementList() for the
4524e5a0209dSMiklos Vajna                     // DocumentSignatureMode::Macros case.
4525e5a0209dSMiklos Vajna                     bool bHasMacros = xWriteableZipStor->hasByName(u"Basic"_ustr)
4526e5a0209dSMiklos Vajna                                       || xWriteableZipStor->hasByName(u"Dialogs"_ustr)
4527e5a0209dSMiklos Vajna                                       || xWriteableZipStor->hasByName(u"Scripts"_ustr);
4528e5a0209dSMiklos Vajna 
4529ac699587SMiklos Vajna                     xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), embed::ElementModes::READWRITE), uno::UNO_SET_THROW);
4530e5a0209dSMiklos Vajna                     if (bImplicitScriptSign && bHasMacros && !bHasSignatures)
4531e5a0209dSMiklos Vajna                     {
4532e5a0209dSMiklos Vajna                         xScriptingStream.set(
4533e5a0209dSMiklos Vajna                             xMetaInf->openStreamElement(
4534e5a0209dSMiklos Vajna                                 xSigner->getScriptingContentSignatureDefaultStreamName(),
4535e5a0209dSMiklos Vajna                                 embed::ElementModes::READWRITE),
4536e5a0209dSMiklos Vajna                             uno::UNO_SET_THROW);
4537e5a0209dSMiklos Vajna                     }
4538e5a0209dSMiklos Vajna                 }
4539083d2f57SVladimir Glazounov 
454086e8cfddSSamuel Mehrbrodt                 bool bSuccess = false;
4541caff013bSMiklos Vajna                 auto onODFSignDocumentContentFinished = [this, xMetaInf, xWriteableZipStor]() {
4542ac49eeddSIvo Hinkelmann                     uno::Reference< embed::XTransactedObject > xTransact( xMetaInf, uno::UNO_QUERY_THROW );
4543ac49eeddSIvo Hinkelmann                     xTransact->commit();
4544ac49eeddSIvo Hinkelmann                     xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
4545ac49eeddSIvo Hinkelmann                     xTransact->commit();
4546a1f5b8b1SIvo Hinkelmann 
4547ac49eeddSIvo Hinkelmann                     // the temporary file has been written, commit it to the original file
4548083d2f57SVladimir Glazounov                     Commit();
4549caff013bSMiklos Vajna                 };
4550caff013bSMiklos Vajna                 if (xCert.is())
4551caff013bSMiklos Vajna                     bSuccess = xSigner->signSignatureLine(
4552caff013bSMiklos Vajna                         GetZipStorageToSign_Impl(), xStream, aSignatureLineId, xCert,
4553caff013bSMiklos Vajna                         xValidGraphic, xInvalidGraphic, aComment);
4554caff013bSMiklos Vajna                 else
4555caff013bSMiklos Vajna                 {
4556e5a0209dSMiklos Vajna                     if (xScriptingStream.is())
4557e5a0209dSMiklos Vajna                     {
4558e5a0209dSMiklos Vajna                         xModelSigner->SetSignScriptingContent(xScriptingStream);
4559e5a0209dSMiklos Vajna                     }
4560e5a0209dSMiklos Vajna 
4561caff013bSMiklos Vajna                     // Async, all code before return has to go into the callback.
4562*16bd75a5SCaolán McNamara                     xModelSigner->SignDocumentContentAsync(GetZipStorageToSign_Impl(), xStream, pViewShell,
4563*16bd75a5SCaolán McNamara                                                            [onODFSignDocumentContentFinished,
4564*16bd75a5SCaolán McNamara                                                             onSignDocumentContentFinished=std::move(onSignDocumentContentFinished)](bool bRet) {
4565caff013bSMiklos Vajna                         if (bRet)
4566caff013bSMiklos Vajna                         {
4567caff013bSMiklos Vajna                             onODFSignDocumentContentFinished();
4568caff013bSMiklos Vajna                         }
4569caff013bSMiklos Vajna 
4570caff013bSMiklos Vajna                         onSignDocumentContentFinished(bRet);
4571caff013bSMiklos Vajna                     });
4572caff013bSMiklos Vajna                     return;
4573caff013bSMiklos Vajna                 }
4574caff013bSMiklos Vajna 
4575caff013bSMiklos Vajna                 if (bSuccess)
4576caff013bSMiklos Vajna                 {
4577caff013bSMiklos Vajna                     onODFSignDocumentContentFinished();
4578df8a15d8SKohei Yoshida                     bChanges = true;
4579083d2f57SVladimir Glazounov                 }
4580a0adf64dSKurt Zenker             }
45814eed1d85SMiklos Vajna             else if (xWriteableZipStor.is())
45828865a3b0SMiklos Vajna             {
45838865a3b0SMiklos Vajna                 // OOXML.
45848865a3b0SMiklos Vajna                 uno::Reference<io::XStream> xStream;
458586e8cfddSSamuel Mehrbrodt 
4586caff013bSMiklos Vajna                 auto onOOXMLSignDocumentContentFinished = [this, xWriteableZipStor]() {
4587caff013bSMiklos Vajna                     uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
4588caff013bSMiklos Vajna                     xTransact->commit();
4589caff013bSMiklos Vajna 
4590caff013bSMiklos Vajna                     // the temporary file has been written, commit it to the original file
4591caff013bSMiklos Vajna                     Commit();
4592caff013bSMiklos Vajna                 };
459386e8cfddSSamuel Mehrbrodt                 bool bSuccess = false;
459486e8cfddSSamuel Mehrbrodt                 if (xCert.is())
459586e8cfddSSamuel Mehrbrodt                 {
45966499ea2fSSamuel Mehrbrodt                     bSuccess = xSigner->signSignatureLine(
4597090e243cSSamuel Mehrbrodt                         GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream, aSignatureLineId,
4598090e243cSSamuel Mehrbrodt                         xCert, xValidGraphic, xInvalidGraphic, aComment);
459986e8cfddSSamuel Mehrbrodt                 }
460086e8cfddSSamuel Mehrbrodt                 else
460186e8cfddSSamuel Mehrbrodt                 {
460279d56540SMiklos Vajna                     // We need read-write to be able to add the signature relation.
4603caff013bSMiklos Vajna                     xModelSigner->SignDocumentContentAsync(
4604*16bd75a5SCaolán McNamara                         GetZipStorageToSign_Impl(/*bReadOnly=*/false), xStream, pViewShell,
4605*16bd75a5SCaolán McNamara                         [onOOXMLSignDocumentContentFinished,
4606*16bd75a5SCaolán McNamara                          onSignDocumentContentFinished=std::move(onSignDocumentContentFinished)](bool bRet) {
4607caff013bSMiklos Vajna                         if (bRet)
4608caff013bSMiklos Vajna                         {
4609caff013bSMiklos Vajna                             onOOXMLSignDocumentContentFinished();
4610caff013bSMiklos Vajna                         }
4611caff013bSMiklos Vajna 
4612caff013bSMiklos Vajna                         onSignDocumentContentFinished(bRet);
4613caff013bSMiklos Vajna                     });
4614caff013bSMiklos Vajna                     return;
461586e8cfddSSamuel Mehrbrodt                 }
461686e8cfddSSamuel Mehrbrodt 
461786e8cfddSSamuel Mehrbrodt                 if (bSuccess)
46188865a3b0SMiklos Vajna                 {
4619caff013bSMiklos Vajna                     onOOXMLSignDocumentContentFinished();
46208865a3b0SMiklos Vajna                     bChanges = true;
46218865a3b0SMiklos Vajna                 }
46228865a3b0SMiklos Vajna             }
46234eed1d85SMiklos Vajna             else
46244eed1d85SMiklos Vajna             {
4625ddc107a1SMiklos Vajna                 // Something not ZIP based: e.g. PDF.
4626ddc107a1SMiklos Vajna                 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | StreamMode::WRITE));
4627482c7c58SMiklos Vajna                 uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(std::move(pStream)));
4628*16bd75a5SCaolán McNamara                 xModelSigner->SignDocumentContentAsync(uno::Reference<embed::XStorage>(), xStream, pViewShell,
4629*16bd75a5SCaolán McNamara                                                        [onSignDocumentContentFinished=std::move(onSignDocumentContentFinished)](bool bRet) {
4630caff013bSMiklos Vajna                     onSignDocumentContentFinished(bRet);
4631caff013bSMiklos Vajna                 });
4632caff013bSMiklos Vajna                 return;
46334eed1d85SMiklos Vajna             }
46348865a3b0SMiklos Vajna         }
4635a0adf64dSKurt Zenker     }
46366c89e69bSCaolán McNamara     catch ( const uno::Exception& )
4637083d2f57SVladimir Glazounov     {
4638f6536f4dSMichael Stahl         TOOLS_WARN_EXCEPTION("sfx.doc", "Couldn't use signing functionality!");
4639083d2f57SVladimir Glazounov     }
4640ac49eeddSIvo Hinkelmann 
4641caff013bSMiklos Vajna     onSignDocumentContentFinished(bChanges);
4642a0adf64dSKurt Zenker }
4643a0adf64dSKurt Zenker 
46440ce0c369SAlexander Wilms 
GetCachedSignatureState_Impl() const4645df905f41SNoel Grandin SignatureState SfxMedium::GetCachedSignatureState_Impl() const
46469e332587SOliver Bolte {
46475e32815aSXisco Fauli     return pImpl->m_nSignatureState;
46489e332587SOliver Bolte }
46499e332587SOliver Bolte 
46500ce0c369SAlexander Wilms 
SetCachedSignatureState_Impl(SignatureState nState)4651d208cf83SNoel Grandin void SfxMedium::SetCachedSignatureState_Impl( SignatureState nState )
46529e332587SOliver Bolte {
46535e32815aSXisco Fauli     pImpl->m_nSignatureState = nState;
46549e332587SOliver Bolte }
46559e332587SOliver Bolte 
SetHasEmbeddedObjects(bool bHasEmbeddedObjects)4656c1676204SMiklos Vajna void SfxMedium::SetHasEmbeddedObjects(bool bHasEmbeddedObjects)
4657c1676204SMiklos Vajna {
4658c1676204SMiklos Vajna     pImpl->m_bHasEmbeddedObjects = bHasEmbeddedObjects;
4659c1676204SMiklos Vajna }
4660c1676204SMiklos Vajna 
HasStorage_Impl() const46615fe7ecc0SNoel Grandin bool SfxMedium::HasStorage_Impl() const
4662762dd2b1SKurt Zenker {
46635e32815aSXisco Fauli     return pImpl->xStorage.is();
4664762dd2b1SKurt Zenker }
4665762dd2b1SKurt Zenker 
IsOpen() const46665fe7ecc0SNoel Grandin bool SfxMedium::IsOpen() const
4667762dd2b1SKurt Zenker {
46685e32815aSXisco Fauli     return pImpl->m_pInStream || pImpl->m_pOutStream || pImpl->xStorage.is();
4669762dd2b1SKurt Zenker }
4670f117fe35SRüdiger Timm 
CreateTempCopyWithExt(std::u16string_view aURL)4671d3849255SNoel Grandin OUString SfxMedium::CreateTempCopyWithExt( std::u16string_view aURL )
4672f117fe35SRüdiger Timm {
46731946794aSLuboš Luňák     OUString aResult;
4674f117fe35SRüdiger Timm 
4675d3849255SNoel Grandin     if ( !aURL.empty() )
4676f117fe35SRüdiger Timm     {
4677d3849255SNoel Grandin         size_t nPrefixLen = aURL.rfind( '.' );
4678898ba5beSNoel Grandin         std::u16string_view aExt = ( nPrefixLen == std::u16string_view::npos ) ? std::u16string_view() : aURL.substr( nPrefixLen );
4679f117fe35SRüdiger Timm 
46804b95451fSNoel Grandin         OUString aNewTempFileURL = ::utl::CreateTempURL( u"", true, aExt );
4681e24a27b4SOlivier Hallot         if ( !aNewTempFileURL.isEmpty() )
4682f117fe35SRüdiger Timm         {
4683f117fe35SRüdiger Timm             INetURLObject aSource( aURL );
4684f117fe35SRüdiger Timm             INetURLObject aDest( aNewTempFileURL );
46851946794aSLuboš Luňák             OUString aFileName = aDest.getName( INetURLObject::LAST_SEGMENT,
4686f117fe35SRüdiger Timm                                                         true,
4687bfde4866SNoel Grandin                                                         INetURLObject::DecodeMechanism::WithCharset );
4688e24a27b4SOlivier Hallot             if ( !aFileName.isEmpty() && aDest.removeSegment() )
4689f117fe35SRüdiger Timm             {
4690f117fe35SRüdiger Timm                 try
4691f117fe35SRüdiger Timm                 {
4692913a2d36SNoel Grandin                     uno::Reference< css::ucb::XCommandEnvironment > xComEnv;
4693bfde4866SNoel Grandin                     ::ucbhelper::Content aTargetContent( aDest.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xComEnv, comphelper::getProcessComponentContext() );
4694bfde4866SNoel Grandin                     ::ucbhelper::Content aSourceContent( aSource.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xComEnv, comphelper::getProcessComponentContext() );
469553491f8aSNoel Grandin                     aTargetContent.transferContent( aSourceContent,
4696d198a822SNoel Grandin                                                         ::ucbhelper::InsertOperation::Copy,
4697f117fe35SRüdiger Timm                                                         aFileName,
469853491f8aSNoel Grandin                                                         NameClash::OVERWRITE );
4699f117fe35SRüdiger Timm                     aResult = aNewTempFileURL;
4700f117fe35SRüdiger Timm                 }
47016c89e69bSCaolán McNamara                 catch( const uno::Exception& )
4702f117fe35SRüdiger Timm                 {}
4703f117fe35SRüdiger Timm             }
4704f117fe35SRüdiger Timm         }
4705f117fe35SRüdiger Timm     }
4706f117fe35SRüdiger Timm 
4707f117fe35SRüdiger Timm     return aResult;
4708f117fe35SRüdiger Timm }
4709f117fe35SRüdiger Timm 
CallApproveHandler(const uno::Reference<task::XInteractionHandler> & xHandler,const uno::Any & rRequest,bool bAllowAbort)471032f95a35SCaolán McNamara bool SfxMedium::CallApproveHandler(const uno::Reference< task::XInteractionHandler >& xHandler, const uno::Any& rRequest, bool bAllowAbort)
4711ac49eeddSIvo Hinkelmann {
471250b4cbe9SKohei Yoshida     bool bResult = false;
4713ac49eeddSIvo Hinkelmann 
4714ac49eeddSIvo Hinkelmann     if ( xHandler.is() )
4715ac49eeddSIvo Hinkelmann     {
4716ac49eeddSIvo Hinkelmann         try
4717ac49eeddSIvo Hinkelmann         {
4718ac49eeddSIvo Hinkelmann             uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( bAllowAbort ? 2 : 1 );
4719ce22935aSMike Kaganski             auto pContinuations = aContinuations.getArray();
4720ac49eeddSIvo Hinkelmann 
4721661e2cc1SMathias Bauer             ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( new ::comphelper::OInteractionApprove );
4722ce22935aSMike Kaganski             pContinuations[ 0 ] = pApprove.get();
4723ac49eeddSIvo Hinkelmann 
4724ac49eeddSIvo Hinkelmann             if ( bAllowAbort )
4725ac49eeddSIvo Hinkelmann             {
4726661e2cc1SMathias Bauer                 ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( new ::comphelper::OInteractionAbort );
4727ce22935aSMike Kaganski                 pContinuations[ 1 ] = pAbort.get();
4728ac49eeddSIvo Hinkelmann             }
4729ac49eeddSIvo Hinkelmann 
473032f95a35SCaolán McNamara             xHandler->handle(::framework::InteractionRequest::CreateRequest(rRequest, aContinuations));
4731661e2cc1SMathias Bauer             bResult = pApprove->wasSelected();
4732ac49eeddSIvo Hinkelmann         }
4733ac49eeddSIvo Hinkelmann         catch( const Exception& )
4734ac49eeddSIvo Hinkelmann         {
4735ac49eeddSIvo Hinkelmann         }
4736ac49eeddSIvo Hinkelmann     }
4737ac49eeddSIvo Hinkelmann 
4738ac49eeddSIvo Hinkelmann     return bResult;
4739ac49eeddSIvo Hinkelmann }
4740ac49eeddSIvo Hinkelmann 
SwitchDocumentToTempFile()47411946794aSLuboš Luňák OUString SfxMedium::SwitchDocumentToTempFile()
4742117456a0SKurt Zenker {
4743117456a0SKurt Zenker     // the method returns empty string in case of failure
47441946794aSLuboš Luňák     OUString aResult;
47455e32815aSXisco Fauli     OUString aOrigURL = pImpl->m_aLogicName;
4746117456a0SKurt Zenker 
4747e24a27b4SOlivier Hallot     if ( !aOrigURL.isEmpty() )
4748117456a0SKurt Zenker     {
4749117456a0SKurt Zenker         sal_Int32 nPrefixLen = aOrigURL.lastIndexOf( '.' );
4750898ba5beSNoel Grandin         std::u16string_view aExt = (nPrefixLen == -1)
4751898ba5beSNoel Grandin                                 ? std::u16string_view()
4752898ba5beSNoel Grandin                                 : aOrigURL.subView(nPrefixLen);
47534b95451fSNoel Grandin         OUString aNewURL = ::utl::CreateTempURL( u"", true, aExt );
4754117456a0SKurt Zenker 
47552058774bSVladimir Glazounov         // TODO/LATER: In future the aLogicName should be set to shared folder URL
47562058774bSVladimir Glazounov         //             and a temporary file should be created. Transport_Impl should be impossible then.
4757e24a27b4SOlivier Hallot         if ( !aNewURL.isEmpty() )
4758117456a0SKurt Zenker         {
4759117456a0SKurt Zenker             uno::Reference< embed::XStorage > xStorage = GetStorage();
4760117456a0SKurt Zenker             uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
4761117456a0SKurt Zenker 
4762117456a0SKurt Zenker             if ( xOptStorage.is() )
4763117456a0SKurt Zenker             {
47645e32815aSXisco Fauli                 // TODO/LATER: reuse the pImpl->pTempFile if it already exists
4765df8a15d8SKohei Yoshida                 CanDisposeStorage_Impl( false );
4766117456a0SKurt Zenker                 Close();
4767f9e78cd4SNoel Grandin                 SetPhysicalName_Impl( OUString() );
4768117456a0SKurt Zenker                 SetName( aNewURL );
4769117456a0SKurt Zenker 
4770117456a0SKurt Zenker                 // remove the readonly state
477150b4cbe9SKohei Yoshida                 bool bWasReadonly = false;
47725e32815aSXisco Fauli                 pImpl->m_nStorOpenMode = SFX_STREAM_READWRITE;
4773e4c40331SNoel Grandin                 const SfxBoolItem* pReadOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(pImpl->m_pSet.get(), SID_DOC_READONLY, false);
4774117456a0SKurt Zenker                 if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
4775df8a15d8SKohei Yoshida                     bWasReadonly = true;
4776f5dd4faeSMike Kaganski                 GetItemSet().ClearItem( SID_DOC_READONLY );
4777117456a0SKurt Zenker 
4778117456a0SKurt Zenker                 GetMedium_Impl();
4779df8a15d8SKohei Yoshida                 LockOrigFileOnDemand( false, false );
4780e5da350eSNoel Grandin                 CreateTempFile();
47812058774bSVladimir Glazounov                 GetMedium_Impl();
4782117456a0SKurt Zenker 
47835e32815aSXisco Fauli                 if ( pImpl->xStream.is() )
4784117456a0SKurt Zenker                 {
4785117456a0SKurt Zenker                     try
4786117456a0SKurt Zenker                     {
47875e32815aSXisco Fauli                         xOptStorage->writeAndAttachToStream( pImpl->xStream );
47885e32815aSXisco Fauli                         pImpl->xStorage = xStorage;
4789117456a0SKurt Zenker                         aResult = aNewURL;
4790117456a0SKurt Zenker                     }
47916c89e69bSCaolán McNamara                     catch( const uno::Exception& )
4792117456a0SKurt Zenker                     {}
4793117456a0SKurt Zenker                 }
4794117456a0SKurt Zenker 
4795117456a0SKurt Zenker                 if (bWasReadonly)
4796117456a0SKurt Zenker                 {
4797117456a0SKurt Zenker                     // set the readonly state back
47985e32815aSXisco Fauli                     pImpl->m_nStorOpenMode = SFX_STREAM_READONLY;
4799f5dd4faeSMike Kaganski                     GetItemSet().Put(SfxBoolItem(SID_DOC_READONLY, true));
4800117456a0SKurt Zenker                 }
4801c7b6c940SBalazs Varga 
4802c7b6c940SBalazs Varga                 if ( aResult.isEmpty() )
4803c7b6c940SBalazs Varga                 {
4804c7b6c940SBalazs Varga                     Close();
4805c7b6c940SBalazs Varga                     SetPhysicalName_Impl( OUString() );
4806c7b6c940SBalazs Varga                     SetName( aOrigURL );
4807117456a0SKurt Zenker                     GetMedium_Impl();
48087bbe74b2SCaolán McNamara                     pImpl->xStorage = std::move(xStorage);
4809117456a0SKurt Zenker                 }
4810117456a0SKurt Zenker             }
4811117456a0SKurt Zenker         }
4812117456a0SKurt Zenker     }
4813117456a0SKurt Zenker 
4814117456a0SKurt Zenker     return aResult;
4815117456a0SKurt Zenker }
4816117456a0SKurt Zenker 
SwitchDocumentToFile(const OUString & aURL)48175fe7ecc0SNoel Grandin bool SfxMedium::SwitchDocumentToFile( const OUString& aURL )
4818117456a0SKurt Zenker {
48192058774bSVladimir Glazounov     // the method is only for storage based documents
482050b4cbe9SKohei Yoshida     bool bResult = false;
48215e32815aSXisco Fauli     OUString aOrigURL = pImpl->m_aLogicName;
4822117456a0SKurt Zenker 
4823e24a27b4SOlivier Hallot     if ( !aURL.isEmpty() && !aOrigURL.isEmpty() )
4824117456a0SKurt Zenker     {
4825117456a0SKurt Zenker         uno::Reference< embed::XStorage > xStorage = GetStorage();
4826117456a0SKurt Zenker         uno::Reference< embed::XOptimizedStorage > xOptStorage( xStorage, uno::UNO_QUERY );
4827117456a0SKurt Zenker 
48285e32815aSXisco Fauli         // TODO/LATER: reuse the pImpl->pTempFile if it already exists
4829df8a15d8SKohei Yoshida         CanDisposeStorage_Impl( false );
4830117456a0SKurt Zenker         Close();
4831f9e78cd4SNoel Grandin         SetPhysicalName_Impl( OUString() );
4832117456a0SKurt Zenker         SetName( aURL );
48332058774bSVladimir Glazounov 
48342058774bSVladimir Glazounov         // open the temporary file based document
48352058774bSVladimir Glazounov         GetMedium_Impl();
4836df8a15d8SKohei Yoshida         LockOrigFileOnDemand( false, false );
4837e5da350eSNoel Grandin         CreateTempFile();
4838117456a0SKurt Zenker         GetMedium_Impl();
4839117456a0SKurt Zenker 
48405e32815aSXisco Fauli         if ( pImpl->xStream.is() )
4841117456a0SKurt Zenker         {
4842117456a0SKurt Zenker             try
4843117456a0SKurt Zenker             {
4844ece0729eSNoel Grandin                 uno::Reference< io::XTruncate > xTruncate( pImpl->xStream, uno::UNO_QUERY );
4845ece0729eSNoel Grandin                 if (xTruncate)
4846ece0729eSNoel Grandin                 {
4847117456a0SKurt Zenker                     xTruncate->truncate();
4848c8cd6291SVasily Melenchuk                     if ( xOptStorage.is() )
48495e32815aSXisco Fauli                         xOptStorage->writeAndAttachToStream( pImpl->xStream );
48505e32815aSXisco Fauli                     pImpl->xStorage = xStorage;
4851df8a15d8SKohei Yoshida                     bResult = true;
4852117456a0SKurt Zenker                 }
4853ece0729eSNoel Grandin             }
48546c89e69bSCaolán McNamara             catch( const uno::Exception& )
4855117456a0SKurt Zenker             {}
4856117456a0SKurt Zenker         }
4857117456a0SKurt Zenker 
4858117456a0SKurt Zenker         if ( !bResult )
4859117456a0SKurt Zenker         {
4860117456a0SKurt Zenker             Close();
4861f9e78cd4SNoel Grandin             SetPhysicalName_Impl( OUString() );
4862117456a0SKurt Zenker             SetName( aOrigURL );
4863117456a0SKurt Zenker             GetMedium_Impl();
4864ee4554b0SCaolán McNamara             pImpl->xStorage = std::move(xStorage);
4865117456a0SKurt Zenker         }
4866117456a0SKurt Zenker     }
4867117456a0SKurt Zenker 
4868117456a0SKurt Zenker     return bResult;
4869117456a0SKurt Zenker }
4870117456a0SKurt Zenker 
SetInCheckIn(bool bInCheckIn)48711a926112SCédric Bosdonnat void SfxMedium::SetInCheckIn( bool bInCheckIn )
48721a926112SCédric Bosdonnat {
48735e32815aSXisco Fauli     pImpl->m_bInCheckIn = bInCheckIn;
48741a926112SCédric Bosdonnat }
48751a926112SCédric Bosdonnat 
IsInCheckIn() const4876df905f41SNoel Grandin bool SfxMedium::IsInCheckIn( ) const
48771a926112SCédric Bosdonnat {
48785e32815aSXisco Fauli     return pImpl->m_bInCheckIn;
48791a926112SCédric Bosdonnat }
48801a926112SCédric Bosdonnat 
488195eb0888SMatt K // should only be called on main thread
GetCheckEditableMutex() const48824dbe4a93SNoel Grandin const std::shared_ptr<std::recursive_mutex>& SfxMedium::GetCheckEditableMutex() const
488395eb0888SMatt K {
488495eb0888SMatt K     return pImpl->m_pCheckEditableWorkerMutex;
488595eb0888SMatt K }
488695eb0888SMatt K 
488795eb0888SMatt K // should only be called while holding pImpl->m_pCheckEditableWorkerMutex
SetWorkerReloadEvent(ImplSVEvent * pEvent)488895eb0888SMatt K void SfxMedium::SetWorkerReloadEvent(ImplSVEvent* pEvent)
488995eb0888SMatt K {
489095eb0888SMatt K     pImpl->m_pReloadEvent = pEvent;
489195eb0888SMatt K }
489295eb0888SMatt K 
489395eb0888SMatt K // should only be called while holding pImpl->m_pCheckEditableWorkerMutex
GetWorkerReloadEvent() const489495eb0888SMatt K ImplSVEvent* SfxMedium::GetWorkerReloadEvent() const
489595eb0888SMatt K {
489695eb0888SMatt K     return pImpl->m_pReloadEvent;
489795eb0888SMatt K }
489895eb0888SMatt K 
489995eb0888SMatt K // should only be called on main thread
AddToCheckEditableWorkerList()490095eb0888SMatt K void SfxMedium::AddToCheckEditableWorkerList()
490195eb0888SMatt K {
490295eb0888SMatt K     if (!pImpl->m_bNotifyWhenEditable)
490395eb0888SMatt K         return;
490495eb0888SMatt K 
490595eb0888SMatt K     CancelCheckEditableEntry();
490695eb0888SMatt K 
490795eb0888SMatt K     if (pImpl->m_pCheckEditableWorkerMutex == nullptr)
490895eb0888SMatt K     {
490995eb0888SMatt K         pImpl->m_pCheckEditableWorkerMutex = std::make_shared<std::recursive_mutex>();
491095eb0888SMatt K         if (pImpl->m_pCheckEditableWorkerMutex == nullptr)
491195eb0888SMatt K             return;
491295eb0888SMatt K     }
491395eb0888SMatt K 
491495eb0888SMatt K     pImpl->m_pIsDestructed = std::make_shared<bool>(false);
491595eb0888SMatt K     if (pImpl->m_pIsDestructed == nullptr)
491695eb0888SMatt K         return;
491795eb0888SMatt K 
491895eb0888SMatt K     std::unique_lock<std::mutex> globalLock(g_chkReadOnlyGlobalMutex);
491995eb0888SMatt K     if (g_newReadOnlyDocs.find(this) == g_newReadOnlyDocs.end())
492095eb0888SMatt K     {
492195eb0888SMatt K         bool bAddNewEntry = false;
492295eb0888SMatt K         if (!g_bChkReadOnlyTaskRunning)
492395eb0888SMatt K         {
492495eb0888SMatt K             std::shared_ptr<comphelper::ThreadTaskTag> pTag
492595eb0888SMatt K                 = comphelper::ThreadPool::createThreadTaskTag();
492695eb0888SMatt K             if (pTag != nullptr)
492795eb0888SMatt K             {
492895eb0888SMatt K                 g_bChkReadOnlyTaskRunning = true;
492995eb0888SMatt K                 bAddNewEntry = true;
493095eb0888SMatt K                 comphelper::ThreadPool::getSharedOptimalPool().pushTask(
493195eb0888SMatt K                     std::make_unique<CheckReadOnlyTask>(pTag));
493295eb0888SMatt K             }
493395eb0888SMatt K         }
493495eb0888SMatt K         else
493595eb0888SMatt K             bAddNewEntry = true;
493695eb0888SMatt K 
493795eb0888SMatt K         if (bAddNewEntry)
493895eb0888SMatt K         {
493995eb0888SMatt K             std::shared_ptr<ReadOnlyMediumEntry> newEntry = std::make_shared<ReadOnlyMediumEntry>(
494095eb0888SMatt K                 pImpl->m_pCheckEditableWorkerMutex, pImpl->m_pIsDestructed);
494195eb0888SMatt K 
494295eb0888SMatt K             if (newEntry != nullptr)
494395eb0888SMatt K             {
49444177e553SCaolán McNamara                 g_newReadOnlyDocs[this] = std::move(newEntry);
494595eb0888SMatt K             }
494695eb0888SMatt K         }
494795eb0888SMatt K     }
494895eb0888SMatt K }
494995eb0888SMatt K 
495095eb0888SMatt K // should only be called on main thread
CancelCheckEditableEntry(bool bRemoveEvent)495195eb0888SMatt K void SfxMedium::CancelCheckEditableEntry(bool bRemoveEvent)
495295eb0888SMatt K {
495395eb0888SMatt K     if (pImpl->m_pCheckEditableWorkerMutex != nullptr)
495495eb0888SMatt K     {
495595eb0888SMatt K         std::unique_lock<std::recursive_mutex> lock(*(pImpl->m_pCheckEditableWorkerMutex));
495695eb0888SMatt K 
495795eb0888SMatt K         if (pImpl->m_pReloadEvent != nullptr)
495895eb0888SMatt K         {
495995eb0888SMatt K             if (bRemoveEvent)
496095eb0888SMatt K                 Application::RemoveUserEvent(pImpl->m_pReloadEvent);
496195eb0888SMatt K             // make sure destructor doesn't use a freed reference
496295eb0888SMatt K             // and reset the event so we can check again
496395eb0888SMatt K             pImpl->m_pReloadEvent = nullptr;
496495eb0888SMatt K         }
496595eb0888SMatt K 
496695eb0888SMatt K         if (pImpl->m_pIsDestructed != nullptr)
496795eb0888SMatt K         {
496895eb0888SMatt K             *(pImpl->m_pIsDestructed) = true;
496995eb0888SMatt K             pImpl->m_pIsDestructed = nullptr;
497095eb0888SMatt K         }
497195eb0888SMatt K     }
497295eb0888SMatt K }
497395eb0888SMatt K 
497495eb0888SMatt K /** callback function, which is triggered by worker thread after successfully checking if the file
497595eb0888SMatt K      is editable. Sent from <Application::PostUserEvent(..)>
497695eb0888SMatt K      Note: This method has to be run in the main thread.
497795eb0888SMatt K */
IMPL_STATIC_LINK(SfxMedium,ShowReloadEditableDialog,void *,p,void)497895eb0888SMatt K IMPL_STATIC_LINK(SfxMedium, ShowReloadEditableDialog, void*, p, void)
497995eb0888SMatt K {
498095eb0888SMatt K     SfxMedium* pMed = static_cast<SfxMedium*>(p);
498195eb0888SMatt K     if (pMed == nullptr)
498295eb0888SMatt K         return;
498395eb0888SMatt K 
498495eb0888SMatt K     pMed->CancelCheckEditableEntry(false);
498595eb0888SMatt K 
498695eb0888SMatt K     uno::Reference<task::XInteractionHandler> xHandler = pMed->GetInteractionHandler();
498795eb0888SMatt K     if (xHandler.is())
498895eb0888SMatt K     {
498995eb0888SMatt K         OUString aDocumentURL
499095eb0888SMatt K             = pMed->GetURLObject().GetLastName(INetURLObject::DecodeMechanism::WithCharset);
499195eb0888SMatt K         ::rtl::Reference<::ucbhelper::InteractionRequest> xInteractionRequestImpl
49920bfa6a18SStephan Bergmann             = new ::ucbhelper::InteractionRequest(uno::Any(document::ReloadEditableRequest(
499395eb0888SMatt K                 OUString(), uno::Reference<uno::XInterface>(), aDocumentURL)));
499495eb0888SMatt K         if (xInteractionRequestImpl != nullptr)
499595eb0888SMatt K         {
4996ce22935aSMike Kaganski             uno::Sequence<uno::Reference<task::XInteractionContinuation>> aContinuations{
4997ce22935aSMike Kaganski                 new ::ucbhelper::InteractionAbort(xInteractionRequestImpl.get()),
4998ce22935aSMike Kaganski                 new ::ucbhelper::InteractionApprove(xInteractionRequestImpl.get())
4999ce22935aSMike Kaganski             };
500095eb0888SMatt K             xInteractionRequestImpl->setContinuations(aContinuations);
500195eb0888SMatt K             xHandler->handle(xInteractionRequestImpl);
500295eb0888SMatt K             ::rtl::Reference<::ucbhelper::InteractionContinuation> xSelected
500395eb0888SMatt K                 = xInteractionRequestImpl->getSelection();
5004e512091eSMike Kaganski             if (uno::Reference<task::XInteractionApprove>(cppu::getXWeak(xSelected.get()), uno::UNO_QUERY).is())
500595eb0888SMatt K             {
500695eb0888SMatt K                 for (SfxViewFrame* pFrame = SfxViewFrame::GetFirst(); pFrame;
500795eb0888SMatt K                      pFrame = SfxViewFrame::GetNext(*pFrame))
500895eb0888SMatt K                 {
500995eb0888SMatt K                     if (pFrame->GetObjectShell()->GetMedium() == pMed)
501095eb0888SMatt K                     {
501195eb0888SMatt K                         // special case to ensure view isn't set to read-only in
501295eb0888SMatt K                         // SfxViewFrame::ExecReload_Impl after reloading
501395eb0888SMatt K                         pMed->SetOriginallyReadOnly(false);
501495eb0888SMatt K                         pFrame->GetDispatcher()->Execute(SID_RELOAD);
501595eb0888SMatt K                         break;
501695eb0888SMatt K                     }
501795eb0888SMatt K                 }
501895eb0888SMatt K             }
501995eb0888SMatt K         }
502095eb0888SMatt K     }
502195eb0888SMatt K }
502295eb0888SMatt K 
CheckCanGetLockfile() const502395eb0888SMatt K bool SfxMedium::CheckCanGetLockfile() const
502495eb0888SMatt K {
502595eb0888SMatt K #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
502695eb0888SMatt K     bool bCanReload = true;
502795eb0888SMatt K #else
502895eb0888SMatt K     bool bCanReload = false;
502995eb0888SMatt K     ::svt::DocumentLockFile aLockFile(GetName());
503095eb0888SMatt K     LockFileEntry aData;
503195eb0888SMatt K     osl::DirectoryItem rItem;
503295eb0888SMatt K     auto nError1 = osl::DirectoryItem::get(aLockFile.GetURL(), rItem);
503395eb0888SMatt K     if (nError1 == osl::FileBase::E_None)
503495eb0888SMatt K     {
503595eb0888SMatt K         try
503695eb0888SMatt K         {
503795eb0888SMatt K             aData = aLockFile.GetLockData();
503895eb0888SMatt K         }
503995eb0888SMatt K         catch (const io::WrongFormatException&)
504095eb0888SMatt K         {
504195eb0888SMatt K             // we get empty or corrupt data
504295eb0888SMatt K             return false;
504395eb0888SMatt K         }
504495eb0888SMatt K         catch (const uno::Exception&)
504595eb0888SMatt K         {
504695eb0888SMatt K             // locked from other app
504795eb0888SMatt K             return false;
504895eb0888SMatt K         }
504995eb0888SMatt K         LockFileEntry aOwnData = svt::LockFileCommon::GenerateOwnEntry();
505095eb0888SMatt K         bool bOwnLock
505195eb0888SMatt K             = aOwnData[LockFileComponent::SYSUSERNAME] == aData[LockFileComponent::SYSUSERNAME];
505295eb0888SMatt K         if (bOwnLock
505395eb0888SMatt K             && aOwnData[LockFileComponent::LOCALHOST] == aData[LockFileComponent::LOCALHOST]
505495eb0888SMatt K             && aOwnData[LockFileComponent::USERURL] == aData[LockFileComponent::USERURL])
505595eb0888SMatt K         {
505695eb0888SMatt K             // this is own lock from the same installation, it could remain because of crash
505795eb0888SMatt K             bCanReload = true;
505895eb0888SMatt K         }
505995eb0888SMatt K     }
506095eb0888SMatt K     else if (nError1 == osl::FileBase::E_NOENT) // file doesn't exist
506195eb0888SMatt K     {
506295eb0888SMatt K         try
506395eb0888SMatt K         {
506495eb0888SMatt K             aLockFile.CreateOwnLockFile();
506595eb0888SMatt K             try
506695eb0888SMatt K             {
506795eb0888SMatt K                 // TODO/LATER: A warning could be shown in case the file is not the own one
506895eb0888SMatt K                 aLockFile.RemoveFile();
506995eb0888SMatt K             }
507095eb0888SMatt K             catch (const io::WrongFormatException&)
507195eb0888SMatt K             {
507295eb0888SMatt K                 try
507395eb0888SMatt K                 {
507495eb0888SMatt K                     // erase the empty or corrupt file
507595eb0888SMatt K                     aLockFile.RemoveFileDirectly();
507695eb0888SMatt K                 }
507795eb0888SMatt K                 catch (const uno::Exception&)
507895eb0888SMatt K                 {
507995eb0888SMatt K                 }
508095eb0888SMatt K             }
508195eb0888SMatt K             bCanReload = true;
508295eb0888SMatt K         }
508395eb0888SMatt K         catch (const uno::Exception&)
508495eb0888SMatt K         {
508595eb0888SMatt K         }
508695eb0888SMatt K     }
508795eb0888SMatt K #endif
508895eb0888SMatt K     return bCanReload;
508995eb0888SMatt K }
509095eb0888SMatt K 
509195eb0888SMatt K // worker thread method, should only be one thread globally
doWork()509295eb0888SMatt K void CheckReadOnlyTask::doWork()
509395eb0888SMatt K {
509495eb0888SMatt K     if (m_xListener == nullptr)
509595eb0888SMatt K         return;
509695eb0888SMatt K 
509795eb0888SMatt K     while (true)
509895eb0888SMatt K     {
509995eb0888SMatt K         std::unique_lock<std::mutex> termLock(m_xListener->mMutex);
510095eb0888SMatt K         if (m_xListener->mCond.wait_for(termLock, std::chrono::seconds(60),
510195eb0888SMatt K                                         [this] { return m_xListener->bIsTerminated; }))
510295eb0888SMatt K             // signalled, spurious wakeups should not be possible
510395eb0888SMatt K             return;
510495eb0888SMatt K 
510595eb0888SMatt K         // must have timed-out
510695eb0888SMatt K         termLock.unlock();
510795eb0888SMatt K         std::unique_lock<std::mutex> globalLock(g_chkReadOnlyGlobalMutex);
51086772ed1dSNoel Grandin         for (auto it = g_newReadOnlyDocs.begin(); it != g_newReadOnlyDocs.end(); )
510995eb0888SMatt K         {
511020c015f2SCaolán McNamara             g_existingReadOnlyDocs[it->first] = it->second;
51116772ed1dSNoel Grandin             it = g_newReadOnlyDocs.erase(it);
511295eb0888SMatt K         }
51130d5bd921SJulien Nabet         if (g_existingReadOnlyDocs.empty())
511495eb0888SMatt K         {
511595eb0888SMatt K             g_bChkReadOnlyTaskRunning = false;
511695eb0888SMatt K             return;
511795eb0888SMatt K         }
511895eb0888SMatt K         globalLock.unlock();
511995eb0888SMatt K 
51206772ed1dSNoel Grandin         auto checkForErase = [](SfxMedium* pMed, const std::shared_ptr<ReadOnlyMediumEntry>& roEntry) -> bool
512195eb0888SMatt K         {
512295eb0888SMatt K             if (pMed == nullptr || roEntry == nullptr || roEntry->_pMutex == nullptr
512395eb0888SMatt K                 || roEntry->_pIsDestructed == nullptr)
51246772ed1dSNoel Grandin                 return true;
512595eb0888SMatt K 
512695eb0888SMatt K             std::unique_lock<std::recursive_mutex> medLock(*(roEntry->_pMutex));
512795eb0888SMatt K             if (*(roEntry->_pIsDestructed) || pMed->GetWorkerReloadEvent() != nullptr)
51286772ed1dSNoel Grandin                 return true;
51296772ed1dSNoel Grandin 
513095eb0888SMatt K             osl::File aFile(
513195eb0888SMatt K                 pMed->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::WithCharset));
513295eb0888SMatt K             if (aFile.open(osl_File_OpenFlag_Write) != osl::FileBase::E_None)
51336772ed1dSNoel Grandin                 return false;
513495eb0888SMatt K 
513595eb0888SMatt K             if (!pMed->CheckCanGetLockfile())
51366772ed1dSNoel Grandin                 return false;
513795eb0888SMatt K 
513895eb0888SMatt K             if (aFile.close() != osl::FileBase::E_None)
51396772ed1dSNoel Grandin                 return true;
514095eb0888SMatt K 
514195eb0888SMatt K             // we can load, ask user
514295eb0888SMatt K             ImplSVEvent* pEvent = Application::PostUserEvent(
514395eb0888SMatt K                 LINK(nullptr, SfxMedium, ShowReloadEditableDialog), pMed);
514495eb0888SMatt K             pMed->SetWorkerReloadEvent(pEvent);
51456772ed1dSNoel Grandin             return true;
51466772ed1dSNoel Grandin         };
51476772ed1dSNoel Grandin 
51486772ed1dSNoel Grandin         for (auto it = g_existingReadOnlyDocs.begin(); it != g_existingReadOnlyDocs.end(); )
51496772ed1dSNoel Grandin         {
51506772ed1dSNoel Grandin             if (checkForErase(it->first, it->second))
51516772ed1dSNoel Grandin                 it = g_existingReadOnlyDocs.erase(it);
51526772ed1dSNoel Grandin             else
51536772ed1dSNoel Grandin                 ++it;
515495eb0888SMatt K         }
515595eb0888SMatt K     }
515695eb0888SMatt K }
515795eb0888SMatt K 
51588694d2bcSSebastian Spaeth /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
5159