    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   Licensed to the Apache Software Foundation (ASF) under one or more
     *   contributor license agreements. See the NOTICE file distributed
     *   with this work for additional information regarding copyright
     *   ownership. The ASF licenses this file to you under the Apache
     *   License, Version 2.0 (the "License"); you may not use this file
     *   except in compliance with the License. You may obtain a copy of
     *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
     */

    #include <digitalsignaturesdialog.hxx>
    #include <certificatechooser.hxx>
    #include <certificateviewer.hxx>
    #include <biginteger.hxx>
    #include <sax/tools/converter.hxx>

    #include <com/sun/star/embed/XStorage.hpp>
    #include <com/sun/star/embed/ElementModes.hpp>
    #include <com/sun/star/embed/StorageFormats.hpp>
    #include <com/sun/star/container/XNameAccess.hpp>
    #include <com/sun/star/lang/XComponent.hpp>
    #include <com/sun/star/security/NoPasswordException.hpp>
    #include <com/sun/star/lang/DisposedException.hpp>
    #include <com/sun/star/beans/XPropertySet.hpp>
    #include <com/sun/star/security/CertificateValidity.hpp>
    #include <com/sun/star/packages/WrongPasswordException.hpp>
    #include <com/sun/star/security/CertificateKind.hpp>
    #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
    #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
    #include <com/sun/star/packages/manifest/ManifestReader.hpp>
    #include <com/sun/star/system/SystemShellExecute.hpp>
    #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
    #include <com/sun/star/system/SystemShellExecuteException.hpp>

    #include <osl/file.hxx>
    #include <rtl/ustrbuf.hxx>
    #include <rtl/uri.hxx>
    #include <sal/log.hxx>

    #include <tools/date.hxx>
    #include <tools/time.hxx>
    #include <svtools/treelistentry.hxx>

    #include <strings.hrc>
    #include <resourcemanager.hxx>

    #include <vcl/weld.hxx>
    #include <unotools/configitem.hxx>

    using namespace css::security;
    using namespace css::uno;
    using namespace css;

    namespace
    {
        class SaveODFItem: public utl::ConfigItem
        {
        private:
            sal_Int16 m_nODF;

            virtual void ImplCommit() override;

        public:
        virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override;
            SaveODFItem();
            //See group ODF in Common.xcs
            bool isLessODF1_2()
            {
                return m_nODF < 3;
            }
        };

        void SaveODFItem::ImplCommit() {}
        void SaveODFItem::Notify( const css::uno::Sequence< OUString >& ) {}

        SaveODFItem::SaveODFItem(): utl::ConfigItem("Office.Common/Save"), m_nODF(0)
        {
            OUString sDef("ODF/DefaultVersion");
            Sequence< css::uno::Any > aValues = GetProperties( Sequence<OUString>(&sDef,1) );
            if ( aValues.getLength() != 1)
                throw uno::RuntimeException(
                    "[xmlsecurity] Could not open property Office.Common/Save/ODF/DefaultVersion",
                    nullptr);

            sal_Int16 nTmp = 0;
            if ( !(aValues[0] >>= nTmp) )
                throw uno::RuntimeException(
                    "[xmlsecurity]SaveODFItem::SaveODFItem(): Wrong Type!",
                    nullptr );

            m_nODF = nTmp;
        }
    }

    DigitalSignaturesDialog::DigitalSignaturesDialog(
        vcl::Window* pParent,
        uno::Reference< uno::XComponentContext >& rxCtx, DocumentSignatureMode eMode,
        bool bReadOnly, const OUString& sODFVersion, bool bHasDocumentSignature)
        : ModalDialog(pParent, "DigitalSignaturesDialog", "xmlsec/ui/digitalsignaturesdialog.ui")
        , mxCtx(rxCtx)
        , maSignatureManager(rxCtx, eMode)
        , m_sODFVersion (sODFVersion)
        , m_bHasDocumentSignature(bHasDocumentSignature)
        , m_bWarningShowSignMacro(false)
    {
        get(m_pHintDocFT, "dochint");
        get(m_pHintBasicFT, "macrohint");
        get(m_pHintPackageFT, "packagehint");
        get(m_pAdESCompliantCB, "adescompliant");
        get(m_pViewBtn, "view");
        get(m_pAddBtn, "sign");
        get(m_pRemoveBtn, "remove");
        get(m_pCloseBtn, "close");
        get(m_pStartCertMgrBtn, "start_certmanager");
        get(m_pSigsValidImg, "validimg");
        get(m_pSigsValidFI, "validft");
        get(m_pSigsInvalidImg, "invalidimg");
        get(m_pSigsInvalidFI, "invalidft");
        get(m_pSigsNotvalidatedImg, "notvalidatedimg");
        get(m_pSigsNotvalidatedFI, "notvalidatedft");
        get(m_pSigsOldSignatureImg, "oldsignatureimg");
        get(m_pSigsOldSignatureFI, "oldsignatureft");

        m_bAdESCompliant = !DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);

        Size aControlSize(375, 109);
        const long nControlWidth = aControlSize.Width();
        aControlSize = LogicToPixel(aControlSize, MapMode(MapUnit::MapAppFont));
        SvSimpleTableContainer *pSignatures = get<SvSimpleTableContainer>("signatures");
        pSignatures->set_width_request(aControlSize.Width());
        pSignatures->set_height_request(aControlSize.Height());

        m_pSignaturesLB = VclPtr<SvSimpleTable>::Create(*pSignatures);
        // Give the first column 6 percent, try to distribute the rest equally.
        static long aTabs[] = { 0, 6*nControlWidth/100, 25*nControlWidth/100, 44*nControlWidth/100, 62*nControlWidth/100, 81*nControlWidth/100 };
        m_pSignaturesLB->SetTabs(SAL_N_ELEMENTS(aTabs), aTabs);

        m_pSignaturesLB->InsertHeaderEntry("\t" + get<FixedText>("signed")->GetText() + "\t"
                   + get<FixedText>("issued")->GetText() + "\t" + get<FixedText>("date")->GetText() + "\t"
                   + get<FixedText>("description")->GetText() + "\t" + get<FixedText>("type")->GetText());

        mbVerifySignatures = true;
        mbSignaturesChanged = false;

        m_pSignaturesLB->SetSelectHdl( LINK( this, DigitalSignaturesDialog, SignatureHighlightHdl ) );
        m_pSignaturesLB->SetDoubleClickHdl( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) );

        m_pAdESCompliantCB->SetToggleHdl( LINK( this, DigitalSignaturesDialog, AdESCompliantCheckBoxHdl ) );
        m_pAdESCompliantCB->Check(m_bAdESCompliant);

        m_pViewBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) );
        m_pViewBtn->Disable();

        m_pAddBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, AddButtonHdl ) );
        if ( bReadOnly  )
            m_pAddBtn->Disable();

        m_pRemoveBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, RemoveButtonHdl ) );
        m_pRemoveBtn->Disable();

        m_pStartCertMgrBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, CertMgrButtonHdl ) );

        m_pCloseBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, OKButtonHdl) );

        switch( maSignatureManager.meSignatureMode )
        {
            case DocumentSignatureMode::Content:
                m_pHintDocFT->Show();
                break;
            case DocumentSignatureMode::Macros:
                m_pHintBasicFT->Show();
                break;
            case DocumentSignatureMode::Package:
                m_pHintPackageFT->Show();
                break;
        }
    }

    DigitalSignaturesDialog::~DigitalSignaturesDialog()
    {
        disposeOnce();
    }

    void DigitalSignaturesDialog::dispose()
    {
        m_pSignaturesLB.disposeAndClear();
        m_pHintDocFT.clear();
        m_pHintBasicFT.clear();
        m_pHintPackageFT.clear();
        m_pSigsValidImg.clear();
        m_pSigsValidFI.clear();
        m_pSigsInvalidImg.clear();
        m_pSigsInvalidFI.clear();
        m_pSigsNotvalidatedImg.clear();
        m_pSigsNotvalidatedFI.clear();
        m_pSigsOldSignatureImg.clear();
        m_pSigsOldSignatureFI.clear();
        m_pAdESCompliantCB.clear();
        m_pViewBtn.clear();
        m_pAddBtn.clear();
        m_pRemoveBtn.clear();
        m_pCloseBtn.clear();
        m_pStartCertMgrBtn.clear();
        ModalDialog::dispose();
    }

    bool DigitalSignaturesDialog::Init()
    {
        bool bInit = maSignatureManager.init();

        SAL_WARN_IF( !bInit, "xmlsecurity.dialogs", "Error initializing security context!" );

        if ( bInit )
        {
            maSignatureManager.maSignatureHelper.SetStartVerifySignatureHdl( LINK( this, DigitalSignaturesDialog, StartVerifySignatureHdl ) );
        }

        return bInit;
    }

    void DigitalSignaturesDialog::SetStorage( const css::uno::Reference < css::embed::XStorage >& rxStore )
    {
        if (!rxStore.is())
        {
            // PDF supports AdES.
            m_bAdESCompliant = true;
            m_pAdESCompliantCB->Check(m_bAdESCompliant);
            return;
        }

        maSignatureManager.mxStore = rxStore;
        maSignatureManager.maSignatureHelper.SetStorage( maSignatureManager.mxStore, m_sODFVersion);

        Reference < css::packages::manifest::XManifestReader > xReader =
            css::packages::manifest::ManifestReader::create(mxCtx);

        uno::Reference<container::XNameAccess> xNameAccess(rxStore, uno::UNO_QUERY);
        if (!xNameAccess.is())
            return;

        if (xNameAccess->hasByName("META-INF"))
        {
            //Get the manifest.xml
            Reference < css::embed::XStorage > xSubStore(rxStore->openStorageElement(
                        "META-INF", css::embed::ElementModes::READ), UNO_QUERY_THROW);

            Reference< css::io::XInputStream > xStream(
                xSubStore->openStreamElement("manifest.xml", css::embed::ElementModes::READ),
                UNO_QUERY_THROW);

            maSignatureManager.m_manifest = xReader->readManifestSequence(xStream);
        }
    }

    void DigitalSignaturesDialog::SetSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream )
    {
        maSignatureManager.mxSignatureStream = rxStream;
    }

    bool DigitalSignaturesDialog::canAddRemove()
    {
        //FIXME: this func needs some cleanup, such as real split between
        //'canAdd' and 'canRemove' case
        bool ret = true;

        uno::Reference<container::XNameAccess> xNameAccess(maSignatureManager.mxStore, uno::UNO_QUERY);
        if (xNameAccess.is() && xNameAccess->hasByName("[Content_Types].xml"))
            // It's always possible to append an OOXML signature.
            return ret;

        if (!maSignatureManager.mxStore.is())
            // It's always possible to append a PDF signature.
            return ret;

        OSL_ASSERT(maSignatureManager.mxStore.is());
        bool bDoc1_1 = DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
        SaveODFItem item;
        bool bSave1_1 = item.isLessODF1_2();

        // see specification
        //cvs: specs/www/appwide/security/Electronic_Signatures_and_Security.sxw
        //Paragraph 'Behavior with regard to ODF 1.2'
        //For both, macro and document
        if ( (!bSave1_1  && bDoc1_1) || (bSave1_1 && bDoc1_1) )
        {
            //#4
            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
                                                      VclMessageType::Warning, VclButtonsType::Ok,
                                                      XsResId(STR_XMLSECDLG_OLD_ODF_FORMAT)));
            xBox->run();
            ret = false;
        }

        //As of OOo 3.2 the document signature includes in macrosignatures.xml. That is
        //adding a macro signature will break an existing document signature.
        //The sfx2 will remove the documentsignature when the user adds a macro signature
        if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Macros
            && ret)
        {
            if (m_bHasDocumentSignature && !m_bWarningShowSignMacro)
            {
                //The warning says that the document signatures will be removed if the user
                //continues. He can then either press 'OK' or 'NO'
                //It the user presses 'Add' or 'Remove' several times then, then the warning
                //is shown every time until the user presses 'OK'. From then on, the warning
                //is not displayed anymore as long as the signatures dialog is alive.
                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
                                                          VclMessageType::Question, VclButtonsType::YesNo,
                                                          XsResId(STR_XMLSECDLG_QUERY_REMOVEDOCSIGNBEFORESIGN)));
                if (xBox->run() == RET_NO)
                    ret = false;
                else
                    m_bWarningShowSignMacro = true;

            }
        }
        return ret;
    }

    bool DigitalSignaturesDialog::canAdd()
    {
        return canAddRemove();
    }

    bool DigitalSignaturesDialog::canRemove()
    {
        bool bRet = true;

        if ( maSignatureManager.meSignatureMode == DocumentSignatureMode::Content )
        {
            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
                                                      VclMessageType::Question, VclButtonsType::YesNo,
                                                      XsResId(STR_XMLSECDLG_QUERY_REALLYREMOVE)));
            short nDlgRet = xBox->run();
            bRet = ( nDlgRet == RET_YES );
        }

        return (bRet && canAddRemove());
    }

    short DigitalSignaturesDialog::Execute()
    {
        // Verify Signatures and add certificates to ListBox...
        mbVerifySignatures = true;
        ImplGetSignatureInformations(/*bUseTempStream=*/false, /*bCacheLastSignature=*/true);
        ImplFillSignaturesBox();

        // FIXME: Disable the "Use XAdES compliant signatures" checkbox if it is irrelevant. If it is
        // enabled, set its initial state based on existing signatures, if any.

        // If it is OOXML, the checkbox is irrelevant.

        // How to find out here whether it is OOXML? I don't want to create a SignatureStreamHelper and
        // check its nStorageFormat as that seems overly complicated and seems to have weird indirect
        // consequences, as I noticed when I tried to use DocumentSignatureManager::IsXAdESRelevant()
        // (which now is in #if 0).

        if (maSignatureManager.maCurrentSignatureInformations.size() > 0)
        {
            // If the document has only SHA-1 signatures we probably want it to stay that way?
        }

        // Only verify once, content will not change.
        // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove
        mbVerifySignatures = false;

        return Dialog::Execute();
    }

    IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureHighlightHdl, SvTreeListBox*, void)
    {
        bool bSel = m_pSignaturesLB->FirstSelected();
        m_pViewBtn->Enable( bSel );
        if ( m_pAddBtn->IsEnabled() ) // not read only
            m_pRemoveBtn->Enable( bSel );
    }

    IMPL_LINK_NOARG(DigitalSignaturesDialog, OKButtonHdl, Button*, void)
    {
        if (mbSignaturesChanged)
            maSignatureManager.write(m_bAdESCompliant);

        EndDialog(RET_OK);
    }

    IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureSelectHdl, SvTreeListBox*, bool)
    {
        ImplShowSignaturesDetails();
        return false;
    }

    IMPL_LINK_NOARG(DigitalSignaturesDialog, AdESCompliantCheckBoxHdl, CheckBox&, void)
    {
        m_bAdESCompliant = m_pAdESCompliantCB->IsChecked();
    }

    IMPL_LINK_NOARG(DigitalSignaturesDialog, ViewButtonHdl, Button*, void)
    {
        ImplShowSignaturesDetails();
    }

    IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void)
    {
        if( ! canAdd())
            return;
        try
        {
            std::vector<uno::Reference<xml::crypto::XXMLSecurityContext>> xSecContexts;
            xSecContexts.push_back(maSignatureManager.getSecurityContext());
            // Gpg signing is only possible with ODF >= 1.2 documents
            if (DocumentSignatureHelper::CanSignWithGPG(maSignatureManager.mxStore, m_sODFVersion))
                xSecContexts.push_back(maSignatureManager.getGpgSecurityContext());

            ScopedVclPtrInstance< CertificateChooser > aChooser( this, mxCtx, xSecContexts, UserAction::Sign );
            if ( aChooser->Execute() == RET_OK )
            {
                sal_Int32 nSecurityId;
                if (!maSignatureManager.add(aChooser->GetSelectedCertificates()[0], aChooser->GetSelectedSecurityContext(),
                                            aChooser->GetDescription(), nSecurityId, m_bAdESCompliant))
                    return;
                mbSignaturesChanged = true;

                xml::crypto::SecurityOperationStatus nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;

                if (maSignatureManager.mxStore.is())
                    // In the PDF case the signature information is only available after parsing.
                    nStatus = maSignatureManager.maSignatureHelper.GetSignatureInformation( nSecurityId ).nStatus;

                if ( nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED )
                {
                    mbSignaturesChanged = true;

                    // Can't simply remember current information, need parsing for getting full information :(
                    // We need to verify the signatures again, otherwise the status in the signature information
                    // will not contain
                    // SecurityOperationStatus_OPERATION_SUCCEEDED
                    mbVerifySignatures = true;
                    ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
                    ImplFillSignaturesBox();
                }
            }
        }
        catch ( uno::Exception& )
        {
            OSL_FAIL( "Exception while adding a signature!" );
            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
                                                      VclMessageType::Error, VclButtonsType::Ok,
                                                      XsResId(STR_XMLSECDLG_SIGNING_FAILED)));
            xBox->run();
            // Don't keep invalid entries...
            ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
            ImplFillSignaturesBox();
        }
    }

    IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, Button*, void)
    {
        if (!canRemove())
            return;
        if( m_pSignaturesLB->FirstSelected() )
        {
            try
            {
                sal_uInt16 nSelected = static_cast<sal_uInt16>(reinterpret_cast<sal_uIntPtr>( m_pSignaturesLB->FirstSelected()->GetUserData() ));
                maSignatureManager.remove(nSelected);

                mbSignaturesChanged = true;

                ImplFillSignaturesBox();
            }
            catch ( uno::Exception& )
            {
                OSL_FAIL( "Exception while removing a signature!" );
                // Don't keep invalid entries...
                ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/true);
                ImplFillSignaturesBox();
            }
        }
    }

    IMPL_STATIC_LINK(DigitalSignaturesDialog, CertMgrButtonHdl, Button*, pButton, void)
    {
    #ifdef _WIN32
        // FIXME: call GpgME::dirInfo("bindir") somewhere in
        // SecurityEnvironmentGpg or whatnot
        // FIXME: perhaps poke GpgME for uiserver, and hope it returns something useful?
        const OUString aGUIServers[] = { OUString("kleopatra.exe"), OUString("launch-gpa.exe"), OUString("gpa.exe"),
                                         OUString("bin\\kleopatra.exe"), OUString("bin\\launch-gpa.exe"), OUString("bin\\gpa.exe") };
        const char* const cPath = "C:\\Program Files (x86)\\GNU\\GnuPG";
    #else
        const OUString aGUIServers[] = { OUString("kleopatra"), OUString("seahorse"),  OUString("gpa"), OUString("kgpg") };
        const char* cPath = getenv("PATH");
    #endif

        if (cPath)
        {
           OUString aPath(cPath, strlen(cPath), osl_getThreadTextEncoding());
           OUString sFoundGUIServer, sExecutable;

           for ( auto const &rServer : aGUIServers )
           {
               osl::FileBase::RC searchError = osl::File::searchFileURL(rServer, aPath, sFoundGUIServer );
               if (searchError == osl::FileBase::E_None)
               {
                   osl::File::getSystemPathFromFileURL( sFoundGUIServer, sExecutable );
                   break;
               }

           }

           if ( !sExecutable.isEmpty() )
           {
               uno::Reference< uno::XComponentContext > xContext =
                   ::comphelper::getProcessComponentContext();
               uno::Reference< css::system::XSystemShellExecute > xSystemShell(
                        css::system::SystemShellExecute::create(xContext) );

               xSystemShell->execute( sExecutable, OUString(),
                   css::system::SystemShellExecuteFlags::DEFAULTS );
           }
           else
           {
               std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pButton->GetFrameWeld(),
                                                             VclMessageType::Info, VclButtonsType::Ok,
                                                             XsResId(STR_XMLSECDLG_NO_CERT_MANAGER)));
               xInfoBox->run();
           }
        }
    }

    IMPL_LINK_NOARG(DigitalSignaturesDialog, StartVerifySignatureHdl, LinkParamNone*, bool)
    {
        return mbVerifySignatures;
    }

    void DigitalSignaturesDialog::ImplFillSignaturesBox()
    {
        m_pSignaturesLB->Clear();

        size_t nInfos = maSignatureManager.maCurrentSignatureInformations.size();
        size_t nValidSigs = 0, nValidCerts = 0;
        bool bAllNewSignatures = true;

        if( nInfos )
        {
            for( size_t n = 0; n < nInfos; ++n )
            {
                DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm(
                    m_sODFVersion, maSignatureManager.maCurrentSignatureInformations[n]);
                std::vector< OUString > aElementsToBeVerified;
                if (maSignatureManager.mxStore.is())
                    aElementsToBeVerified = DocumentSignatureHelper::CreateElementList(maSignatureManager.mxStore, maSignatureManager.meSignatureMode, mode);

                const SignatureInformation& rInfo = maSignatureManager.maCurrentSignatureInformations[n];
                uno::Reference< css::security::XCertificate > xCert = getCertificate(rInfo);

                OUString aSubject;
                OUString aIssuer;
                OUString aDateTimeStr;
                OUString aDescription;
                OUString aType;

                bool bSigValid = false;
                bool bCertValid = false;
                if( xCert.is() )
                {
                    //check the validity of the cert
                    try {
                        sal_Int32 certResult = getSecurityEnvironmentForCertificate(xCert)->verifyCertificate(xCert,
                                                                                                              Sequence<uno::Reference<security::XCertificate> >());

                        bCertValid = certResult == css::security::CertificateValidity::VALID;
                        if ( bCertValid )
                            nValidCerts++;

                    } catch (css::uno::SecurityException& ) {
                        OSL_FAIL("Verification of certificate failed");
                        bCertValid = false;
                    }

                    aSubject = XmlSec::GetContentPart( xCert->getSubjectName() );
                    aIssuer = XmlSec::GetContentPart( xCert->getIssuerName() );
                }
                else if (!rInfo.ouGpgCertificate.isEmpty())
                {
                    // In case we don't have the gpg key locally, get some data from the document
                    aIssuer = rInfo.ouGpgOwner;
                }

                aDateTimeStr = XmlSec::GetDateTimeString( rInfo.stDateTime );
                aDescription = rInfo.ouDescription;

                // Decide type string.
                if (maSignatureManager.mxStore.is())
                {
                    // OpenPGP
                    if (!rInfo.ouGpgCertificate.isEmpty())
                        aType = "OpenPGP";
                    // XML based: XAdES or not.
                    else if (!rInfo.ouCertDigest.isEmpty())
                        aType = "XAdES";
                    else
                        aType = "XML-DSig";
                }
                else
                {
                    // Assume PDF: PAdES or not.
                    if (rInfo.bHasSigningCertificate)
                        aType = "PAdES";
                    else
                        aType = "PDF";
                }

                bSigValid = ( rInfo.nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED );

                if ( bSigValid )
                {
                     bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned(
                          aElementsToBeVerified, rInfo, mode);

                    if( bSigValid )
                        nValidSigs++;
                }

                Image aImage;
                if (!bSigValid)
                {
                    aImage = m_pSigsInvalidImg->GetImage();
                }
                else if (bSigValid && !bCertValid)
                {
                    aImage = m_pSigsNotvalidatedImg->GetImage();
                }
                //Check if the signature is a "old" document signature, that is, which was created
                //by an version of OOo previous to 3.2
                // If there is no storage, then it's pointless to check storage
                // stream references.
                else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Content
                    && bSigValid && bCertValid && (maSignatureManager.mxStore.is() && !DocumentSignatureHelper::isOOo3_2_Signature(
                    maSignatureManager.maCurrentSignatureInformations[n])))
                {
                    aImage = m_pSigsNotvalidatedImg->GetImage();
                    bAllNewSignatures = false;
                }
                else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Content
                    && bSigValid && bCertValid && DocumentSignatureHelper::isOOo3_2_Signature(
                    maSignatureManager.maCurrentSignatureInformations[n]))
                {
                    aImage = m_pSigsValidImg->GetImage();
                }
                else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Macros
                    && bSigValid && bCertValid)
                {
                    aImage = m_pSigsValidImg->GetImage();
                }

                SvTreeListEntry* pEntry = m_pSignaturesLB->InsertEntry( OUString(), aImage, aImage );
                m_pSignaturesLB->SetEntryText( aSubject, pEntry, 1 );
                m_pSignaturesLB->SetEntryText( aIssuer, pEntry, 2 );
                m_pSignaturesLB->SetEntryText( aDateTimeStr, pEntry, 3 );
                m_pSignaturesLB->SetEntryText(aDescription, pEntry, 4);
                m_pSignaturesLB->SetEntryText(aType, pEntry, 5);
                pEntry->SetUserData( reinterpret_cast<void*>(n) );     // misuse user data as index
            }
        }

        bool bAllSigsValid = (nValidSigs == nInfos);
        bool bAllCertsValid = (nValidCerts == nInfos);
        bool bShowValidState = nInfos && (bAllSigsValid && bAllCertsValid && bAllNewSignatures);

        m_pSigsValidImg->Show( bShowValidState);
        m_pSigsValidFI->Show( bShowValidState );

        bool bShowInvalidState = nInfos && !bAllSigsValid;

        m_pSigsInvalidImg->Show( bShowInvalidState );
        m_pSigsInvalidFI->Show( bShowInvalidState );

        bool bShowNotValidatedState = nInfos && bAllSigsValid && !bAllCertsValid;

        m_pSigsNotvalidatedImg->Show(bShowNotValidatedState);
        m_pSigsNotvalidatedFI->Show(bShowNotValidatedState);

        //bAllNewSignatures is always true if we are not in document mode
        bool bShowOldSignature = nInfos && bAllSigsValid && bAllCertsValid && !bAllNewSignatures;
        m_pSigsOldSignatureImg->Show(bShowOldSignature);
        m_pSigsOldSignatureFI->Show(bShowOldSignature);

        SignatureHighlightHdl( nullptr );
    }

    uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(const SignatureInformation& rInfo)
    {
        uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = maSignatureManager.getSecurityEnvironment();
        uno::Reference<xml::crypto::XSecurityEnvironment> xGpgSecEnv = maSignatureManager.getGpgSecurityEnvironment();
        uno::Reference<security::XCertificate> xCert;

        //First we try to get the certificate which is embedded in the XML Signature
        if (xSecEnv.is() && !rInfo.ouX509Certificate.isEmpty())
            xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate);
        else {
            //There must be an embedded certificate because we use it to get the
            //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName
            //because it could be modified by an attacker. The issuer is displayed
            //in the digital signature dialog.
            //Comparing the X509IssuerName with the one from the X509Certificate in order
            //to find out if the X509IssuerName was modified does not work. See #i62684
            SAL_WARN( "xmlsecurity.dialogs", "Could not find embedded certificate!");
        }

        //In case there is no embedded certificate we try to get it from a local store
        if (!xCert.is() && xSecEnv.is())
            xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) );
        if (!xCert.is() && xGpgSecEnv.is())
            xCert = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, xmlsecurity::numericStringToBigInteger("") );

        SAL_WARN_IF( !xCert.is(), "xmlsecurity.dialogs", "Certificate not found and can't be created!" );

        return xCert;
    }

    uno::Reference<xml::crypto::XSecurityEnvironment> DigitalSignaturesDialog::getSecurityEnvironmentForCertificate(const uno::Reference<security::XCertificate>& xCert)
    {
        if (xCert->getCertificateKind() == CertificateKind_OPENPGP)
            return maSignatureManager.getGpgSecurityEnvironment();
        else if (xCert->getCertificateKind() == CertificateKind_X509)
            return maSignatureManager.getSecurityEnvironment();

        throw RuntimeException("Unknown certificate kind");
    }

    //If bUseTempStream is true then the temporary signature stream is used.
    //Otherwise the real signature stream is used.
    void DigitalSignaturesDialog::ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature)
    {
        maSignatureManager.read(bUseTempStream, bCacheLastSignature);
        mbVerifySignatures = false;
    }

    void DigitalSignaturesDialog::ImplShowSignaturesDetails()
    {
        if( m_pSignaturesLB->FirstSelected() )
        {
            sal_uInt16 nSelected = static_cast<sal_uInt16>(reinterpret_cast<sal_uIntPtr>( m_pSignaturesLB->FirstSelected()->GetUserData() ));
            const SignatureInformation& rInfo = maSignatureManager.maCurrentSignatureInformations[ nSelected ];
            uno::Reference<security::XCertificate> xCert = getCertificate(rInfo);

            if ( xCert.is() )
            {
                uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = getSecurityEnvironmentForCertificate(xCert);
                ScopedVclPtrInstance<CertificateViewer> aViewer(this, xSecEnv, xCert, false);
                aViewer->Execute();
            }
            else
            {
                std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
                                                              VclMessageType::Info, VclButtonsType::Ok,
                                                              XsResId(STR_XMLSECDLG_NO_CERT_FOUND)));
                xInfoBox->run();
            }
        }
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V547 Expression 'cPath' is always true.

↑ V560 A part of conditional expression is always true: bSigValid.

↑ V560 A part of conditional expression is always true: bSigValid.

↑ V560 A part of conditional expression is always true: bCertValid.

↑ V560 A part of conditional expression is always true: bSigValid.

↑ V560 A part of conditional expression is always true: bCertValid.

↑ V560 A part of conditional expression is always true: bSigValid.

↑ V560 A part of conditional expression is always true: bCertValid.