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