include/sfx2/digitalsignatures.hxx                          |    8 +
 offapi/com/sun/star/security/XDocumentDigitalSignatures.idl |    2 
 sfx2/source/doc/docfile.cxx                                 |   79 ++++++++----
 xmlsecurity/source/component/documentdigitalsignatures.cxx  |   20 ++-
 4 files changed, 82 insertions(+), 27 deletions(-)

New commits:
commit caff013bee53216efeb49db4bcda44b55c223b58
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Sep 9 09:11:06 2024 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Sep 9 17:30:28 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.
    
    Change-Id: If771ced711041364988af45ad9dd0dd1a2a8660d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173060
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@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 d85be941c8d1..cd201d080f82 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 ee9308f51bfe..2d8290a6476a 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -4338,6 +4338,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() )
@@ -4426,6 +4434,8 @@ void SfxMedium::SignContents_Impl(weld::Window* 
pDialogParent,
         }
         else
         {
+            auto xModelSigner = 
dynamic_cast<sfx2::DigitalSignatures*>(xSigner.get());
+            assert(xModelSigner);
             if (xMetaInf.is())
             {
                 // ODF.
@@ -4434,23 +4444,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;
                 }
             }
@@ -4459,6 +4483,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())
                 {
@@ -4469,17 +4500,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;
                 }
             }
@@ -4488,8 +4523,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;
             }
         }
     }
@@ -4498,11 +4535,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 c49b7427f67d..31b965a63765 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -212,6 +212,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;
 };
 
 }
@@ -273,11 +277,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(
@@ -827,6 +830,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,

Reply via email to