1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
45
46 #include <comphelper/processfactory.hxx>
47 #include <comphelper/sequence.hxx>
48 #include <comphelper/storagehelper.hxx>
49 #include <comphelper/synchronousdispatch.hxx>
50
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>
65
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>
87
88 #include <officecfg/Office/ProtocolHandler.hxx>
89 #include <officecfg/Office/Security.hxx>
90
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;
101
SetTemplate_Impl(const OUString & rFileName,const OUString & rLongName,SfxObjectShell * pDoc)102 void SetTemplate_Impl( const OUString &rFileName,
103 const OUString &rLongName,
104 SfxObjectShell *pDoc)
105 {
106 // write TemplateName to DocumentProperties of document
107 // TemplateDate stays as default (=current date)
108 pDoc->ResetFromTemplate( rLongName, rFileName );
109 }
110
111 namespace {
112
113 class SfxDocPasswordVerifier : public ::comphelper::IDocPasswordVerifier
114 {
115 public:
SfxDocPasswordVerifier(const Reference<embed::XStorage> & rxStorage)116 explicit SfxDocPasswordVerifier( const Reference< embed::XStorage >& rxStorage ) :
117 mxStorage( rxStorage ) {}
118
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;
123
124
125 private:
126 Reference< embed::XStorage > mxStorage;
127 };
128
129 }
130
verifyPassword(const OUString & rPassword,uno::Sequence<beans::NamedValue> & o_rEncryptionData)131 ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
132 {
133 o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( rPassword );
134 return verifyEncryptionData( o_rEncryptionData );
135 }
136
137
verifyEncryptionData(const uno::Sequence<beans::NamedValue> & rEncryptionData)138 ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
139 {
140 ::comphelper::DocPasswordVerifierResult eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
141 try
142 {
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 );
147
148 mxStorage->openStreamElement(
149 "content.xml",
150 embed::ElementModes::READ | embed::ElementModes::NOCREATE );
151
152 // no exception -> success
153 eResult = ::comphelper::DocPasswordVerifierResult::OK;
154 }
155 catch( const packages::WrongPasswordException& )
156 {
157 eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword;
158 }
159 catch( const uno::Exception& )
160 {
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;
164 }
165 return eResult;
166 }
167
168
CheckPasswd_Impl(SfxObjectShell * pDoc,SfxMedium * pFile)169 ErrCode CheckPasswd_Impl
170 (
171 SfxObjectShell* pDoc,
172 SfxMedium* pFile // the Medium and its Password should be obtained
173 )
174
175 /* [Description]
176
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.
181 */
182 {
183 ErrCode nRet = ERRCODE_NONE;
184
185 if( !pFile->GetFilter() || pFile->IsStorage() )
186 {
187 uno::Reference< embed::XStorage > xStorage = pFile->GetStorage();
188 if( xStorage.is() )
189 {
190 uno::Reference< beans::XPropertySet > xStorageProps( xStorage, uno::UNO_QUERY );
191 if ( xStorageProps.is() )
192 {
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& )
201 {
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
205 }
206
207 if ( bIsEncrypted )
208 {
209 css::uno::Reference<css::awt::XWindow> xWin(pDoc ? pDoc->GetDialogParent(pFile) : nullptr);
210 if (xWin)
211 xWin->setVisible(true);
212
213 nRet = ERRCODE_SFX_CANTGETPASSWD;
214
215 SfxItemSet *pSet = pFile->GetItemSet();
216 if( pSet )
217 {
218 Reference< css::task::XInteractionHandler > xInteractionHandler = pFile->GetInteractionHandler();
219 if( xInteractionHandler.is() )
220 {
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();
226
227 uno::Sequence< beans::NamedValue > aEncryptionData;
228 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pSet, SID_ENCRYPTIONDATA, false);
229 if ( pEncryptionDataItem )
230 pEncryptionDataItem->GetValue() >>= aEncryptionData;
231
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);
237
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)
244 {
245 aEncryptionData = comphelper::concatSequences(
246 aEncryptionData, std::initializer_list<beans::NamedValue>{
247 { "ForSalvage", css::uno::Any(true) } });
248 }
249
250 SfxDocPasswordVerifier aVerifier( xStorage );
251 aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
252 aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard );
253
254 pSet->ClearItem( SID_PASSWORD );
255 pSet->ClearItem( SID_ENCRYPTIONDATA );
256
257 if ( aEncryptionData.hasElements() )
258 {
259 pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
260
261 try
262 {
263 // update the version list of the medium using the new password
264 pFile->GetVersionList();
265 }
266 catch( uno::Exception& )
267 {
268 // TODO/LATER: set the error code
269 }
270
271 nRet = ERRCODE_NONE;
272 }
273 else
274 nRet = ERRCODE_IO_ABORT;
275 }
276 }
277 }
278 }
279 else
280 {
281 OSL_FAIL( "A storage must implement XPropertySet interface!" );
282 nRet = ERRCODE_SFX_CANTGETPASSWD;
283 }
284 }
285 }
286
287 return nRet;
288 }
289
290
LoadTemplate(SfxObjectShellLock & xDoc,const OUString & rFileName,std::unique_ptr<SfxItemSet> pSet)291 ErrCode SfxApplication::LoadTemplate( SfxObjectShellLock& xDoc, const OUString &rFileName, std::unique_ptr<SfxItemSet> pSet )
292 {
293 std::shared_ptr<const SfxFilter> pFilter;
294 SfxMedium aMedium( rFileName, ( StreamMode::READ | StreamMode::SHARE_DENYNONE ) );
295
296 if ( !aMedium.GetStorage( false ).is() )
297 aMedium.GetInStream();
298
299 if ( aMedium.GetError() )
300 {
301 return aMedium.GetErrorCode();
302 }
303
304 aMedium.UseInteractionHandler( true );
305 ErrCode nErr = GetFilterMatcher().GuessFilter( aMedium, pFilter, SfxFilterFlags::TEMPLATE, SfxFilterFlags::NONE );
306 if ( ERRCODE_NONE != nErr)
307 {
308 return ERRCODE_SFX_NOTATEMPLATE;
309 }
310
311 if( !pFilter || !pFilter->IsAllowedAsTemplate() )
312 {
313 return ERRCODE_SFX_NOTATEMPLATE;
314 }
315
316 if ( pFilter->GetFilterFlags() & SfxFilterFlags::STARONEFILTER )
317 {
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
330 {
331 const SfxViewFrameItem *pView = dynamic_cast<const SfxViewFrameItem*>( pRet );
332 if ( pView )
333 {
334 SfxViewFrame *pFrame = pView->GetFrame();
335 if ( pFrame )
336 xDoc = pFrame->GetObjectShell();
337 }
338 }
339
340 if ( !xDoc.Is() )
341 return ERRCODE_SFX_DOLOADFAILED;
342 }
343 else
344 {
345 if ( !xDoc.Is() )
346 xDoc = SfxObjectShell::CreateObject( pFilter->GetServiceName() );
347
348 //pMedium takes ownership of pSet
349 SfxMedium *pMedium = new SfxMedium( rFileName, StreamMode::STD_READ, pFilter, std::move(pSet) );
350 if(!xDoc->DoLoad(pMedium))
351 {
352 ErrCode nErrCode = xDoc->GetErrorCode();
353 xDoc->DoClose();
354 xDoc.Clear();
355 return nErrCode;
356 }
357 }
358
359 try
360 {
361 // TODO: introduce error handling
362
363 uno::Reference< embed::XStorage > xTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage();
364 if( !xTempStorage.is() )
365 throw uno::RuntimeException();
366
367 xDoc->GetStorage()->copyToStorage( xTempStorage );
368
369 if ( !xDoc->DoSaveCompleted( new SfxMedium( xTempStorage, OUString() ) ) )
370 throw uno::RuntimeException();
371 }
372 catch( uno::Exception& )
373 {
374 xDoc->DoClose();
375 xDoc.Clear();
376
377 // TODO: transfer correct error outside
378 return ERRCODE_SFX_GENERAL;
379 }
380
381 SetTemplate_Impl( rFileName, OUString(), xDoc );
382
383 xDoc->SetNoName();
384 xDoc->InvalidateName();
385 xDoc->SetModified(false);
386 xDoc->ResetError();
387
388 css::uno::Reference< css::frame::XModel > xModel = xDoc->GetModel();
389 if ( xModel.is() )
390 {
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 );
401 }
402
403 return xDoc->GetErrorCode();
404 }
405
406
NewDocDirectExec_Impl(SfxRequest & rReq)407 void SfxApplication::NewDocDirectExec_Impl( SfxRequest& rReq )
408 {
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();
415
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" ) );
420
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 );
428
429 SfxGetpApp()->ExecuteSlot( aReq );
430 const SfxViewFrameItem* pItem = dynamic_cast<const SfxViewFrameItem*>( aReq.GetReturnValue() );
431 if ( pItem )
432 rReq.SetReturnValue( SfxFrameItem( 0, pItem->GetFrame() ) );
433 }
434
NewDocDirectState_Impl(SfxItemSet & rSet)435 void SfxApplication::NewDocDirectState_Impl( SfxItemSet &rSet )
436 {
437 rSet.Put(SfxStringItem(SID_NEWDOCDIRECT, "private:factory/" + SvtModuleOptions().GetDefaultModuleName()));
438 }
439
NewDocExec_Impl(SfxRequest & rReq)440 void SfxApplication::NewDocExec_Impl( SfxRequest& rReq )
441 {
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);
446
447 SfxObjectShellLock xDoc;
448
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 )
453 {
454 bool bNewWin = false;
455 weld::Window* pTopWin = GetTopWindow();
456
457 SfxObjectShell* pCurrentShell = SfxObjectShell::Current();
458 Reference<XModel> xModel;
459 if(pCurrentShell)
460 xModel = pCurrentShell->GetModel();
461
462 SfxTemplateManagerDlg aTemplDlg(rReq.GetFrameWeld());
463
464 if (xModel.is())
465 aTemplDlg.setDocumentModel(xModel);
466
467 int nRet = aTemplDlg.run();
468 if ( nRet == RET_OK )
469 {
470 rReq.Done();
471 if ( pTopWin != GetTopWindow() )
472 {
473 // the dialogue opens a document -> a new TopWindow appears
474 pTopWin = GetTopWindow();
475 bNewWin = true;
476 }
477 }
478
479 if (bNewWin && pTopWin)
480 {
481 // after the destruction of the dialogue its parent comes to top,
482 // but we want that the new document is on top
483 pTopWin->present();
484 }
485
486 return;
487 }
488 else
489 {
490 // Template-Name
491 if ( pTemplNameItem )
492 aTemplateName = pTemplNameItem->GetValue();
493
494 // Template-Region
495 if ( pTemplRegionNameItem )
496 aTemplateRegion = pTemplRegionNameItem->GetValue();
497
498 // Template-File-Name
499 if ( pTemplFileNameItem )
500 {
501 aTemplateFileName = pTemplFileNameItem->GetValue();
502 bDirect = true;
503 }
504 }
505
506 ErrCode lErr = ERRCODE_NONE;
507 SfxItemSet* pSet = new SfxAllItemSet( GetPool() );
508 pSet->Put( SfxBoolItem( SID_TEMPLATE, true ) );
509 if ( !bDirect )
510 {
511 SfxDocumentTemplates aTmpFac;
512 if( aTemplateFileName.isEmpty() )
513 aTmpFac.GetFull( aTemplateRegion, aTemplateName, aTemplateFileName );
514
515 if( aTemplateFileName.isEmpty() )
516 lErr = ERRCODE_SFX_TEMPLATENOTFOUND;
517 }
518
519 INetURLObject aObj( aTemplateFileName );
520 SfxErrorContext aEC( ERRCTX_SFX_LOADTEMPLATE, aObj.PathToFileName() );
521
522 if ( lErr != ERRCODE_NONE )
523 {
524 ErrCode lFatalErr = lErr.IgnoreWarning();
525 if ( lFatalErr )
526 ErrorHandler::HandleError(lErr);
527 }
528 else
529 {
530 SfxCallMode eMode = SfxCallMode::SYNCHRON;
531
532 const SfxPoolItem *pRet=nullptr;
533 SfxStringItem aReferer( SID_REFERER, "private:user" );
534 SfxStringItem aTarget( SID_TARGETNAME, "_default" );
535 if ( !aTemplateFileName.isEmpty() )
536 {
537 DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" );
538
539 SfxStringItem aName( SID_FILE_NAME, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
540 SfxStringItem aTemplName( SID_TEMPLATE_NAME, aTemplateName );
541 SfxStringItem aTemplRegionName( SID_TEMPLATE_REGIONNAME, aTemplateRegion );
542 pRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
543 {&aName, &aTarget, &aReferer, &aTemplName, &aTemplRegionName});
544 }
545 else
546 {
547 SfxStringItem aName( SID_FILE_NAME, "private:factory" );
548 pRet = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode,
549 { &aName, &aTarget, &aReferer } );
550 }
551
552 if ( pRet )
553 rReq.SetReturnValue( *pRet );
554 }
555 }
556
557
558 namespace {
559
560 /**
561 * Check if a given filter type should open the hyperlinked document
562 * natively.
563 *
564 * @param rFilter filter object
565 */
lcl_isFilterNativelySupported(const SfxFilter & rFilter)566 bool lcl_isFilterNativelySupported(const SfxFilter& rFilter)
567 {
568 if (rFilter.IsOwnFormat())
569 return true;
570
571 const OUString& aName = rFilter.GetFilterName();
572 // We can handle all Excel variants natively.
573 return aName.startsWith("MS Excel");
574 }
575
576 }
577
OpenDocExec_Impl(SfxRequest & rReq)578 void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq )
579 {
580 OUString aDocService;
581 const SfxStringItem* pDocSrvItem = rReq.GetArg<SfxStringItem>(SID_DOC_SERVICE);
582 if (pDocSrvItem)
583 aDocService = pDocSrvItem->GetValue();
584
585 sal_uInt16 nSID = rReq.GetSlot();
586 const SfxStringItem* pFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
587 if ( pFileNameItem )
588 {
589 OUString aCommand( pFileNameItem->GetValue() );
590 const SfxSlot* pSlot = GetInterface()->GetSlot( aCommand );
591 if ( pSlot )
592 {
593 pFileNameItem = nullptr;
594 }
595 else
596 {
597 if ( aCommand.startsWith("slot:") )
598 {
599 sal_uInt16 nSlotId = static_cast<sal_uInt16>(aCommand.copy(5).toInt32());
600 if ( nSlotId == SID_OPENDOC )
601 pFileNameItem = nullptr;
602 }
603 }
604 }
605
606 if ( !pFileNameItem )
607 {
608 // get FileName from dialog
609 std::vector<OUString> aURLList;
610 OUString aFilter;
611 std::unique_ptr<SfxItemSet> pSet;
612 OUString aPath;
613 const SfxStringItem* pFolderNameItem = rReq.GetArg<SfxStringItem>(SID_PATH);
614 if ( pFolderNameItem )
615 aPath = pFolderNameItem->GetValue();
616 else if ( nSID == SID_OPENTEMPLATE )
617 {
618 aPath = SvtPathOptions().GetTemplatePath();
619 if (!aPath.isEmpty()) // if not empty then get last token
620 aPath = aPath.copy(aPath.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not
621 }
622
623 sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG;
624 const SfxBoolItem* pSystemDialogItem = rReq.GetArg<SfxBoolItem>(SID_FILE_DIALOG);
625 if ( pSystemDialogItem )
626 nDialog = pSystemDialogItem->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM : SFX2_IMPL_DIALOG_OOO;
627
628 const SfxBoolItem* pRemoteDialogItem = rReq.GetArg<SfxBoolItem>(SID_REMOTE_DIALOG);
629 if ( pRemoteDialogItem && pRemoteDialogItem->GetValue())
630 nDialog = SFX2_IMPL_DIALOG_REMOTE;
631
632 sal_Int16 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION;
633 FileDialogFlags eDialogFlags = FileDialogFlags::MultiSelection;
634 const SfxBoolItem* pSignPDFItem = rReq.GetArg<SfxBoolItem>(SID_SIGNPDF);
635 if (pSignPDFItem && pSignPDFItem->GetValue())
636 {
637 eDialogFlags |= FileDialogFlags::SignPDF;
638 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE;
639 }
640
641 OUString sStandardDir;
642
643 const SfxStringItem* pStandardDirItem = rReq.GetArg<SfxStringItem>(SID_STANDARD_DIR);
644 if ( pStandardDirItem )
645 sStandardDir = pStandardDirItem->GetValue();
646
647 css::uno::Sequence< OUString > aDenyList;
648
649 const SfxStringListItem* pDenyListItem = rReq.GetArg<SfxStringListItem>(SID_DENY_LIST);
650 if ( pDenyListItem )
651 pDenyListItem->GetStringList( aDenyList );
652
653 weld::Window* pTopWindow = GetTopWindow();
654 ErrCode nErr = sfx2::FileOpenDialog_Impl(pTopWindow,
655 nDialogType,
656 eDialogFlags, aURLList,
657 aFilter, pSet, &aPath, nDialog, sStandardDir, aDenyList);
658
659 if ( nErr == ERRCODE_ABORT )
660 {
661 aURLList.clear();
662 return;
663 }
664
665 rReq.SetArgs( *static_cast<SfxAllItemSet*>(pSet.get()) );
666 if ( !aFilter.isEmpty() )
667 rReq.AppendItem( SfxStringItem( SID_FILTER_NAME, aFilter ) );
668 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
669 rReq.AppendItem( SfxStringItem( SID_REFERER, "private:user" ) );
670 pSet.reset();
671
672 if(!aURLList.empty())
673 {
674 if ( nSID == SID_OPENTEMPLATE )
675 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
676
677 // This helper wraps an existing (or may new created InteractionHandler)
678 // intercept all incoming interactions and provide useful information
679 // later if the following transaction was finished.
680
681 rtl::Reference<sfx2::PreventDuplicateInteraction> pHandler = new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext());
682 uno::Reference<task::XInteractionHandler> xHandler(pHandler);
683 uno::Reference<task::XInteractionHandler> xWrappedHandler;
684
685 // wrap existing handler or create new UUI handler
686 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
687 if (pInteractionItem)
688 {
689 pInteractionItem->GetValue() >>= xWrappedHandler;
690 rReq.RemoveItem( SID_INTERACTIONHANDLER );
691 }
692 if (xWrappedHandler.is())
693 pHandler->setHandler(xWrappedHandler);
694 else
695 pHandler->useDefaultUUIHandler();
696 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHandler)) );
697
698 // define rules for this handler
699 css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get();
700 ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule(aInteraction);
701 pHandler->addInteractionRule(aRule);
702
703 if (!aDocService.isEmpty())
704 {
705 rReq.RemoveItem(SID_DOC_SERVICE);
706 rReq.AppendItem(SfxStringItem(SID_DOC_SERVICE, aDocService));
707 }
708
709 for (auto const& url : aURLList)
710 {
711 rReq.RemoveItem( SID_FILE_NAME );
712 rReq.AppendItem( SfxStringItem( SID_FILE_NAME, url ) );
713
714 // Run synchronous, so that not the next document is loaded
715 // when rescheduling
716 // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished
717 // but only if reschedule is a problem
718 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
719
720 // check for special interaction "NO MORE DOCUMENTS ALLOWED" and
721 // break loop then. Otherwise we risk showing the same interaction more than once.
722 if ( pHandler->getInteractionInfo(aInteraction, &aRule) )
723 {
724 if (aRule.m_nCallCount > 0)
725 {
726 if (aRule.m_xRequest.is())
727 {
728 css::task::ErrorCodeRequest aRequest;
729 if (aRule.m_xRequest->getRequest() >>= aRequest)
730 {
731 if (aRequest.ErrCode == sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED)))
732 break;
733 }
734 }
735 }
736 }
737 }
738
739 aURLList.clear();
740 return;
741 }
742 aURLList.clear();
743 }
744
745 bool bHyperlinkUsed = false;
746
747 if ( SID_OPENURL == nSID )
748 {
749 // SID_OPENURL does the same as SID_OPENDOC!
750 rReq.SetSlot( SID_OPENDOC );
751 }
752 else if ( nSID == SID_OPENTEMPLATE )
753 {
754 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) );
755 }
756 // pass URL to OS by using ShellExecuter or open it internal
757 // if it seems to be an own format.
758 /* Attention!
759 There exist two possibilities to open hyperlinks:
760 a) using SID_OPENHYPERLINK (new)
761 b) using SID_BROWSE (old)
762 */
763 else if ( nSID == SID_OPENHYPERLINK )
764 {
765 rReq.SetSlot( SID_OPENDOC );
766 bHyperlinkUsed = true;
767 }
768
769 // no else here! It's optional ...
770 if (!bHyperlinkUsed)
771 {
772 const SfxBoolItem* pHyperLinkUsedItem = rReq.GetArg<SfxBoolItem>(SID_BROWSE);
773 if ( pHyperLinkUsedItem )
774 bHyperlinkUsed = pHyperLinkUsedItem->GetValue();
775 // no "official" item, so remove it from ItemSet before using UNO-API
776 rReq.RemoveItem( SID_BROWSE );
777 }
778
779 const SfxStringItem* pFileName = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
780 OUString aFileName = pFileName->GetValue();
781
782 OUString aReferer;
783 const SfxStringItem* pRefererItem = rReq.GetArg<SfxStringItem>(SID_REFERER);
784 if ( pRefererItem )
785 aReferer = pRefererItem->GetValue();
786
787 const SfxStringItem* pFileFlagsItem = rReq.GetArg<SfxStringItem>(SID_OPTIONS);
788 if ( pFileFlagsItem )
789 {
790 const OUString aFileFlags = pFileFlagsItem->GetValue().toAsciiUpperCase();
791 if ( aFileFlags.indexOf('T') >= 0 )
792 {
793 rReq.RemoveItem( SID_TEMPLATE );
794 rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, true ) );
795 }
796
797 if ( aFileFlags.indexOf('H') >= 0 )
798 {
799 rReq.RemoveItem( SID_HIDDEN );
800 rReq.AppendItem( SfxBoolItem( SID_HIDDEN, true ) );
801 }
802
803 if ( aFileFlags.indexOf('R') >= 0 )
804 {
805 rReq.RemoveItem( SID_DOC_READONLY );
806 rReq.AppendItem( SfxBoolItem( SID_DOC_READONLY, true ) );
807 }
808
809 if ( aFileFlags.indexOf('B') >= 0 )
810 {
811 rReq.RemoveItem( SID_PREVIEW );
812 rReq.AppendItem( SfxBoolItem( SID_PREVIEW, true ) );
813 }
814
815 rReq.RemoveItem( SID_OPTIONS );
816 }
817
818 // Mark without URL cannot be handled by hyperlink code
819 if ( bHyperlinkUsed && !aFileName.isEmpty() && aFileName[0] != '#' )
820 {
821 uno::Reference<document::XTypeDetection> xTypeDetection(
822 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), UNO_QUERY);
823
824 if ( xTypeDetection.is() )
825 {
826 URL aURL;
827
828 aURL.Complete = aFileName;
829 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
830 xTrans->parseStrict( aURL );
831
832 INetProtocol aINetProtocol = INetURLObject( aURL.Complete ).GetProtocol();
833 auto eMode = officecfg::Office::Security::Hyperlinks::Open::get();
834
835 if ( eMode == SvtExtendedSecurityOptions::OPEN_NEVER && aINetProtocol != INetProtocol::VndSunStarHelp )
836 {
837 SolarMutexGuard aGuard;
838 weld::Window *pWindow = SfxGetpApp()->GetTopWindow();
839
840 std::unique_ptr<weld::MessageDialog> xSecurityWarningBox(Application::CreateMessageDialog(pWindow,
841 VclMessageType::Warning, VclButtonsType::Ok, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS)));
842 xSecurityWarningBox->set_title(SfxResId(RID_SECURITY_WARNING_TITLE));
843 xSecurityWarningBox->run();
844 return;
845 }
846
847 const OUString aTypeName { xTypeDetection->queryTypeByURL( aURL.Main ) };
848 SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher();
849 std::shared_ptr<const SfxFilter> pFilter = rMatcher.GetFilter4EA( aTypeName );
850 if (!pFilter || !lcl_isFilterNativelySupported(*pFilter))
851 {
852 // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS
853 if ( aINetProtocol == INetProtocol::Mailto )
854 {
855 // don't dispatch mailto hyperlink to desktop dispatcher
856 rReq.RemoveItem( SID_TARGETNAME );
857 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_self" ) );
858 }
859 else if ( aINetProtocol == INetProtocol::Ftp ||
860 aINetProtocol == INetProtocol::Http ||
861 aINetProtocol == INetProtocol::Https )
862 {
863 sfx2::openUriExternally(aURL.Complete, true);
864 return;
865 }
866 else
867 {
868 // check for "internal" protocols that should not be forwarded to the system
869 // add special protocols that always should be treated as internal
870 std::vector < OUString > aProtocols { "private:*", "vnd.sun.star.*" };
871
872 // get registered protocol handlers from configuration
873 Reference < XNameAccess > xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get());
874 const Sequence < OUString > aNames = xAccess->getElementNames();
875 for ( const auto& rName : aNames )
876 {
877 Reference < XPropertySet > xSet;
878 Any aRet = xAccess->getByName( rName );
879 aRet >>= xSet;
880 if ( xSet.is() )
881 {
882 // copy protocols
883 aRet = xSet->getPropertyValue("Protocols");
884 Sequence < OUString > aTmp;
885 aRet >>= aTmp;
886
887 aProtocols.insert(aProtocols.end(),aTmp.begin(),aTmp.end());
888 }
889 }
890
891 bool bFound = false;
892 for (const OUString & rProtocol : aProtocols)
893 {
894 WildCard aPattern(rProtocol);
895 if ( aPattern.Matches( aURL.Complete ) )
896 {
897 bFound = true;
898 break;
899 }
900 }
901
902 if ( !bFound )
903 {
904 bool bLoadInternal = false;
905 try
906 {
907 sfx2::openUriExternally(
908 aURL.Complete, pFilter == nullptr);
909 }
910 catch ( css::system::SystemShellExecuteException& )
911 {
912 rReq.RemoveItem( SID_TARGETNAME );
913 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
914 bLoadInternal = true;
915 }
916 if ( !bLoadInternal )
917 return;
918 }
919 }
920 }
921 else
922 {
923 // hyperlink document must be loaded into a new frame
924 rReq.RemoveItem( SID_TARGETNAME );
925 rReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
926 }
927 }
928 }
929
930 if (!SvtSecurityOptions().isSecureMacroUri(aFileName, aReferer))
931 {
932 SfxErrorContext aCtx( ERRCTX_SFX_OPENDOC, aFileName );
933 ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED );
934 return;
935 }
936
937 SfxFrame* pTargetFrame = nullptr;
938 Reference< XFrame > xTargetFrame;
939
940 const SfxFrameItem* pFrameItem = rReq.GetArg<SfxFrameItem>(SID_DOCFRAME);
941 if ( pFrameItem )
942 pTargetFrame = pFrameItem->GetFrame();
943
944 if ( !pTargetFrame )
945 {
946 const SfxUnoFrameItem* pUnoFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME);
947 if ( pUnoFrameItem )
948 xTargetFrame = pUnoFrameItem->GetFrame();
949 }
950
951 if ( !pTargetFrame && !xTargetFrame.is() && SfxViewFrame::Current() )
952 pTargetFrame = &SfxViewFrame::Current()->GetFrame();
953
954 // check if caller has set a callback
955 std::unique_ptr<SfxLinkItem> pLinkItem;
956
957 // remove from Itemset, because it confuses the parameter transformation
958 if (auto pParamLinkItem = rReq.GetArg<SfxLinkItem>(SID_DONELINK))
959 pLinkItem.reset(pParamLinkItem->Clone());
960
961 rReq.RemoveItem( SID_DONELINK );
962
963 // check if the view must be hidden
964 bool bHidden = false;
965 const SfxBoolItem* pHidItem = rReq.GetArg<SfxBoolItem>(SID_HIDDEN);
966 if ( pHidItem )
967 bHidden = pHidItem->GetValue();
968
969 // This request is a UI call. We have to set the right values inside the MediaDescriptor
970 // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate.
971 // But we have to look for already existing values or for real hidden requests.
972 const SfxBoolItem* pPreviewItem = rReq.GetArg<SfxBoolItem>(SID_PREVIEW);
973 if (!bHidden && ( !pPreviewItem || !pPreviewItem->GetValue() ) )
974 {
975 const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
976 const SfxUInt16Item* pMacroExecItem = rReq.GetArg<SfxUInt16Item>(SID_MACROEXECMODE);
977 const SfxUInt16Item* pDocTemplateItem = rReq.GetArg<SfxUInt16Item>(SID_UPDATEDOCMODE);
978
979 if (!pInteractionItem)
980 {
981 Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr );
982 rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHdl)) );
983 }
984 if (!pMacroExecItem)
985 rReq.AppendItem( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) );
986 if (!pDocTemplateItem)
987 rReq.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) );
988 }
989
990 // extract target name
991 OUString aTarget;
992 const SfxStringItem* pTargetItem = rReq.GetArg<SfxStringItem>(SID_TARGETNAME);
993 if ( pTargetItem )
994 aTarget = pTargetItem->GetValue();
995 else
996 {
997 const SfxBoolItem* pNewViewItem = rReq.GetArg<SfxBoolItem>(SID_OPEN_NEW_VIEW);
998 if ( pNewViewItem && pNewViewItem->GetValue() )
999 aTarget = "_blank" ;
1000 }
1001
1002 if ( bHidden )
1003 {
1004 aTarget = "_blank";
1005 DBG_ASSERT( rReq.IsSynchronCall() || pLinkItem, "Hidden load process must be done synchronously!" );
1006 }
1007
1008 Reference < XController > xController;
1009 // if a frame is given, it must be used for the starting point of the targeting mechanism
1010 // this code is also used if asynchronous loading is possible, because loadComponent always is synchron
1011 if ( !xTargetFrame.is() )
1012 {
1013 if ( pTargetFrame )
1014 {
1015 xTargetFrame = pTargetFrame->GetFrameInterface();
1016 }
1017 else
1018 {
1019 xTargetFrame = Desktop::create(::comphelper::getProcessComponentContext());
1020 }
1021 }
1022
1023 // make URL ready
1024 const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
1025 aFileName = pURLItem->GetValue();
1026 if( aFileName.startsWith("#") ) // Mark without URL
1027 {
1028 SfxViewFrame *pView = pTargetFrame ? pTargetFrame->GetCurrentViewFrame() : nullptr;
1029 if ( !pView )
1030 pView = SfxViewFrame::Current();
1031 pView->GetViewShell()->JumpToMark( aFileName.copy(1) );
1032 rReq.SetReturnValue( SfxViewFrameItem( pView ) );
1033 return;
1034 }
1035
1036 // convert items to properties for framework API calls
1037 Sequence < PropertyValue > aArgs;
1038 TransformItems( SID_OPENDOC, *rReq.GetArgs(), aArgs );
1039 // Any Referer (that was relevant in the above call to
1040 // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming
1041 // this "open" request is initiated directly by the user:
1042 auto pArg = std::find_if(aArgs.begin(), aArgs.end(),
1043 [](const PropertyValue& rArg) { return rArg.Name == "Referer"; });
1044 if (pArg != aArgs.end())
1045 {
1046 auto nIndex = static_cast<sal_Int32>(std::distance(aArgs.begin(), pArg));
1047 comphelper::removeElementAt(aArgs, nIndex);
1048 }
1049
1050 // TODO/LATER: either remove LinkItem or create an asynchronous process for it
1051 if( bHidden || pLinkItem || rReq.IsSynchronCall() )
1052 {
1053 // if loading must be done synchron, we must wait for completion to get a return value
1054 // find frame by myself; I must know the exact frame to get the controller for the return value from it
1055 Reference < XComponent > xComp;
1056
1057 try
1058 {
1059 xComp = ::comphelper::SynchronousDispatch::dispatch( xTargetFrame, aFileName, aTarget, aArgs );
1060 }
1061 catch(const RuntimeException&)
1062 {
1063 throw;
1064 }
1065 catch(const css::uno::Exception&)
1066 {
1067 }
1068
1069 Reference < XModel > xModel( xComp, UNO_QUERY );
1070 if ( xModel.is() )
1071 xController = xModel->getCurrentController();
1072 else
1073 xController.set( xComp, UNO_QUERY );
1074
1075 }
1076 else
1077 {
1078 URL aURL;
1079 aURL.Complete = aFileName;
1080 Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
1081 xTrans->parseStrict( aURL );
1082
1083 Reference < XDispatchProvider > xProv( xTargetFrame, UNO_QUERY );
1084 Reference < XDispatch > xDisp = xProv.is() ? xProv->queryDispatch( aURL, aTarget, FrameSearchFlag::ALL ) : Reference < XDispatch >();
1085 if ( xDisp.is() )
1086 xDisp->dispatch( aURL, aArgs );
1087 }
1088
1089 if ( xController.is() )
1090 {
1091 // try to find the SfxFrame for the controller
1092 SfxFrame* pCntrFrame = nullptr;
1093 for ( SfxViewShell* pShell = SfxViewShell::GetFirst( false ); pShell; pShell = SfxViewShell::GetNext( *pShell, false ) )
1094 {
1095 if ( pShell->GetController() == xController )
1096 {
1097 pCntrFrame = &pShell->GetViewFrame()->GetFrame();
1098 break;
1099 }
1100 }
1101
1102 if ( pCntrFrame )
1103 {
1104 SfxObjectShell* pSh = pCntrFrame->GetCurrentDocument();
1105 DBG_ASSERT( pSh, "Controller without ObjectShell ?!" );
1106
1107 rReq.SetReturnValue( SfxViewFrameItem( pCntrFrame->GetCurrentViewFrame() ) );
1108
1109 if ( bHidden )
1110 pSh->RestoreNoDelete();
1111 }
1112 }
1113
1114 if (pLinkItem)
1115 {
1116 const SfxPoolItem* pRetValue = rReq.GetReturnValue();
1117 if (pRetValue)
1118 {
1119 pLinkItem->GetValue().Call(pRetValue);
1120 }
1121 }
1122 }
1123
OpenRemoteExec_Impl(SfxRequest & rReq)1124 void SfxApplication::OpenRemoteExec_Impl( SfxRequest& rReq )
1125 {
1126 rReq.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG, true ) );
1127 GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() );
1128 }
1129
SignPDFExec_Impl(SfxRequest & rReq)1130 void SfxApplication::SignPDFExec_Impl(SfxRequest& rReq)
1131 {
1132 rReq.AppendItem(SfxBoolItem(SID_SIGNPDF, true));
1133 GetDispatcher_Impl()->Execute(SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs());
1134 }
1135
1136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1137