basctl/source/basicide/docsignature.cxx                     |    2 
 include/sfx2/digitalsignatures.hxx                          |    8 +
 include/sfx2/docfile.hxx                                    |    3 
 include/sfx2/objsh.hxx                                      |    2 
 offapi/com/sun/star/security/XDocumentDigitalSignatures.idl |    2 
 sfx2/source/doc/docfile.cxx                                 |   85 ++++++++----
 sfx2/source/doc/objserv.cxx                                 |   51 ++++---
 xmlsecurity/source/component/documentdigitalsignatures.cxx  |   20 ++
 8 files changed, 121 insertions(+), 52 deletions(-)

New commits:
commit 38122c330d6b1cb002e6de16dfc3a1dd7fcbb3bc
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Sep 9 09:11:06 2024 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Sep 12 11:29:30 2024 +0200

    cool#9992 lok doc sign: async 
DocumentDigitalSignatures::signDocumentContent()
    
    Currently SfxObjectShell::CheckIsReadonly() has a hack for the LOK case
    to show the signatures dialog read-only, as only that is async.
    
    The next step is to make
    DocumentDigitalSignatures::signDocumentContent() async, but passing an
    std::function via the UNO API is tricky.
    
    Notice how DocumentDigitalSignatures in xmlsecurity/ also implements
    sfx2::DigitalSignatures, add a new SignDocumentContentAsync() there and
    adapt all uses of signDocumentContent() to go with that instead.
    
    This requires introducing some lambdas for code after
    signDocumentContent() in general and for ODF/OOXML specific code in
    particular, to avoid code duplication.
    
    (cherry picked from commit caff013bee53216efeb49db4bcda44b55c223b58)
    
    Change-Id: If771ced711041364988af45ad9dd0dd1a2a8660d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173118
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/include/sfx2/digitalsignatures.hxx 
b/include/sfx2/digitalsignatures.hxx
index b46cdd52e9d9..bb0abd6e54e3 100644
--- a/include/sfx2/digitalsignatures.hxx
+++ b/include/sfx2/digitalsignatures.hxx
@@ -9,6 +9,8 @@
 
 #pragma once
 
+#include <functional>
+
 #include <com/sun/star/embed/XStorage.hpp>
 #include <com/sun/star/frame/XModel.hpp>
 #include <com/sun/star/io/XStream.hpp>
@@ -30,6 +32,12 @@ public:
                              const css::uno::Reference<css::io::XStream>& 
xStream)
         = 0;
 
+    /// Async replacement for signDocumentContent().
+    virtual void SignDocumentContentAsync(const 
css::uno::Reference<css::embed::XStorage>& xStorage,
+                                          const 
css::uno::Reference<css::io::XStream>& xSignStream,
+                                          const std::function<void(bool)>& 
rCallback)
+        = 0;
+
 protected:
     ~DigitalSignatures() noexcept = default;
 };
diff --git a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl 
b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl
index a90304313582..58dfe915ba10 100644
--- a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl
+++ b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl
@@ -32,6 +32,8 @@ interface XDocumentDigitalSignatures : 
com::sun::star::uno::XInterface
     /** signs the content of the document including text and pictures.
 
        <p>Macros will not be signed.</p>
+
+       Deprecated, this synchronous version would block the UI till signing is 
in progress.
      */
     boolean signDocumentContent( [in] ::com::sun::star::embed::XStorage 
xStorage,
                                  [in] ::com::sun::star::io::XStream 
xSignStream);
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index ca38ff5f9fb9..2b7a1fb82453 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -4332,6 +4332,14 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
     CreateTempFile( false );
     GetMedium_Impl();
 
+    auto onSignDocumentContentFinished = [this, rCallback](bool bRet) {
+        CloseAndRelease();
+
+        ResetError();
+
+        rCallback(bRet);
+    };
+
     try
     {
         if ( !pImpl->xStream.is() )
@@ -4420,6 +4428,8 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
         }
         else
         {
+            auto xModelSigner = 
dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get());
+            assert(xModelSigner);
             if (xMetaInf.is())
             {
                 // ODF.
@@ -4428,23 +4438,37 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
                     
xStream.set(xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(),
 embed::ElementModes::READWRITE), uno::UNO_SET_THROW);
 
                 bool bSuccess = false;
+                auto onODFSignDocumentContentFinished = [this, xMetaInf, 
xWriteableZipStor]() {
+                    uno::Reference< embed::XTransactedObject > xTransact( 
xMetaInf, uno::UNO_QUERY_THROW );
+                    xTransact->commit();
+                    xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
+                    xTransact->commit();
+
+                    // the temporary file has been written, commit it to the 
original file
+                    Commit();
+                };
                 if (xCert.is())
                     bSuccess = xSigner->signSignatureLine(
                         GetZipStorageToSign_Impl(), xStream, aSignatureLineId, 
xCert,
                         xValidGraphic, xInvalidGraphic, aComment);
                 else
-                    bSuccess = 
xSigner->signDocumentContent(GetZipStorageToSign_Impl(),
-                                                            xStream);
+                {
+                    // Async, all code before return has to go into the 
callback.
+                    
xModelSigner->SignDocumentContentAsync(GetZipStorageToSign_Impl(),
+                                                            xStream, 
[onODFSignDocumentContentFinished, onSignDocumentContentFinished](bool bRet) {
+                        if (bRet)
+                        {
+                            onODFSignDocumentContentFinished();
+                        }
+
+                        onSignDocumentContentFinished(bRet);
+                    });
+                    return;
+                }
 
                 if (bSuccess)
                 {
-                    uno::Reference< embed::XTransactedObject > xTransact( 
xMetaInf, uno::UNO_QUERY_THROW );
-                    xTransact->commit();
-                    xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
-                    xTransact->commit();
-
-                    // the temporary file has been written, commit it to the 
original file
-                    Commit();
+                    onODFSignDocumentContentFinished();
                     bChanges = true;
                 }
             }
@@ -4453,6 +4477,13 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
                 // OOXML.
                 uno::Reference<io::XStream> xStream;
 
+                auto onOOXMLSignDocumentContentFinished = [this, 
xWriteableZipStor]() {
+                    uno::Reference<embed::XTransactedObject> 
xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
+                    xTransact->commit();
+
+                    // the temporary file has been written, commit it to the 
original file
+                    Commit();
+                };
                 bool bSuccess = false;
                 if (xCert.is())
                 {
@@ -4463,17 +4494,21 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
                 else
                 {
                     // We need read-write to be able to add the signature 
relation.
-                    bSuccess =xSigner->signDocumentContent(
-                        GetZipStorageToSign_Impl(/*bReadOnly=*/false), 
xStream);
+                    xModelSigner->SignDocumentContentAsync(
+                        GetZipStorageToSign_Impl(/*bReadOnly=*/false), 
xStream, [onOOXMLSignDocumentContentFinished, 
onSignDocumentContentFinished](bool bRet) {
+                        if (bRet)
+                        {
+                            onOOXMLSignDocumentContentFinished();
+                        }
+
+                        onSignDocumentContentFinished(bRet);
+                    });
+                    return;
                 }
 
                 if (bSuccess)
                 {
-                    uno::Reference<embed::XTransactedObject> 
xTransact(xWriteableZipStor, uno::UNO_QUERY_THROW);
-                    xTransact->commit();
-
-                    // the temporary file has been written, commit it to the 
original file
-                    Commit();
+                    onOOXMLSignDocumentContentFinished();
                     bChanges = true;
                 }
             }
@@ -4482,8 +4517,10 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
                 // Something not ZIP based: e.g. PDF.
                 std::unique_ptr<SvStream> 
pStream(utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ | 
StreamMode::WRITE));
                 uno::Reference<io::XStream> xStream(new 
utl::OStreamWrapper(*pStream));
-                if 
(xSigner->signDocumentContent(uno::Reference<embed::XStorage>(), xStream))
-                    bChanges = true;
+                
xModelSigner->SignDocumentContentAsync(uno::Reference<embed::XStorage>(), 
xStream, [onSignDocumentContentFinished](bool bRet) {
+                    onSignDocumentContentFinished(bRet);
+                });
+                return;
             }
         }
     }
@@ -4492,11 +4529,7 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
         TOOLS_WARN_EXCEPTION("sfx.doc", "Couldn't use signing functionality!");
     }
 
-    CloseAndRelease();
-
-    ResetError();
-
-    rCallback(bChanges);
+    onSignDocumentContentFinished(bChanges);
 }
 
 
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx 
b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index c1768c0e953a..7d4c96e78679 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -217,6 +217,10 @@ public:
                              const 
css::uno::Reference<css::security::XCertificate>& xCertificate,
                              const css::uno::Reference<css::embed::XStorage>& 
xStorage,
                              const css::uno::Reference<css::io::XStream>& 
xStream) override;
+    /// See sfx2::DigitalSignatures::SignDocumentContentAsync().
+    void SignDocumentContentAsync(const 
css::uno::Reference<css::embed::XStorage>& xStorage,
+                                  const css::uno::Reference<css::io::XStream>& 
xSignStream,
+                                  const std::function<void(bool)>& rCallback) 
override;
 };
 
 }
@@ -278,11 +282,10 @@ DocumentDigitalSignatures::getSupportedServiceNames()
 }
 
 sal_Bool DocumentDigitalSignatures::signDocumentContent(
-    const Reference< css::embed::XStorage >& rxStorage,
-    const Reference< css::io::XStream >& xSignStream)
+    const Reference< css::embed::XStorage >& /*rxStorage*/,
+    const Reference< css::io::XStream >& /*xSignStream*/)
 {
-    OSL_ENSURE(!m_sODFVersion.isEmpty(), "DocumentDigitalSignatures: ODF 
Version not set, assuming minimum 1.2");
-    return ImplViewSignatures( rxStorage, xSignStream, 
DocumentSignatureMode::Content, false );
+    for (;;) { std::abort(); } // avoid "must return a value" warnings
 }
 
 sal_Bool DocumentDigitalSignatures::signSignatureLine(
@@ -830,6 +833,15 @@ bool DocumentDigitalSignatures::SignModelWithCertificate(
                                    DocumentSignatureMode::Content);
 }
 
+void DocumentDigitalSignatures::SignDocumentContentAsync(const 
css::uno::Reference<css::embed::XStorage>& rxStorage,
+                              const css::uno::Reference<css::io::XStream>& 
xSignStream,
+                              const std::function<void(bool)>& rCallback)
+{
+    OSL_ENSURE(!m_sODFVersion.isEmpty(), "DocumentDigitalSignatures: ODF 
Version not set, assuming minimum 1.2");
+    bool bRet = ImplViewSignatures( rxStorage, xSignStream, 
DocumentSignatureMode::Content, false );
+    rCallback(bRet);
+}
+
 sal_Bool DocumentDigitalSignatures::signPackageWithCertificate(
     css::uno::Reference<css::security::XCertificate> const& xCertificate,
     css::uno::Reference<css::embed::XStorage> const& xStorage,
commit 11af9233ab7b2ff40eaa45922f38fe65b14ff881
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Sep 6 09:47:25 2024 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Sep 12 11:29:20 2024 +0200

    cool#9992 lok doc sign: make SfxMedium::SignContents_Impl() async
    
    Currently SfxObjectShell::CheckIsReadonly() has a hack for the LOK case
    to show the signatures dialog read-only, as only that is async.
    
    The next step to get rid of this hack is to make
    SfxMedium::SignContents_Impl() async, now that
    SfxObjectShell::SignDocumentContent() is async.
    
    This requires all callers of SfxMedium::SignContents_Impl() to be async,
    most notably SfxObjectShell::SignScriptingContent() has to be converted
    as well.
    
    Note that no lifecycle problem is expected here for the callback, since
    the object shell and its medium is typically around for as long as the
    document is loaded.
    
    (cherry picked from commit de0bc0a2c30a76144b47e9abb17770043813133c)
    
    Change-Id: I57f2c747f8448b9adc0398f874ede36211fed817
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173062
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/basctl/source/basicide/docsignature.cxx 
b/basctl/source/basicide/docsignature.cxx
index 08d7a1ab9c13..ee04435274db 100644
--- a/basctl/source/basicide/docsignature.cxx
+++ b/basctl/source/basicide/docsignature.cxx
@@ -60,7 +60,7 @@ namespace basctl
     {
         OSL_PRECOND( supportsSignatures(), 
"DocumentSignature::signScriptingContent: signatures not supported by this 
document!" );
         if ( m_pShell )
-            m_pShell->SignScriptingContent(pDialogParent);
+            m_pShell->SignScriptingContent(pDialogParent, [](bool 
/*bSigned*/){});
     }
 
     SignatureState DocumentSignature::getScriptingSignatureState() const
diff --git a/include/sfx2/docfile.hxx b/include/sfx2/docfile.hxx
index fb8039f6b8f1..01046aa66789 100644
--- a/include/sfx2/docfile.hxx
+++ b/include/sfx2/docfile.hxx
@@ -270,9 +270,10 @@ public:
                              const INetURLObject& aDest,
                              const css::uno::Reference< 
css::ucb::XCommandEnvironment >& xComEnv );
 
-    SAL_DLLPRIVATE bool
+    SAL_DLLPRIVATE void
     SignContents_Impl(weld::Window* pDialogParent,
                       bool bSignScriptingContent, bool 
bHasValidDocumentSignature,
+                      const std::function<void(bool)>& rCallback,
                       const OUString& aSignatureLineId = OUString(),
                       const css::uno::Reference<css::security::XCertificate>& 
xCert
                       = css::uno::Reference<css::security::XCertificate>(),
diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx
index b3b55286b349..0b9a456b0b0c 100644
--- a/include/sfx2/objsh.hxx
+++ b/include/sfx2/objsh.hxx
@@ -375,7 +375,7 @@ public:
                            const css::uno::Reference<css::graphic::XGraphic>& 
xInvalidGraphic,
                            const OUString& aComment);
     SignatureState              GetScriptingSignatureState();
-    bool                        SignScriptingContent(weld::Window* 
pDialogParent);
+    void SignScriptingContent(weld::Window* pDialogParent, const 
std::function<void(bool)>& rCallback);
     DECL_DLLPRIVATE_LINK(SignDocumentHandler, weld::Button&, void);
 
     virtual std::shared_ptr<SfxDocumentInfoDialog> 
CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet);
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index ba45c8eb9250..ca38ff5f9fb9 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -4298,9 +4298,10 @@ bool SfxMedium::SignDocumentContentUsingCertificate(
 }
 
 // note: this is the only function creating scripting signature
-bool SfxMedium::SignContents_Impl(weld::Window* pDialogParent,
+void SfxMedium::SignContents_Impl(weld::Window* pDialogParent,
                                   bool bSignScriptingContent,
                                   bool bHasValidDocumentSignature,
+                                  const std::function<void(bool)>& rCallback,
                                   const OUString& aSignatureLineId,
                                   const Reference<XCertificate>& xCert,
                                   const Reference<XGraphic>& xValidGraphic,
@@ -4312,7 +4313,8 @@ bool SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
     if (IsOpen() || GetErrorIgnoreWarning())
     {
         SAL_WARN("sfx.doc", "The medium must be closed by the signer!");
-        return bChanges;
+        rCallback(bChanges);
+        return;
     }
 
     // The component should know if there was a valid document signature, since
@@ -4494,7 +4496,7 @@ bool SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
 
     ResetError();
 
-    return bChanges;
+    rCallback(bChanges);
 }
 
 
diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx
index eaf8cf71cece..535facf5c81d 100644
--- a/sfx2/source/doc/objserv.cxx
+++ b/sfx2/source/doc/objserv.cxx
@@ -617,7 +617,11 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
         }
         else
         {
-            bHaveWeSigned |= SignScriptingContent(pDialogParent);
+            // Async, all code before return has to go into the callback.
+            SignScriptingContent(pDialogParent, [this, pDialogParent] (bool 
bSigned) {
+                AfterSignContent(bSigned, pDialogParent);
+            });
+            return;
         }
 
         AfterSignContent(bHaveWeSigned, pDialogParent);
@@ -2142,11 +2146,12 @@ void SfxObjectShell::SignDocumentContent(weld::Window* 
pDialogParent, const std:
         return;
     }
 
-    bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, false, 
HasValidSignatures());
-
-    AfterSigning(bSignSuccess, false);
+    // Async, all code before the end has to go into the callback.
+    GetMedium()->SignContents_Impl(pDialogParent, false, HasValidSignatures(), 
[this, rCallback](bool bSignSuccess) {
+            AfterSigning(bSignSuccess, false);
 
-    rCallback(bSignSuccess);
+            rCallback(bSignSuccess);
+    });
 }
 
 bool SfxObjectShell::ResignDocument(uno::Sequence< 
security::DocumentSignatureInformation >& rSignaturesInfo)
@@ -2257,15 +2262,15 @@ void SfxObjectShell::SignSignatureLine(weld::Window* 
pDialogParent,
     if (CheckIsReadonly(false, pDialogParent))
         return;
 
-    bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent,
-        false, HasValidSignatures(), aSignatureLineId, xCert, xValidGraphic, 
xInvalidGraphic, aComment);
-
-    AfterSigning(bSignSuccess, false);
+    GetMedium()->SignContents_Impl(pDialogParent,
+        false, HasValidSignatures(), [this](bool bSignSuccess) {
+        AfterSigning(bSignSuccess, false);
 
-    // Reload the document to get the updated graphic
-    // FIXME: Update just the signature line graphic instead of reloading the 
document
-    if (SfxViewFrame* pFrame = GetFrame())
-        pFrame->GetDispatcher()->Execute(SID_RELOAD);
+        // Reload the document to get the updated graphic
+        // FIXME: Update just the signature line graphic instead of reloading 
the document
+        if (SfxViewFrame* pFrame = GetFrame())
+            pFrame->GetDispatcher()->Execute(SID_RELOAD);
+    }, aSignatureLineId, xCert, xValidGraphic, xInvalidGraphic, aComment);
 }
 
 SignatureState SfxObjectShell::GetScriptingSignatureState()
@@ -2273,19 +2278,25 @@ SignatureState 
SfxObjectShell::GetScriptingSignatureState()
     return ImplGetSignatureState( true );
 }
 
-bool SfxObjectShell::SignScriptingContent(weld::Window* pDialogParent)
+void SfxObjectShell::SignScriptingContent(weld::Window* pDialogParent, const 
std::function<void(bool)>& rCallback)
 {
     if (!PrepareForSigning(pDialogParent))
-        return false;
+    {
+        rCallback(false);
+        return;
+    }
 
     if (CheckIsReadonly(true, pDialogParent))
-        return false;
-
-    bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, true, 
HasValidSignatures());
+    {
+        rCallback(false);
+        return;
+    }
 
-    AfterSigning(bSignSuccess, true);
+    GetMedium()->SignContents_Impl(pDialogParent, true, HasValidSignatures(), 
[this, rCallback](bool bSignSuccess) {
+        AfterSigning(bSignSuccess, true);
 
-    return bSignSuccess;
+        rCallback(bSignSuccess);
+    });
 }
 
 const uno::Sequence<sal_Int8>& SfxObjectShell::getUnoTunnelId()

Reply via email to