Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / appl / appopen.cxx
blobe59e58b0803395fab1a9dedf4a13dc0320ed5749
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/uno/Reference.h>
21 #include <com/sun/star/beans/PropertyValue.hpp>
22 #include <com/sun/star/beans/NamedValue.hpp>
23 #include <com/sun/star/frame/FrameSearchFlag.hpp>
24 #include <com/sun/star/frame/XDispatchProvider.hpp>
25 #include <com/sun/star/frame/XFrame.hpp>
26 #include <com/sun/star/frame/Desktop.hpp>
27 #include <com/sun/star/util/URL.hpp>
28 #include <com/sun/star/util/URLTransformer.hpp>
29 #include <com/sun/star/util/XURLTransformer.hpp>
30 #include <com/sun/star/system/SystemShellExecuteException.hpp>
31 #include <com/sun/star/document/XTypeDetection.hpp>
32 #include <com/sun/star/document/MacroExecMode.hpp>
33 #include <com/sun/star/document/UpdateDocMode.hpp>
34 #include <com/sun/star/task/ErrorCodeRequest.hpp>
35 #include <com/sun/star/task/InteractionHandler.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/embed/ElementModes.hpp>
38 #include <com/sun/star/embed/XStorage.hpp>
39 #include <com/sun/star/container/XNameAccess.hpp>
40 #include <com/sun/star/packages/WrongPasswordException.hpp>
41 #include <com/sun/star/uno/Sequence.h>
42 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <rtl/ustring.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <comphelper/sequence.hxx>
48 #include <comphelper/storagehelper.hxx>
49 #include <comphelper/synchronousdispatch.hxx>
51 #include <svl/intitem.hxx>
52 #include <svl/stritem.hxx>
53 #include <svl/eitem.hxx>
54 #include <sfx2/doctempl.hxx>
55 #include <svtools/sfxecode.hxx>
56 #include <preventduplicateinteraction.hxx>
57 #include <svtools/ehdl.hxx>
58 #include <unotools/pathoptions.hxx>
59 #include <unotools/securityoptions.hxx>
60 #include <unotools/moduleoptions.hxx>
61 #include <unotools/extendedsecurityoptions.hxx>
62 #include <comphelper/docpasswordhelper.hxx>
63 #include <vcl/svapp.hxx>
64 #include <vcl/weld.hxx>
66 #include <sfx2/app.hxx>
67 #include <sfx2/bindings.hxx>
68 #include <sfx2/dispatch.hxx>
69 #include <sfx2/docfile.hxx>
70 #include <sfx2/docfilt.hxx>
71 #include <sfx2/fcontnr.hxx>
72 #include <sfx2/objitem.hxx>
73 #include <sfx2/objsh.hxx>
74 #include <svl/slstitm.hxx>
75 #include <appopen.hxx>
76 #include <sfx2/request.hxx>
77 #include <sfx2/sfxresid.hxx>
78 #include <sfx2/viewsh.hxx>
79 #include <sfx2/strings.hrc>
80 #include <sfx2/viewfrm.hxx>
81 #include <sfx2/sfxuno.hxx>
82 #include <sfx2/objface.hxx>
83 #include <sfx2/filedlghelper.hxx>
84 #include <sfx2/templatedlg.hxx>
85 #include <sfx2/sfxsids.hrc>
86 #include <openuriexternally.hxx>
88 #include <officecfg/Office/ProtocolHandler.hxx>
89 #include <officecfg/Office/Security.hxx>
91 using namespace ::com::sun::star;
92 using namespace ::com::sun::star::beans;
93 using namespace ::com::sun::star::frame;
94 using namespace ::com::sun::star::lang;
95 using namespace ::com::sun::star::uno;
96 using namespace ::com::sun::star::util;
97 using namespace ::com::sun::star::task;
98 using namespace ::com::sun::star::container;
99 using namespace ::cppu;
100 using namespace ::sfx2;
102 void SetTemplate_Impl( const OUString &rFileName,
103 const OUString &rLongName,
104 SfxObjectShell *pDoc)
106 // write TemplateName to DocumentProperties of document
107 // TemplateDate stays as default (=current date)
108 pDoc->ResetFromTemplate( rLongName, rFileName );
111 namespace {
113 class SfxDocPasswordVerifier : public ::comphelper::IDocPasswordVerifier
115 public:
116 explicit SfxDocPasswordVerifier( const Reference< embed::XStorage >& rxStorage ) :
117 mxStorage( rxStorage ) {}
119 virtual ::comphelper::DocPasswordVerifierResult
120 verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) override;
121 virtual ::comphelper::DocPasswordVerifierResult
122 verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) override;
125 private:
126 Reference< embed::XStorage > mxStorage;
131 ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
133 o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( rPassword );
134 return verifyEncryptionData( o_rEncryptionData );
138 ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
140 ::comphelper::DocPasswordVerifierResult eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
143 // check the encryption data
144 // if the data correct is the stream will be opened successfully
145 // and immediately closed
146 ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( mxStorage, rEncryptionData );
148 mxStorage->openStreamElement(
149 "content.xml",
150 embed::ElementModes::READ | embed::ElementModes::NOCREATE );
152 // no exception -> success
153 eResult = ::comphelper::DocPasswordVerifierResult::OK;
155 catch( const packages::WrongPasswordException& )
157 eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
159 catch( const uno::Exception& )
161 // unknown error, report it as wrong password
162 // TODO/LATER: we need an additional way to report unknown problems in this case
163 eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
165 return eResult;
169 ErrCode CheckPasswd_Impl
171 SfxObjectShell* pDoc,
172 SfxMedium* pFile // the Medium and its Password should be obtained
175 /* [Description]
177 Ask for the password for a medium, only works if it concerns storage.
178 If the password flag is set in the Document Info, then the password is
179 requested through a user dialogue and the set at the Set of the medium.
180 If the set does not exist the it is created.
183 ErrCode nRet = ERRCODE_NONE;
185 if( !pFile->GetFilter() || pFile->IsStorage() )
187 uno::Reference< embed::XStorage > xStorage = pFile->GetStorage();
188 if( xStorage.is() )
190 uno::Reference< beans::XPropertySet > xStorageProps( xStorage, uno::UNO_QUERY );
191 if ( xStorageProps.is() )
193 bool bIsEncrypted = false;
194 uno::Sequence< uno::Sequence< beans::NamedValue > > aGpgProperties;
195 try {
196 xStorageProps->getPropertyValue("HasEncryptedEntries")
197 >>= bIsEncrypted;
198 xStorageProps->getPropertyValue("EncryptionGpGProperties")
199 >>= aGpgProperties;
200 } catch( uno::Exception& )
202 // TODO/LATER:
203 // the storage either has no encrypted elements or it's just
204 // does not allow to detect it, probably it should be implemented later
207 if ( bIsEncrypted )
209 vcl::Window* pWin = pDoc ? pDoc->GetDialogParent( pFile ) : nullptr;
210 if ( pWin )
211 pWin->Show();
213 nRet = ERRCODE_SFX_CANTGETPASSWD;
215 SfxItemSet *pSet = pFile->GetItemSet();
216 if( pSet )
218 Reference< css::task::XInteractionHandler > xInteractionHandler = pFile->GetInteractionHandler();
219 if( xInteractionHandler.is() )
221 // use the comphelper password helper to request a password
222 OUString aPassword;
223 const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(pSet, SID_PASSWORD, false);
224 if ( pPasswordItem )
225 aPassword = pPasswordItem->GetValue();
227 uno::Sequence< beans::NamedValue > aEncryptionData;
228 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pSet, SID_ENCRYPTIONDATA, false);
229 if ( pEncryptionDataItem )
230 pEncryptionDataItem->GetValue() >>= aEncryptionData;
232 // try if one of the public key entries is
233 // decryptable, then extract session key
234 // from it
235 if ( !aEncryptionData.hasElements() && aGpgProperties.hasElements() )
236 aEncryptionData = ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties);
238 // tdf#93389: if recovering a document, encryption data should contain
239 // entries for the real filter, not only for recovery ODF, to keep it
240 // encrypted. Pass this in encryption data.
241 // TODO: pass here the real filter (from AutoRecovery::implts_openDocs)
242 // to marshal this to requestAndVerifyDocPassword
243 if (pSet->GetItemState(SID_DOC_SALVAGE, false) == SfxItemState::SET)
245 aEncryptionData = comphelper::concatSequences(
246 aEncryptionData, std::initializer_list<beans::NamedValue>{
247 { "ForSalvage", css::uno::Any(true) } });
250 SfxDocPasswordVerifier aVerifier( xStorage );
251 aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
252 aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard );
254 pSet->ClearItem( SID_PASSWORD );
255 pSet->ClearItem( SID_ENCRYPTIONDATA );
257 if ( aEncryptionData.hasElements() )
259 pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
263 // update the version list of the medium using the new password
264 pFile->GetVersionList();
266 catch( uno::Exception& )
268 // TODO/LATER: set the error code
271 nRet = ERRCODE_NONE;
273 else
274 nRet = ERRCODE_IO_ABORT;
279 else
281 OSL_FAIL( "A storage must implement XPropertySet interface!" );
282 nRet = ERRCODE_SFX_CANTGETPASSWD;
287 return nRet;
291 ErrCode SfxApplication::LoadTemplate( SfxObjectShellLock& xDoc, const OUString &rFileName, std::unique_ptr<SfxItemSet> pSet )
293 std::shared_ptr<const SfxFilter> pFilter;
294 SfxMedium aMedium( rFileName, ( StreamMode::READ | StreamMode::SHARE_DENYNONE ) );
296 if ( !aMedium.GetStorage( false ).is() )
297 aMedium.GetInStream();
299 if ( aMedium.GetError() )
301 return aMedium.GetErrorCode();
304 aMedium.UseInteractionHandler( true );
305 ErrCode nErr = GetFilterMatcher().GuessFilter( aMedium, pFilter, SfxFilterFlags::TEMPLATE, SfxFilterFlags::NONE );
306 if ( ERRCODE_NONE != nErr)
308 return ERRCODE_SFX_NOTATEMPLATE;
311 if( !pFilter || !pFilter->IsAllowedAsTemplate() )
313 return ERRCODE_SFX_NOTATEMPLATE;
316 if ( pFilter->GetFilterFlags() & SfxFilterFlags::STARONEFILTER )
318 DBG_ASSERT( !xDoc.Is(), "Sorry, not implemented!" );
319 SfxStringItem aName( SID_FILE_NAME, rFileName );
320 SfxStringItem aReferer( SID_REFERER, "private:user" );
321 SfxStringItem aFlags( SID_OPTIONS, "T" );
322 SfxBoolItem aHidden( SID_HIDDEN, true );
323 const SfxPoolItem *pRet = GetDispatcher_Impl()->ExecuteList(
324 SID_OPENDOC, SfxCallMode::SYNCHRON,
325 { &aName, &aHidden, &aReferer, &aFlags } );
326 const SfxObjectItem *pObj = dynamic_cast<const SfxObjectItem*>( pRet );
327 if ( pObj )
328 xDoc = dynamic_cast<SfxObjectShell*>( pObj->GetShell() );
329 else
331 const SfxViewFrameItem *pView = dynamic_cast<const SfxViewFrameItem*>( pRet );
332 if ( pView )
334 SfxViewFrame *pFrame = pView->GetFrame();
335 if ( pFrame )
336 xDoc = pFrame->GetObjectShell();
340 if ( !xDoc.Is() )
341 return ERRCODE_SFX_DOLOADFAILED;
343 else
345 if ( !xDoc.Is() )
346 xDoc = SfxObjectShell::CreateObject( pFilter->GetServiceName() );
348 //pMedium takes ownership of pSet
349 SfxMedium *pMedium = new SfxMedium( rFileName, StreamMode::STD_READ, pFilter, std::move(pSet) );
350 if(!xDoc->DoLoad(pMedium))
352 ErrCode nErrCode = xDoc->GetErrorCode();
353 xDoc->DoClose();
354 xDoc.Clear();
355 return nErrCode;
361 // TODO: introduce error handling
363 uno::Reference< embed::XStorage > xTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
364 if( !xTempStorage.is() )
365 throw uno::RuntimeException();
367 xDoc->GetStorage()->copyToStorage( xTempStorage );
369 if ( !xDoc->DoSaveCompleted( new SfxMedium( xTempStorage, OUString() ) ) )
370 throw uno::RuntimeException();
372 catch( uno::Exception& )
374 xDoc->DoClose();
375 xDoc.Clear();
377 // TODO: transfer correct error outside
378 return ERRCODE_SFX_GENERAL;
381 SetTemplate_Impl( rFileName, OUString(), xDoc );
383 xDoc->SetNoName();
384 xDoc->InvalidateName();
385 xDoc->SetModified(false);
386 xDoc->ResetError();
388 css::uno::Reference< css::frame::XModel > xModel = xDoc->GetModel();
389 if ( xModel.is() )
391 std::unique_ptr<SfxItemSet> pNew = xDoc->GetMedium()->GetItemSet()->Clone();
392 pNew->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL );
393 pNew->ClearItem( SID_FILTER_NAME );
394 css::uno::Sequence< css::beans::PropertyValue > aArgs;
395 TransformItems( SID_OPENDOC, *pNew, aArgs );
396 sal_Int32 nLength = aArgs.getLength();
397 aArgs.realloc( nLength + 1 );
398 aArgs[nLength].Name = "Title";
399 aArgs[nLength].Value <<= xDoc->GetTitle( SFX_TITLE_DETECT );
400 xModel->attachResource( OUString(), aArgs );
403 return xDoc->GetErrorCode();
407 void SfxApplication::NewDocDirectExec_Impl( SfxRequest& rReq )
409 const SfxStringItem* pFactoryItem = rReq.GetArg<SfxStringItem>(SID_NEWDOCDIRECT);
410 OUString aFactName;
411 if ( pFactoryItem )
412 aFactName = pFactoryItem->GetValue();
413 else
414 aFactName = SvtModuleOptions().GetDefaultModuleName();
416 SfxRequest aReq( SID_OPENDOC, SfxCallMode::SYNCHRON, GetPool() );
417 aReq.AppendItem( SfxStringItem( SID_FILE_NAME, "private:factory/" + aFactName ) );
418 aReq.AppendItem( SfxFrameItem( SID_DOCFRAME, GetFrame() ) );
419 aReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
421 // TODO/LATER: Should the other arguments be transferred as well?
422 const SfxStringItem* pDefaultPathItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILEPATH);
423 if ( pDefaultPathItem )
424 aReq.AppendItem( *pDefaultPathItem );
425 const SfxStringItem* pDefaultNameItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILENAME);
426 if ( pDefaultNameItem )
427 aReq.AppendItem( *pDefaultNameItem );
429 SfxGetpApp()->ExecuteSlot( aReq );
430 const SfxViewFrameItem* pItem = dynamic_cast<const SfxViewFrameItem*>( aReq.GetReturnValue() );
431 if ( pItem )
432 rReq.SetReturnValue( SfxFrameItem( 0, pItem->GetFrame() ) );
435 void SfxApplication::NewDocDirectState_Impl( SfxItemSet &rSet )
437 rSet.Put(SfxStringItem(SID_NEWDOCDIRECT, "private:factory/" + SvtModuleOptions().GetDefaultModuleName()));
440 void SfxApplication::NewDocExec_Impl( SfxRequest& rReq )
442 // No Parameter from BASIC only Factory given?
443 const SfxStringItem* pTemplNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_NAME);
444 const SfxStringItem* pTemplFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
445 const SfxStringItem* pTemplRegionNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_REGIONNAME);
447 SfxObjectShellLock xDoc;
449 OUString aTemplateRegion, aTemplateName, aTemplateFileName;
450 bool bDirect = false; // through FileName instead of Region/Template
451 SfxErrorContext aEc(ERRCTX_SFX_NEWDOC);
452 if ( !pTemplNameItem && !pTemplFileNameItem )
454 bool bNewWin = false;
455 vcl::Window* pTopWin = GetTopWindow();
457 SfxObjectShell* pCurrentShell = SfxObjectShell::Current();
458 Reference<XModel> xModel;
459 if(pCurrentShell)
460 xModel = pCurrentShell->GetModel();
462 SfxTemplateManagerDlg aTemplDlg(rReq.GetFrameWeld());
464 if (xModel.is())
465 aTemplDlg.setDocumentModel(xModel);
467 int nRet = aTemplDlg.run();
468 if ( nRet == RET_OK )
470 rReq.Done();
471 if ( pTopWin != GetTopWindow() )
473 // the dialogue opens a document -> a new TopWindow appears
474 pTopWin = GetTopWindow();
475 bNewWin = true;
479 if ( bNewWin && pTopWin )
480 // after the destruction of the dialogue its parent comes to top,
481 // but we want that the new document is on top
482 pTopWin->ToTop();
484 return;
486 else
488 // Template-Name
489 if ( pTemplNameItem )
490 aTemplateName = pTemplNameItem->GetValue();
492 // Template-Region
493 if ( pTemplRegionNameItem )
494 aTemplateRegion = pTemplRegionNameItem->GetValue();
496 // Template-File-Name
497 if ( pTemplFileNameItem )
499 aTemplateFileName = pTemplFileNameItem->GetValue();
500 bDirect = true;
504 ErrCode lErr = ERRCODE_NONE;
505 SfxItemSet* pSet = new SfxAllItemSet( GetPool() );
506 pSet->Put( SfxBoolItem( SID_TEMPLATE, true ) );
507 if ( !bDirect )
509 SfxDocumentTemplates aTmpFac;
510 if( aTemplateFileName.isEmpty() )
511 aTmpFac.GetFull( aTemplateRegion, aTemplateName, aTemplateFileName );
513 if( aTemplateFileName.isEmpty() )
514 lErr = ERRCODE_SFX_TEMPLATENOTFOUND;
517 INetURLObject aObj( aTemplateFileName );
518 SfxErrorContext aEC( ERRCTX_SFX_LOADTEMPLATE, aObj.PathToFileName() );
520 if ( lErr != ERRCODE_NONE )
522 ErrCode lFatalErr = lErr.IgnoreWarning();
523 if ( lFatalErr )
524 ErrorHandler::HandleError(lErr);
526 else
528 SfxCallMode eMode = SfxCallMode::SYNCHRON;
530 const SfxPoolItem *pRet=nullptr;
531 SfxStringItem aReferer( SID_REFERER, "private:user" );
532 SfxStringItem aTarget( SID_TARGETNAME, "_default" );
533 if ( !aTemplateFileName.isEmpty() )
535 DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" );
537 SfxStringItem aName( SID_FILE_NAME, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
538 SfxStringItem aTemplName( SID_TEMPLATE_NAME, aTemplateName );
539 SfxStringItem aTemplRegionName( SID_TEMPLATE_REGIONNAME, aTemplateRegion );
540 pRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
541 {&aName, &aTarget, &aReferer, &aTemplName, &aTemplRegionName});
543 else
545 SfxStringItem aName( SID_FILE_NAME, "private:factory" );
546 pRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
547 { &aName, &aTarget, &aReferer } );
550 if ( pRet )
551 rReq.SetReturnValue( *pRet );
556 namespace {
559 * Check if a given filter type should open the hyperlinked document
560 * natively.
562 * @param rFilter filter object
564 bool lcl_isFilterNativelySupported(const SfxFilter& rFilter)
566 if (rFilter.IsOwnFormat())
567 return true;
569 const OUString& aName = rFilter.GetFilterName();
570 // We can handle all Excel variants natively.
571 return aName.startsWith("MS Excel");
576 void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq )
578 OUString aDocService;
579 const SfxStringItem* pDocSrvItem = rReq.GetArg<SfxStringItem>(SID_DOC_SERVICE);
580 if (pDocSrvItem)
581 aDocService = pDocSrvItem->GetValue();
583 sal_uInt16 nSID = rReq.GetSlot();
584 const SfxStringItem* pFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
585 if ( pFileNameItem )
587 OUString aCommand( pFileNameItem->GetValue() );
588 const SfxSlot* pSlot = GetInterface()->GetSlot( aCommand );
589 if ( pSlot )
591 pFileNameItem = nullptr;
593 else
595 if ( aCommand.startsWith("slot:") )
597 sal_uInt16 nSlotId = static_cast<sal_uInt16>(aCommand.copy(5).toInt32());
598 if ( nSlotId == SID_OPENDOC )
599 pFileNameItem = nullptr;
604 if ( !pFileNameItem )
606 // get FileName from dialog
607 std::vector<OUString> aURLList;
608 OUString aFilter;
609 std::unique_ptr<SfxItemSet> pSet;
610 OUString aPath;
611 const SfxStringItem* pFolderNameItem = rReq.GetArg<SfxStringItem>(SID_PATH);
612 if ( pFolderNameItem )
613 aPath = pFolderNameItem->GetValue();
614 else if ( nSID == SID_OPENTEMPLATE )
616 aPath = SvtPathOptions().GetTemplatePath();
617 if (!aPath.isEmpty()) // if not empty then get last token
618 aPath = aPath.copy(aPath.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not
621 sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG;
622 const SfxBoolItem* pSystemDialogItem = rReq.GetArg<SfxBoolItem>(SID_FILE_DIALOG);
623 if ( pSystemDialogItem )
624 nDialog = pSystemDialogItem->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM : SFX2_IMPL_DIALOG_OOO;
626 const SfxBoolItem* pRemoteDialogItem = rReq.GetArg<SfxBoolItem>(SID_REMOTE_DIALOG);
627 if ( pRemoteDialogItem && pRemoteDialogItem->GetValue())
628 nDialog = SFX2_IMPL_DIALOG_REMOTE;
630 sal_Int16 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION;
631 FileDialogFlags eDialogFlags = FileDialogFlags::MultiSelection;
632 const SfxBoolItem* pSignPDFItem = rReq.GetArg<SfxBoolItem>(SID_SIGNPDF);
633 if (pSignPDFItem && pSignPDFItem->GetValue())
635 eDialogFlags |= FileDialogFlags::SignPDF;
636 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
639 OUString sStandardDir;
641 const SfxStringItem* pStandardDirItem = rReq.GetArg<SfxStringItem>(SID_STANDARD_DIR);
642 if ( pStandardDirItem )
643 sStandardDir = pStandardDirItem->GetValue();
645 css::uno::Sequence< OUString > aDenyList;
647 const SfxStringListItem* pDenyListItem = rReq.GetArg<SfxStringListItem>(SID_DENY_LIST);
648 if ( pDenyListItem )
649 pDenyListItem->GetStringList( aDenyList );
651 vcl::Window* pTopWindow = GetTopWindow();
652 ErrCode nErr = sfx2::FileOpenDialog_Impl(pTopWindow ? pTopWindow->GetFrameWeld() : nullptr,
653 nDialogType,
654 eDialogFlags, aURLList,
655 aFilter, pSet, &aPath, nDialog, sStandardDir, aDenyList);
657 if ( nErr == ERRCODE_ABORT )
659 aURLList.clear();
660 return;
663 rReq.SetArgs( *static_cast<SfxAllItemSet*>(pSet.get()) );
664 if ( !aFilter.isEmpty() )
665 rReq.AppendItem( SfxStringItem( SID_FILTER_NAME, aFilter ) );
666 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
667 rReq.AppendItem( SfxStringItem( SID_REFERER, "private:user" ) );
668 pSet.reset();
670 if(!aURLList.empty())
672 if ( nSID == SID_OPENTEMPLATE )
673 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
675 // This helper wraps an existing (or may new created InteractionHandler)
676 // intercept all incoming interactions and provide useful information
677 // later if the following transaction was finished.
679 sfx2::PreventDuplicateInteraction* pHandler = new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext());
680 uno::Reference<task::XInteractionHandler> xHandler(static_cast< css::task::XInteractionHandler* >(pHandler), css::uno::UNO_QUERY);
681 uno::Reference<task::XInteractionHandler> xWrappedHandler;
683 // wrap existing handler or create new UUI handler
684 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
685 if (pInteractionItem)
687 pInteractionItem->GetValue() >>= xWrappedHandler;
688 rReq.RemoveItem( SID_INTERACTIONHANDLER );
690 if (xWrappedHandler.is())
691 pHandler->setHandler(xWrappedHandler);
692 else
693 pHandler->useDefaultUUIHandler();
694 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHandler)) );
696 // define rules for this handler
697 css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get();
698 ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule(aInteraction);
699 pHandler->addInteractionRule(aRule);
701 if (!aDocService.isEmpty())
703 rReq.RemoveItem(SID_DOC_SERVICE);
704 rReq.AppendItem(SfxStringItem(SID_DOC_SERVICE, aDocService));
707 for (auto const& url : aURLList)
709 rReq.RemoveItem( SID_FILE_NAME );
710 rReq.AppendItem( SfxStringItem( SID_FILE_NAME, url ) );
712 // Run synchronous, so that not the next document is loaded
713 // when rescheduling
714 // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished
715 // but only if reschedule is a problem
716 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
718 // check for special interaction "NO MORE DOCUMENTS ALLOWED" and
719 // break loop then. Otherwise we risk showing the same interaction more than once.
720 if ( pHandler->getInteractionInfo(aInteraction, &aRule) )
722 if (aRule.m_nCallCount > 0)
724 if (aRule.m_xRequest.is())
726 css::task::ErrorCodeRequest aRequest;
727 if (aRule.m_xRequest->getRequest() >>= aRequest)
729 if (aRequest.ErrCode == sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED)))
730 break;
737 aURLList.clear();
738 return;
740 aURLList.clear();
743 bool bHyperlinkUsed = false;
745 if ( SID_OPENURL == nSID )
747 // SID_OPENURL does the same as SID_OPENDOC!
748 rReq.SetSlot( SID_OPENDOC );
750 else if ( nSID == SID_OPENTEMPLATE )
752 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
754 // pass URL to OS by using ShellExecuter or open it internal
755 // if it seems to be an own format.
756 /* Attention!
757 There exist two possibilities to open hyperlinks:
758 a) using SID_OPENHYPERLINK (new)
759 b) using SID_BROWSE (old)
761 else if ( nSID == SID_OPENHYPERLINK )
763 rReq.SetSlot( SID_OPENDOC );
764 bHyperlinkUsed = true;
767 // no else here! It's optional ...
768 if (!bHyperlinkUsed)
770 const SfxBoolItem* pHyperLinkUsedItem = rReq.GetArg<SfxBoolItem>(SID_BROWSE);
771 if ( pHyperLinkUsedItem )
772 bHyperlinkUsed = pHyperLinkUsedItem->GetValue();
773 // no "official" item, so remove it from ItemSet before using UNO-API
774 rReq.RemoveItem( SID_BROWSE );
777 const SfxStringItem* pFileName = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
778 OUString aFileName = pFileName->GetValue();
780 OUString aReferer;
781 const SfxStringItem* pRefererItem = rReq.GetArg<SfxStringItem>(SID_REFERER);
782 if ( pRefererItem )
783 aReferer = pRefererItem->GetValue();
785 const SfxStringItem* pFileFlagsItem = rReq.GetArg<SfxStringItem>(SID_OPTIONS);
786 if ( pFileFlagsItem )
788 const OUString aFileFlags = pFileFlagsItem->GetValue().toAsciiUpperCase();
789 if ( aFileFlags.indexOf('T') >= 0 )
791 rReq.RemoveItem( SID_TEMPLATE );
792 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, true ) );
795 if ( aFileFlags.indexOf('H') >= 0 )
797 rReq.RemoveItem( SID_HIDDEN );
798 rReq.AppendItem( SfxBoolItem( SID_HIDDEN, true ) );
801 if ( aFileFlags.indexOf('R') >= 0 )
803 rReq.RemoveItem( SID_DOC_READONLY );
804 rReq.AppendItem( SfxBoolItem( SID_DOC_READONLY, true ) );
807 if ( aFileFlags.indexOf('B') >= 0 )
809 rReq.RemoveItem( SID_PREVIEW );
810 rReq.AppendItem( SfxBoolItem( SID_PREVIEW, true ) );
813 rReq.RemoveItem( SID_OPTIONS );
816 // Mark without URL cannot be handled by hyperlink code
817 if ( bHyperlinkUsed && !aFileName.isEmpty() && aFileName[0] != '#' )
819 uno::Reference<document::XTypeDetection> xTypeDetection(
820 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), UNO_QUERY);
822 if ( xTypeDetection.is() )
824 URL aURL;
826 aURL.Complete = aFileName;
827 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
828 xTrans->parseStrict( aURL );
830 INetProtocol aINetProtocol = INetURLObject( aURL.Complete ).GetProtocol();
831 auto eMode = officecfg::Office::Security::Hyperlinks::Open::get();
833 if ( eMode == SvtExtendedSecurityOptions::OPEN_NEVER && aINetProtocol != INetProtocol::VndSunStarHelp )
835 SolarMutexGuard aGuard;
836 vcl::Window *pWindow = SfxGetpApp()->GetTopWindow();
838 std::unique_ptr<weld::MessageDialog> xSecurityWarningBox(Application::CreateMessageDialog(pWindow ? pWindow->GetFrameWeld() : nullptr,
839 VclMessageType::Warning, VclButtonsType::Ok, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS)));
840 xSecurityWarningBox->set_title(SfxResId(RID_SECURITY_WARNING_TITLE));
841 xSecurityWarningBox->run();
842 return;
845 const OUString aTypeName { xTypeDetection->queryTypeByURL( aURL.Main ) };
846 SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
847 std::shared_ptr<const SfxFilter> pFilter = rMatcher.GetFilter4EA( aTypeName );
848 if (!pFilter || !lcl_isFilterNativelySupported(*pFilter))
850 // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS
851 if ( aINetProtocol == INetProtocol::Mailto )
853 // don't dispatch mailto hyperlink to desktop dispatcher
854 rReq.RemoveItem( SID_TARGETNAME );
855 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_self" ) );
857 else if ( aINetProtocol == INetProtocol::Ftp ||
858 aINetProtocol == INetProtocol::Http ||
859 aINetProtocol == INetProtocol::Https )
861 sfx2::openUriExternally(aURL.Complete, true);
862 return;
864 else
866 // check for "internal" protocols that should not be forwarded to the system
867 std::vector < OUString > aProtocols(2);
869 // add special protocols that always should be treated as internal
870 aProtocols[0] = "private:*";
871 aProtocols[1] = "vnd.sun.star.*";
873 // get registered protocol handlers from configuration
874 Reference < XNameAccess > xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get());
875 const Sequence < OUString > aNames = xAccess->getElementNames();
876 for ( const auto& rName : aNames )
878 Reference < XPropertySet > xSet;
879 Any aRet = xAccess->getByName( rName );
880 aRet >>= xSet;
881 if ( xSet.is() )
883 // copy protocols
884 aRet = xSet->getPropertyValue("Protocols");
885 Sequence < OUString > aTmp;
886 aRet >>= aTmp;
888 aProtocols.insert(aProtocols.end(),aTmp.begin(),aTmp.end());
892 bool bFound = false;
893 for (const OUString & rProtocol : aProtocols)
895 WildCard aPattern(rProtocol);
896 if ( aPattern.Matches( aURL.Complete ) )
898 bFound = true;
899 break;
903 if ( !bFound )
905 bool bLoadInternal = false;
908 sfx2::openUriExternally(
909 aURL.Complete, pFilter == nullptr);
911 catch ( css::system::SystemShellExecuteException& )
913 rReq.RemoveItem( SID_TARGETNAME );
914 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
915 bLoadInternal = true;
917 if ( !bLoadInternal )
918 return;
922 else
924 // hyperlink document must be loaded into a new frame
925 rReq.RemoveItem( SID_TARGETNAME );
926 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
931 if (!SvtSecurityOptions().isSecureMacroUri(aFileName, aReferer))
933 SfxErrorContext aCtx( ERRCTX_SFX_OPENDOC, aFileName );
934 ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED );
935 return;
938 SfxFrame* pTargetFrame = nullptr;
939 Reference< XFrame > xTargetFrame;
941 const SfxFrameItem* pFrameItem = rReq.GetArg<SfxFrameItem>(SID_DOCFRAME);
942 if ( pFrameItem )
943 pTargetFrame = pFrameItem->GetFrame();
945 if ( !pTargetFrame )
947 const SfxUnoFrameItem* pUnoFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME);
948 if ( pUnoFrameItem )
949 xTargetFrame = pUnoFrameItem->GetFrame();
952 if ( !pTargetFrame && !xTargetFrame.is() && SfxViewFrame::Current() )
953 pTargetFrame = &SfxViewFrame::Current()->GetFrame();
955 // check if caller has set a callback
956 std::unique_ptr<SfxLinkItem> pLinkItem;
958 // remove from Itemset, because it confuses the parameter transformation
959 if (auto pParamLinkItem = rReq.GetArg<SfxLinkItem>(SID_DONELINK))
960 pLinkItem.reset(pParamLinkItem->Clone());
962 rReq.RemoveItem( SID_DONELINK );
964 // check if the view must be hidden
965 bool bHidden = false;
966 const SfxBoolItem* pHidItem = rReq.GetArg<SfxBoolItem>(SID_HIDDEN);
967 if ( pHidItem )
968 bHidden = pHidItem->GetValue();
970 // This request is a UI call. We have to set the right values inside the MediaDescriptor
971 // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate.
972 // But we have to look for already existing values or for real hidden requests.
973 const SfxBoolItem* pPreviewItem = rReq.GetArg<SfxBoolItem>(SID_PREVIEW);
974 if (!bHidden && ( !pPreviewItem || !pPreviewItem->GetValue() ) )
976 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
977 const SfxUInt16Item* pMacroExecItem = rReq.GetArg<SfxUInt16Item>(SID_MACROEXECMODE);
978 const SfxUInt16Item* pDocTemplateItem = rReq.GetArg<SfxUInt16Item>(SID_UPDATEDOCMODE);
980 if (!pInteractionItem)
982 Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr );
983 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHdl)) );
985 if (!pMacroExecItem)
986 rReq.AppendItem( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) );
987 if (!pDocTemplateItem)
988 rReq.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) );
991 // extract target name
992 OUString aTarget;
993 const SfxStringItem* pTargetItem = rReq.GetArg<SfxStringItem>(SID_TARGETNAME);
994 if ( pTargetItem )
995 aTarget = pTargetItem->GetValue();
996 else
998 const SfxBoolItem* pNewViewItem = rReq.GetArg<SfxBoolItem>(SID_OPEN_NEW_VIEW);
999 if ( pNewViewItem && pNewViewItem->GetValue() )
1000 aTarget = "_blank" ;
1003 if ( bHidden )
1005 aTarget = "_blank";
1006 DBG_ASSERT( rReq.IsSynchronCall() || pLinkItem, "Hidden load process must be done synchronously!" );
1009 Reference < XController > xController;
1010 // if a frame is given, it must be used for the starting point of the targeting mechanism
1011 // this code is also used if asynchronous loading is possible, because loadComponent always is synchron
1012 if ( !xTargetFrame.is() )
1014 if ( pTargetFrame )
1016 xTargetFrame = pTargetFrame->GetFrameInterface();
1018 else
1020 xTargetFrame = Desktop::create(::comphelper::getProcessComponentContext());
1024 // make URL ready
1025 const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
1026 aFileName = pURLItem->GetValue();
1027 if( aFileName.startsWith("#") ) // Mark without URL
1029 SfxViewFrame *pView = pTargetFrame ? pTargetFrame->GetCurrentViewFrame() : nullptr;
1030 if ( !pView )
1031 pView = SfxViewFrame::Current();
1032 pView->GetViewShell()->JumpToMark( aFileName.copy(1) );
1033 rReq.SetReturnValue( SfxViewFrameItem( pView ) );
1034 return;
1037 // convert items to properties for framework API calls
1038 Sequence < PropertyValue > aArgs;
1039 TransformItems( SID_OPENDOC, *rReq.GetArgs(), aArgs );
1040 // Any Referer (that was relevant in the above call to
1041 // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming
1042 // this "open" request is initiated directly by the user:
1043 auto pArg = std::find_if(aArgs.begin(), aArgs.end(),
1044 [](const PropertyValue& rArg) { return rArg.Name == "Referer"; });
1045 if (pArg != aArgs.end())
1047 auto nIndex = static_cast<sal_Int32>(std::distance(aArgs.begin(), pArg));
1048 comphelper::removeElementAt(aArgs, nIndex);
1051 // TODO/LATER: either remove LinkItem or create an asynchronous process for it
1052 if( bHidden || pLinkItem || rReq.IsSynchronCall() )
1054 // if loading must be done synchron, we must wait for completion to get a return value
1055 // find frame by myself; I must know the exact frame to get the controller for the return value from it
1056 Reference < XComponent > xComp;
1060 xComp = ::comphelper::SynchronousDispatch::dispatch( xTargetFrame, aFileName, aTarget, aArgs );
1062 catch(const RuntimeException&)
1064 throw;
1066 catch(const css::uno::Exception&)
1070 Reference < XModel > xModel( xComp, UNO_QUERY );
1071 if ( xModel.is() )
1072 xController = xModel->getCurrentController();
1073 else
1074 xController.set( xComp, UNO_QUERY );
1077 else
1079 URL aURL;
1080 aURL.Complete = aFileName;
1081 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
1082 xTrans->parseStrict( aURL );
1084 Reference < XDispatchProvider > xProv( xTargetFrame, UNO_QUERY );
1085 Reference < XDispatch > xDisp = xProv.is() ? xProv->queryDispatch( aURL, aTarget, FrameSearchFlag::ALL ) : Reference < XDispatch >();
1086 if ( xDisp.is() )
1087 xDisp->dispatch( aURL, aArgs );
1090 if ( xController.is() )
1092 // try to find the SfxFrame for the controller
1093 SfxFrame* pCntrFrame = nullptr;
1094 for ( SfxViewShell* pShell = SfxViewShell::GetFirst( false ); pShell; pShell = SfxViewShell::GetNext( *pShell, false ) )
1096 if ( pShell->GetController() == xController )
1098 pCntrFrame = &pShell->GetViewFrame()->GetFrame();
1099 break;
1103 if ( pCntrFrame )
1105 SfxObjectShell* pSh = pCntrFrame->GetCurrentDocument();
1106 DBG_ASSERT( pSh, "Controller without ObjectShell ?!" );
1108 rReq.SetReturnValue( SfxViewFrameItem( pCntrFrame->GetCurrentViewFrame() ) );
1110 if ( bHidden )
1111 pSh->RestoreNoDelete();
1115 if (pLinkItem)
1117 const SfxPoolItem* pRetValue = rReq.GetReturnValue();
1118 if (pRetValue)
1120 pLinkItem->GetValue().Call(pRetValue);
1125 void SfxApplication::OpenRemoteExec_Impl( SfxRequest& rReq )
1127 rReq.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG, true ) );
1128 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
1131 void SfxApplication::SignPDFExec_Impl(SfxRequest& rReq)
1133 rReq.AppendItem(SfxBoolItem(SID_SIGNPDF, true));
1134 GetDispatcher_Impl()->Execute(SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs());
1137 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */