/* -*- 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 <config_gpgme.h> #if HAVE_FEATURE_GPGME #include <com/sun/star/xml/crypto/GPGSEInitializer.hpp> #include <com/sun/star/xml/crypto/SEInitializer.hpp> #include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp> #endif #include <com/sun/star/security/DocumentDigitalSignatures.hpp> #include <com/sun/star/security/XCertificate.hpp>
sal_uInt16 getSlotIDFromMode( sal_Int16 nStoreMode )
{ // This is a temporary hardcoded solution must be removed when // dialogs do not need parameters in SidSet representation any more
if ( !aFilterProps.hasElements() )
{ // the default filter was not found, use just the first acceptable one
aFilterProps = GetDocServiceAnyFilter( nMust, nDont );
}
}
if ( nResult != STATUS_NO_ACTION && GetStorable()->hasLocation() )
{ // the saving is acceptable // in case the configuration entry is not set or set to false // or in case of version creation if ( officecfg::Office::Common::Save::Document::AlwaysSaveAs::get()
&& GetMediaDescr().find( u"VersionComment"_ustr ) == GetMediaDescr().end() )
{ // notify the user that SaveAs is going to be done
std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(m_xModel),
VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_NEW_FILENAME_SAVE))); if (xMessageBox->run() == RET_OK)
nResult = STATUS_SAVEAS; else
nResult = STATUS_NO_ACTION;
}
}
return nResult;
}
sal_Int8 ModelData_Impl::CheckStateForSave()
{ // if the document is readonly or a new one a SaveAs operation must be used if ( !GetStorable()->hasLocation() || GetStorable()->isReadonly() ) return STATUS_SAVEAS;
// check acceptable entries for media descriptor
::comphelper::SequenceAsHashMap aAcceptedArgs;
// remove unacceptable entry if there is any
DBG_ASSERT( GetMediaDescr().size() == aAcceptedArgs.size(), "Unacceptable parameters are provided in Save request!\n" ); if ( GetMediaDescr().size() != aAcceptedArgs.size() )
GetMediaDescr() = std::move(aAcceptedArgs);
// check that the old filter is acceptable return CheckFilter( GetDocProps().getUnpackedValueOrDefault(aFilterNameString, OUString()) );
}
// only a temporary solution until default filter retrieving feature is implemented // then GetDocServiceDefaultFilter() must be used
::comphelper::SequenceAsHashMap aDefFiltPropsHM = GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT, SfxFilterFlags::NONE );
SfxFilterFlags nDefFiltFlags = static_cast<SfxFilterFlags>(aDefFiltPropsHM.getUnpackedValueOrDefault(u"Flags"_ustr, sal_Int32(0) ));
bool bAsk = false;
// if the old filter is not acceptable // and there is no default filter or it is not acceptable for requested parameters then proceed with saveAs if ( ( aFiltPropsHM.empty() || !( nFiltFlags & SfxFilterFlags::EXPORT ) )
&& ( aDefFiltPropsHM.empty() || !( nDefFiltFlags & SfxFilterFlags::EXPORT ) || nDefFiltFlags & SfxFilterFlags::INTERNAL ) ) return STATUS_SAVEAS;
// so at this point there is either an acceptable old filter or default one if ( aFiltPropsHM.empty() || !( nFiltFlags & SfxFilterFlags::EXPORT ) )
{ // so the default filter must be acceptable return STATUS_SAVEAS_STANDARDNAME;
} elseif ( ( !( nFiltFlags & SfxFilterFlags::OWN ) || ( nFiltFlags & SfxFilterFlags::ALIEN ) )
&& !aDefFiltPropsHM.empty()
&& ( nDefFiltFlags & SfxFilterFlags::EXPORT ) && !( nDefFiltFlags & SfxFilterFlags::INTERNAL ))
{
bAsk = true;
}
// check if EncryptionData supports this output format
{
OUString aSupportedFilters; const ::comphelper::SequenceAsHashMap& rDocumentProperties = GetDocProps(); const css::uno::Sequence<css::beans::NamedValue> aEncryptionData = rDocumentProperties.getUnpackedValueOrDefault(u"EncryptionData"_ustr, css::uno::Sequence<css::beans::NamedValue>()); if (aEncryptionData != css::uno::Sequence<css::beans::NamedValue>())
{ for (const css::beans::NamedValue& aNamedValue : aEncryptionData)
{ if (aNamedValue.Name == "SupportedFilters")
{
aNamedValue.Value >>= aSupportedFilters;
}
}
}
// if 'SupportedFilters' is empty assume that all filters are supported. if (!aSupportedFilters.isEmpty())
{ const OUString aSelectedFilter = aFiltPropsHM.getUnpackedValueOrDefault(u"UIName"_ustr, OUString());
// the file name must be specified if overwrite option is set if ( aOverwriteIter != GetMediaDescr().end() ) throw task::ErrorCodeIOException(
u"ModelData_Impl::OutputFileDialog: ERRCODE_IO_INVALIDPARAMETER"_ustr,
uno::Reference< uno::XInterface >(),
sal_uInt32(ERRCODE_IO_INVALIDPARAMETER));
// no target file name is specified // we need to show the file dialog
// check if we have a filter which allows for filter options, so we need a corresponding checkbox in the dialog bool bAllowOptions = false;
// in case of Export, filter options dialog is used if available if( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) )
bAllowOptions = CheckFilterOptionsDialogExistence();
// get the filename by dialog ... // create the file dialog
sal_Int16 aDialogMode = bAllowOptions
? css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS
: css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD;
FileDialogFlags aDialogFlags = FileDialogFlags::NONE;
// Fall back to the document base URL - but only if the document is not based on a template. // Otherwise the template's directory would be used, which is not what we want. if (SfxViewShell* pViewShell = SfxViewShell::Current())
{
SfxObjectShell* pDocShell = pViewShell->GetObjectShell(); if (pDocShell && !pDocShell->IsBasedOnTemplate())
{ if (sPreselectedDir.isEmpty())
sPreselectedDir = GetDocProps().getUnpackedValueOrDefault("DocumentBaseURL", OUString()); if (sPreselectedDir.isEmpty() && GetStorable()->hasLocation())
sPreselectedDir = GetStorable()->getLocation();
}
}
INetURLObject aObj(sPreselectedDir);
aObj.removeSegment(); // remove file name from URL
sPreselectedDir = aObj.GetMainURL(INetURLObject::DecodeMechanism::NONE); if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) )
{ if ( ( nStoreMode & PDFEXPORT_REQUESTED ) && !aPreselectedFilterPropsHM.empty() )
{ // this is a PDF export // the filter options has been shown already const OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"UIName"_ustr, OUString() );
pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aFilterUIName, u"pdf", sPreselectedDir, rDenyList, pFrameWin ));
pFileDlg->SetCurrentFilter( aFilterUIName );
} elseif ((nStoreMode & EPUBEXPORT_REQUESTED) && !aPreselectedFilterPropsHM.empty())
{ // This is an EPUB export, the filter options has been shown already. const OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"UIName"_ustr, OUString() );
pFileDlg.reset(new sfx2::FileDialogHelper(aDialogMode, aDialogFlags, aFilterUIName, u"epub", sPreselectedDir, rDenyList, pFrameWin));
pFileDlg->SetCurrentFilter(aFilterUIName);
} else
{ // This is the normal dialog
pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aDocServiceName, nDialog, nMust, nDont, sPreselectedDir, rDenyList, pFrameWin ));
}
if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) )
{ // it is export, set the preselected filter
pFileDlg->SetCurrentFilter( aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"UIName"_ustr, OUString() ) );
aAdjustToType = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"Type"_ustr, OUString() );
} // it is no export, bSetStandardName == true means that user agreed to store document in the default (default default ;-)) format elseif ( bSetStandardName || GetStorable()->hasLocation() )
{
uno::Sequence< beans::PropertyValue > aOldFilterProps; const OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() );
if ( !aOldFilterName.isEmpty() )
m_pOwner->GetFilterConfiguration()->getByName( aOldFilterName ) >>= aOldFilterProps;
// This is a temporary hardcoded solution must be removed when // dialogs do not need parameters in SidSet representation any more
sal_uInt16 nSlotID = getSlotIDFromMode( nStoreMode ); if ( !nSlotID ) throw lang::IllegalArgumentException(); // TODO:
// generate SidSet from MediaDescriptor and provide it into FileDialog // than merge changed SidSet back
std::optional<SfxAllItemSet> pDialogParams( SfxGetpApp()->GetPool() );
TransformParameters( nSlotID,
GetMediaDescr().getAsConstPropertyValueList(),
*pDialogParams );
if ( bPreselectPassword && !pDialogParams->HasItem( SID_ENCRYPTIONDATA ) )
{ // the file dialog preselects the password checkbox if the provided mediadescriptor has encryption data entry // after dialog execution the password interaction flag will be either removed or not
pDialogParams->Put( SfxBoolItem( SID_PASSWORDINTERACTION, true ) );
}
// aFilterName is a pure output parameter, pDialogParams is an in/out parameter
OUString aFilterName; // in LOK case we don't show File Picker so it will fail, but execute to do other preparations if (pFileDlg->Execute(pDialogParams, aFilterName, nScriptingSignatureState) != ERRCODE_NONE
&& !comphelper::LibreOfficeKit::isActive() )
{ throw task::ErrorCodeIOException(
u"ModelData_Impl::OutputFileDialog: ERRCODE_IO_ABORT"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
} elseif (comphelper::LibreOfficeKit::isActive())
{
aFilterName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( u"Name"_ustr, OUString() );
}
// the following two arguments can not be converted in MediaDescriptor, // so they should be removed from the ItemSet after retrieving const SfxBoolItem* pRecommendReadOnly = SfxItemSet::GetItem<SfxBoolItem>(&*pDialogParams, SID_RECOMMENDREADONLY, false);
m_bRecommendReadOnly = ( pRecommendReadOnly && pRecommendReadOnly->GetValue() );
pDialogParams->ClearItem( SID_RECOMMENDREADONLY );
// get the path from the dialog
INetURLObject aURL( pFileDlg->GetPath() );
if (comphelper::LibreOfficeKit::isActive())
{ #ifdef IOS // The iOS app (and maybe the Android app) have fails to set the URL to // save to so we need to set it to a temporary file. // Note: the iOS app is responsible for deleting the temporary file. if (nStoreMode & EXPORT_REQUESTED && aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE).isEmpty())
{ // Mirror the "export/docbasename.pdf" path format to match the // format used in the "downloadas" message handler in the iOS app's // -[DocumentViewController userContentController:didReceiveScriptMessage] // selector. // Important note: temporary files created here must be in their // own subdirectory since the iOS app's UIDocumentPickerDelegate // will try to delete both the temporary file and its parent // directory.
OUString aFullName = u"export/" + aRecommendedName;
OUString aBaseName;
OUString aExtension;
sal_Int32 nPos = aFullName.lastIndexOf( '.' ); if ( nPos >= 0 )
{
aBaseName = aFullName.copy(0, nPos);
aExtension = aFullName.copy(nPos, aFullName.getLength() - nPos);
}
aURL = INetURLObject(::utl::CreateTempURL( aBaseName, false, aExtension, nullptr, true));
// Remove any stale files left from a previous export
OUString fileURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); if (!fileURL.isEmpty())
osl::File::remove(fileURL);
} else
{ #endif // keep name with extension
aSuggestedName = aRecommendedName;
OUString aExtension; if (size_t nPos = aSuggestedName.lastIndexOf('.') + 1)
aExtension = aSuggestedName.copy(nPos, aSuggestedName.getLength() - nPos);
aURL.SetExtension(aExtension); #ifdef IOS
} #endif
} else
{ // the path should be provided outside since it might be used for further calls to the dialog
aSuggestedName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
}
aSuggestedDir = pFileDlg->GetDisplayDirectory();
// old filter options should be cleared in case different filter is used
if ( aFilterName == aFilterFromMediaDescr )
{ // preserve current settings if any // if there no current settings and the name is the same // as old filter name use old filter settings
if ( ( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) ) && bUseFilterOptions )
{ try
{ // for exporters: always show dialog if format uses options // for save: show dialog if format uses options and no options given or if forced by user
uno::Any aVal =
xExtFileDlg->getValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS, 0 );
// merge in results of the dialog execution
GetMediaDescr()[u"URL"_ustr] <<= aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
GetMediaDescr()[sFilterNameString] <<= aFilterName;
// for Export - keep a runtime var for each document where the document was last exported to if (GetStorable()->hasLocation() && (nStoreMode & EXPORT_REQUESTED))
{
uno::Sequence< beans::PropertyValue > descriptor{
beans::PropertyValue(u"ExportDirectory"_ustr,
-1, uno::Any(aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE )), beans::PropertyState_DIRECT_VALUE),
};
GetModel()->setArgs(descriptor);
}
uno::Reference < util::XURLTransformer > xTransformer( util::URLTransformer::create( comphelper::getProcessComponentContext() ) ); if ( xTransformer->parseStrict( aURL ) )
{
uno::Reference< frame::XDispatch > xDispatch = xFrameDispatch->queryDispatch(
aURL,
u"_self"_ustr,
0 ); if ( xDispatch.is() )
{ // tdf#119206 use (abuse?) a SynchronMode of true, // which will become SfxRequest::IsSynchronCall of true // in SfxObjectShell::ExecFile_Impl to request that we // do not want the properties dialog to be run async
uno::Sequence< beans::PropertyValue > aProperties{
comphelper::makePropertyValue(u"SynchronMode"_ustr, true)
};
xDispatch->dispatch(aURL, aProperties);
bDialogUsed = true;
}
}
}
}
} catch ( const uno::Exception& )
{
}
OUString ModelData_Impl::GetRecommendedName( const OUString& aSuggestedName, const OUString& aTypeName )
{ // the last used name might be provided by aSuggestedName from the old selection, or from the MediaDescriptor if ( !aSuggestedName.isEmpty() ) return aSuggestedName;
m_bSetStandardName = false; // can be set only for SaveAs
m_bPreselectPassword = bPreselectPassword;
m_nScriptingSignatureState = nScriptingSignatureState;
// parse the slot name
m_bRemote = false;
m_nStoreMode = getStoreModeFromSlotName( aSlotName );
// if saving is not acceptable the warning must be shown even in case of SaveAs operation if ( ( m_nStoreMode & SAVEAS_REQUESTED ) && aModelData.CheckSaveAcceptable( STATUS_SAVEAS ) == STATUS_NO_ACTION ) throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
} elseif ( m_nStoreMode & SAVE_REQUESTED )
{ // if saving is not acceptable by the configuration the warning must be shown
nStatusSave = aModelData.CheckSaveAcceptable( STATUS_SAVE );
if ( nStatusSave == STATUS_NO_ACTION ) throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); elseif ( nStatusSave == STATUS_SAVE )
{ // check whether it is possible to use save operation
nStatusSave = aModelData.CheckStateForSave();
}
if ( nStatusSave == STATUS_NO_ACTION )
{ throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
} elseif ( nStatusSave != STATUS_SAVE )
{ // this should be a usual SaveAs operation
m_nStoreMode = SAVEAS_REQUESTED; if ( nStatusSave == STATUS_SAVEAS_STANDARDNAME )
m_bSetStandardName = true;
}
}
// if it is no export, warn user that the signature will be removed if ( !pDocShell->IsRememberingSignature()
&& (SignatureState::OK == nDocumentSignatureState
|| SignatureState::INVALID == nDocumentSignatureState
|| SignatureState::NOTVALIDATED == nDocumentSignatureState
|| SignatureState::PARTIAL_OK == nDocumentSignatureState) )
{
std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(xModel),
VclMessageType::Question, VclButtonsType::YesNo, SfxResId(RID_SVXSTR_XMLSEC_QUERY_LOSINGSIGNATURE))); if (xMessageBox->run() != RET_YES)
{ // the user has decided not to store the document throw task::ErrorCodeIOException(
u"SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT (Preserve Signature)"_ustr,
uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
}
}
}
if ( m_nStoreMode & SAVE_REQUESTED && nStatusSave == STATUS_SAVE )
{ // Document properties can contain streams that should be freed before storing
aModelData.FreeDocumentProps();
if ( aModelData.GetStorable2().is() )
{ try
{
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.