/src/libreoffice/sfx2/source/appl/appopen.cxx
Line | Count | Source (jump to first uncovered line) |
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/SetFlagContextHelper.hxx> |
49 | | #include <comphelper/storagehelper.hxx> |
50 | | #include <comphelper/string.hxx> |
51 | | #include <comphelper/synchronousdispatch.hxx> |
52 | | |
53 | | #include <svl/intitem.hxx> |
54 | | #include <svl/stritem.hxx> |
55 | | #include <svl/eitem.hxx> |
56 | | #include <sfx2/doctempl.hxx> |
57 | | #include <svtools/sfxecode.hxx> |
58 | | #include <preventduplicateinteraction.hxx> |
59 | | #include <svtools/ehdl.hxx> |
60 | | #include <unotools/pathoptions.hxx> |
61 | | #include <unotools/securityoptions.hxx> |
62 | | #include <unotools/moduleoptions.hxx> |
63 | | #include <unotools/extendedsecurityoptions.hxx> |
64 | | #include <comphelper/docpasswordhelper.hxx> |
65 | | #include <vcl/svapp.hxx> |
66 | | #include <vcl/weld.hxx> |
67 | | |
68 | | #include <sfx2/app.hxx> |
69 | | #include <sfx2/bindings.hxx> |
70 | | #include <sfx2/dispatch.hxx> |
71 | | #include <sfx2/docfile.hxx> |
72 | | #include <sfx2/docfilt.hxx> |
73 | | #include <sfx2/fcontnr.hxx> |
74 | | #include <sfx2/objitem.hxx> |
75 | | #include <sfx2/objsh.hxx> |
76 | | #include <svl/slstitm.hxx> |
77 | | #include <appopen.hxx> |
78 | | #include <sfx2/request.hxx> |
79 | | #include <sfx2/sfxresid.hxx> |
80 | | #include <sfx2/viewsh.hxx> |
81 | | #include <sfx2/strings.hrc> |
82 | | #include <sfx2/viewfrm.hxx> |
83 | | #include <sfx2/sfxuno.hxx> |
84 | | #include <sfx2/objface.hxx> |
85 | | #include <sfx2/filedlghelper.hxx> |
86 | | #include <sfx2/templatedlg.hxx> |
87 | | #include <sfx2/sfxsids.hrc> |
88 | | #include <o3tl/string_view.hxx> |
89 | | #include <openuriexternally.hxx> |
90 | | |
91 | | #include <officecfg/Office/ProtocolHandler.hxx> |
92 | | #include <officecfg/Office/Security.hxx> |
93 | | |
94 | | using namespace ::com::sun::star; |
95 | | using namespace ::com::sun::star::beans; |
96 | | using namespace ::com::sun::star::frame; |
97 | | using namespace ::com::sun::star::lang; |
98 | | using namespace ::com::sun::star::uno; |
99 | | using namespace ::com::sun::star::util; |
100 | | using namespace ::com::sun::star::task; |
101 | | using namespace ::com::sun::star::container; |
102 | | using namespace ::cppu; |
103 | | using namespace ::sfx2; |
104 | | |
105 | | void SetTemplate_Impl( std::u16string_view rFileName, |
106 | | const OUString &rLongName, |
107 | | SfxObjectShell *pDoc) |
108 | 0 | { |
109 | | // write TemplateName to DocumentProperties of document |
110 | | // TemplateDate stays as default (=current date) |
111 | 0 | pDoc->ResetFromTemplate( rLongName, rFileName ); |
112 | 0 | } |
113 | | |
114 | | namespace { |
115 | | |
116 | | class SfxDocPasswordVerifier : public ::comphelper::IDocPasswordVerifier |
117 | | { |
118 | | public: |
119 | | explicit SfxDocPasswordVerifier(SfxMedium& rMedium) |
120 | 0 | : m_rMedium(rMedium) |
121 | 0 | , mxStorage(rMedium.GetStorage()) |
122 | 0 | { |
123 | 0 | } |
124 | | |
125 | | virtual ::comphelper::DocPasswordVerifierResult |
126 | | verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) override; |
127 | | virtual ::comphelper::DocPasswordVerifierResult |
128 | | verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) override; |
129 | | |
130 | | private: |
131 | | SfxMedium & m_rMedium; |
132 | | Reference< embed::XStorage > mxStorage; |
133 | | }; |
134 | | |
135 | | } |
136 | | |
137 | | ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) |
138 | 0 | { |
139 | 0 | o_rEncryptionData = ::comphelper::OStorageHelper::CreatePackageEncryptionData( rPassword ); |
140 | 0 | return verifyEncryptionData( o_rEncryptionData ); |
141 | 0 | } |
142 | | |
143 | | |
144 | | ::comphelper::DocPasswordVerifierResult SfxDocPasswordVerifier::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) |
145 | 0 | { |
146 | 0 | ::comphelper::DocPasswordVerifierResult eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword; |
147 | 0 | try |
148 | 0 | { |
149 | | // check the encryption data |
150 | | // if the data correct is the stream will be opened successfully |
151 | | // and immediately closed |
152 | 0 | ::comphelper::OStorageHelper::SetCommonStorageEncryptionData( mxStorage, rEncryptionData ); |
153 | | |
154 | | // for new ODF encryption, try to extract the encrypted inner package |
155 | | // (it will become the SfxObjectShell storage) |
156 | 0 | if (!m_rMedium.TryEncryptedInnerPackage(mxStorage)) |
157 | 0 | { // ... old ODF encryption: |
158 | 0 | mxStorage->openStreamElement( |
159 | 0 | u"content.xml"_ustr, |
160 | 0 | embed::ElementModes::READ | embed::ElementModes::NOCREATE ); |
161 | 0 | } |
162 | | |
163 | | // no exception -> success |
164 | 0 | eResult = ::comphelper::DocPasswordVerifierResult::OK; |
165 | 0 | } |
166 | 0 | catch( const packages::WrongPasswordException& ) |
167 | 0 | { |
168 | 0 | eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword; |
169 | 0 | } |
170 | 0 | catch( const uno::Exception& ) |
171 | 0 | { |
172 | | // unknown error, report it as wrong password |
173 | | // TODO/LATER: we need an additional way to report unknown problems in this case |
174 | 0 | eResult = ::comphelper::DocPasswordVerifierResult::WrongPassword; |
175 | 0 | } |
176 | 0 | return eResult; |
177 | 0 | } |
178 | | |
179 | | |
180 | | ErrCode CheckPasswd_Impl |
181 | | ( |
182 | | SfxObjectShell* pDoc, |
183 | | SfxMedium* pFile // the Medium and its Password should be obtained |
184 | | ) |
185 | | |
186 | | /* [Description] |
187 | | |
188 | | Ask for the password for a medium, only works if it concerns storage. |
189 | | If the password flag is set in the Document Info, then the password is |
190 | | requested through a user dialogue and the set at the Set of the medium. |
191 | | If the set does not exist the it is created. |
192 | | */ |
193 | 0 | { |
194 | 0 | ErrCode nRet = ERRCODE_NONE; |
195 | |
|
196 | 0 | if( !pFile->GetFilter() || pFile->IsStorage() ) |
197 | 0 | { |
198 | 0 | uno::Reference< embed::XStorage > xStorage = pFile->GetStorage(); |
199 | 0 | if( xStorage.is() ) |
200 | 0 | { |
201 | 0 | uno::Reference< beans::XPropertySet > xStorageProps( xStorage, uno::UNO_QUERY ); |
202 | 0 | if ( xStorageProps.is() ) |
203 | 0 | { |
204 | 0 | bool bIsEncrypted = false; |
205 | 0 | uno::Sequence< uno::Sequence< beans::NamedValue > > aGpgProperties; |
206 | 0 | try { |
207 | 0 | xStorageProps->getPropertyValue(u"HasEncryptedEntries"_ustr) |
208 | 0 | >>= bIsEncrypted; |
209 | 0 | xStorageProps->getPropertyValue(u"EncryptionGpGProperties"_ustr) |
210 | 0 | >>= aGpgProperties; |
211 | 0 | } catch( uno::Exception& ) |
212 | 0 | { |
213 | | // TODO/LATER: |
214 | | // the storage either has no encrypted elements or it's just |
215 | | // does not allow to detect it, probably it should be implemented later |
216 | 0 | } |
217 | |
|
218 | 0 | if ( bIsEncrypted ) |
219 | 0 | { |
220 | 0 | css::uno::Reference<css::awt::XWindow> xWin(pDoc ? pDoc->GetDialogParent(pFile) : nullptr); |
221 | 0 | if (xWin) |
222 | 0 | xWin->setVisible(true); |
223 | |
|
224 | 0 | nRet = ERRCODE_SFX_CANTGETPASSWD; |
225 | |
|
226 | 0 | SfxItemSet& rSet = pFile->GetItemSet(); |
227 | 0 | Reference< css::task::XInteractionHandler > xInteractionHandler = pFile->GetInteractionHandler(); |
228 | 0 | if( xInteractionHandler.is() ) |
229 | 0 | { |
230 | | // use the comphelper password helper to request a password |
231 | 0 | OUString aPassword; |
232 | 0 | const SfxStringItem* pPasswordItem = rSet.GetItem(SID_PASSWORD, false); |
233 | 0 | if ( pPasswordItem ) |
234 | 0 | aPassword = pPasswordItem->GetValue(); |
235 | |
|
236 | 0 | uno::Sequence< beans::NamedValue > aEncryptionData; |
237 | 0 | const SfxUnoAnyItem* pEncryptionDataItem = rSet.GetItem(SID_ENCRYPTIONDATA, false); |
238 | 0 | if ( pEncryptionDataItem ) |
239 | 0 | pEncryptionDataItem->GetValue() >>= aEncryptionData; |
240 | | |
241 | | // try if one of the public key entries is |
242 | | // decryptable, then extract session key |
243 | | // from it |
244 | 0 | if ( !aEncryptionData.hasElements() && aGpgProperties.hasElements() ) |
245 | 0 | aEncryptionData = ::comphelper::DocPasswordHelper::decryptGpgSession(aGpgProperties); |
246 | | |
247 | | // tdf#93389: if recovering a document, encryption data should contain |
248 | | // entries for the real filter, not only for recovery ODF, to keep it |
249 | | // encrypted. Pass this in encryption data. |
250 | | // TODO: pass here the real filter (from AutoRecovery::implts_openDocs) |
251 | | // to marshal this to requestAndVerifyDocPassword |
252 | 0 | if (rSet.GetItemState(SID_DOC_SALVAGE, false) == SfxItemState::SET) |
253 | 0 | { |
254 | 0 | aEncryptionData = comphelper::concatSequences( |
255 | 0 | aEncryptionData, std::initializer_list<beans::NamedValue>{ |
256 | 0 | { u"ForSalvage"_ustr, css::uno::Any(true) } }); |
257 | 0 | } |
258 | |
|
259 | 0 | SfxDocPasswordVerifier aVerifier(*pFile); |
260 | 0 | aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword( |
261 | 0 | aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard ); |
262 | |
|
263 | 0 | rSet.ClearItem( SID_PASSWORD ); |
264 | 0 | rSet.ClearItem( SID_ENCRYPTIONDATA ); |
265 | |
|
266 | 0 | if ( aEncryptionData.hasElements() ) |
267 | 0 | { |
268 | 0 | rSet.Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ) ); |
269 | |
|
270 | 0 | try |
271 | 0 | { |
272 | | // update the version list of the medium using the new password |
273 | 0 | pFile->GetVersionList(); |
274 | 0 | } |
275 | 0 | catch( uno::Exception& ) |
276 | 0 | { |
277 | | // TODO/LATER: set the error code |
278 | 0 | } |
279 | |
|
280 | 0 | nRet = ERRCODE_NONE; |
281 | 0 | } |
282 | 0 | else |
283 | 0 | nRet = ERRCODE_IO_ABORT; |
284 | 0 | } |
285 | 0 | } |
286 | 0 | } |
287 | 0 | else |
288 | 0 | { |
289 | 0 | OSL_FAIL( "A storage must implement XPropertySet interface!" ); |
290 | 0 | nRet = ERRCODE_SFX_CANTGETPASSWD; |
291 | 0 | } |
292 | 0 | } |
293 | 0 | } |
294 | |
|
295 | 0 | return nRet; |
296 | 0 | } |
297 | | |
298 | | |
299 | | ErrCodeMsg SfxApplication::LoadTemplate( SfxObjectShellLock& xDoc, const OUString &rFileName, std::unique_ptr<SfxItemSet> pSet ) |
300 | 0 | { |
301 | 0 | std::shared_ptr<const SfxFilter> pFilter; |
302 | 0 | SfxMedium aMedium( rFileName, ( StreamMode::READ | StreamMode::SHARE_DENYNONE ) ); |
303 | |
|
304 | 0 | if ( !aMedium.GetStorage( false ).is() ) |
305 | 0 | aMedium.GetInStream(); |
306 | |
|
307 | 0 | if ( aMedium.GetErrorIgnoreWarning() ) |
308 | 0 | { |
309 | 0 | return aMedium.GetErrorCode(); |
310 | 0 | } |
311 | | |
312 | 0 | aMedium.UseInteractionHandler( true ); |
313 | 0 | ErrCode nErr = GetFilterMatcher().GuessFilter( aMedium, pFilter, SfxFilterFlags::TEMPLATE, SfxFilterFlags::NONE ); |
314 | 0 | if ( ERRCODE_NONE != nErr) |
315 | 0 | { |
316 | 0 | return ERRCODE_SFX_NOTATEMPLATE; |
317 | 0 | } |
318 | | |
319 | 0 | if( !pFilter || !pFilter->IsAllowedAsTemplate() ) |
320 | 0 | { |
321 | 0 | return ERRCODE_SFX_NOTATEMPLATE; |
322 | 0 | } |
323 | | |
324 | 0 | if ( pFilter->GetFilterFlags() & SfxFilterFlags::STARONEFILTER ) |
325 | 0 | { |
326 | 0 | DBG_ASSERT( !xDoc.Is(), "Sorry, not implemented!" ); |
327 | 0 | SfxStringItem aName( SID_FILE_NAME, rFileName ); |
328 | 0 | SfxStringItem aReferer( SID_REFERER, u"private:user"_ustr ); |
329 | 0 | SfxStringItem aFlags( SID_OPTIONS, u"T"_ustr ); |
330 | 0 | SfxBoolItem aHidden( SID_HIDDEN, true ); |
331 | 0 | const SfxPoolItemHolder aRet(GetDispatcher_Impl()->ExecuteList( |
332 | 0 | SID_OPENDOC, SfxCallMode::SYNCHRON, |
333 | 0 | { &aName, &aHidden, &aReferer, &aFlags } )); |
334 | 0 | const SfxObjectItem* pObj(dynamic_cast<const SfxObjectItem*>(aRet.getItem())); |
335 | 0 | if ( pObj ) |
336 | 0 | xDoc = dynamic_cast<SfxObjectShell*>( pObj->GetShell() ); |
337 | 0 | else |
338 | 0 | { |
339 | 0 | const SfxViewFrameItem* pView(dynamic_cast<const SfxViewFrameItem*>(aRet.getItem())); |
340 | 0 | if ( pView ) |
341 | 0 | { |
342 | 0 | SfxViewFrame *pFrame = pView->GetFrame(); |
343 | 0 | if ( pFrame ) |
344 | 0 | xDoc = pFrame->GetObjectShell(); |
345 | 0 | } |
346 | 0 | } |
347 | |
|
348 | 0 | if ( !xDoc.Is() ) |
349 | 0 | return ERRCODE_SFX_DOLOADFAILED; |
350 | 0 | } |
351 | 0 | else |
352 | 0 | { |
353 | 0 | if ( !xDoc.Is() ) |
354 | 0 | xDoc = SfxObjectShell::CreateObject( pFilter->GetServiceName() ); |
355 | | |
356 | | //pMedium takes ownership of pSet |
357 | 0 | SfxMedium *pMedium = new SfxMedium(rFileName, StreamMode::STD_READ, std::move(pFilter), std::move(pSet)); |
358 | 0 | if(!xDoc->DoLoad(pMedium)) |
359 | 0 | { |
360 | 0 | ErrCodeMsg nErrCode = xDoc->GetErrorCode(); |
361 | 0 | xDoc->DoClose(); |
362 | 0 | xDoc.Clear(); |
363 | 0 | return nErrCode; |
364 | 0 | } |
365 | 0 | } |
366 | | |
367 | 0 | try |
368 | 0 | { |
369 | | // TODO: introduce error handling |
370 | |
|
371 | 0 | uno::Reference< embed::XStorage > xTempStorage = ::comphelper::OStorageHelper::GetTemporaryStorage(); |
372 | 0 | if( !xTempStorage.is() ) |
373 | 0 | throw uno::RuntimeException(); |
374 | | |
375 | 0 | xDoc->GetStorage()->copyToStorage( xTempStorage ); |
376 | |
|
377 | 0 | if ( !xDoc->DoSaveCompleted( new SfxMedium( xTempStorage, OUString() ) ) ) |
378 | 0 | throw uno::RuntimeException(); |
379 | 0 | } |
380 | 0 | catch( uno::Exception& ) |
381 | 0 | { |
382 | 0 | xDoc->DoClose(); |
383 | 0 | xDoc.Clear(); |
384 | | |
385 | | // TODO: transfer correct error outside |
386 | 0 | return ERRCODE_SFX_GENERAL; |
387 | 0 | } |
388 | | |
389 | 0 | SetTemplate_Impl( rFileName, OUString(), xDoc ); |
390 | |
|
391 | 0 | xDoc->SetNoName(); |
392 | 0 | xDoc->InvalidateName(); |
393 | 0 | xDoc->SetModified(false); |
394 | 0 | xDoc->ResetError(); |
395 | |
|
396 | 0 | css::uno::Reference< css::frame::XModel > xModel = xDoc->GetModel(); |
397 | 0 | if ( xModel.is() ) |
398 | 0 | { |
399 | 0 | std::unique_ptr<SfxItemSet> pNew = xDoc->GetMedium()->GetItemSet().Clone(); |
400 | 0 | pNew->ClearItem( SID_PROGRESS_STATUSBAR_CONTROL ); |
401 | 0 | pNew->ClearItem( SID_FILTER_NAME ); |
402 | 0 | css::uno::Sequence< css::beans::PropertyValue > aArgs; |
403 | 0 | TransformItems( SID_OPENDOC, *pNew, aArgs ); |
404 | 0 | sal_Int32 nLength = aArgs.getLength(); |
405 | 0 | aArgs.realloc( nLength + 1 ); |
406 | 0 | auto pArgs = aArgs.getArray(); |
407 | 0 | pArgs[nLength].Name = "Title"; |
408 | 0 | pArgs[nLength].Value <<= xDoc->GetTitle( SFX_TITLE_DETECT ); |
409 | 0 | xModel->attachResource( OUString(), aArgs ); |
410 | 0 | } |
411 | |
|
412 | 0 | return xDoc->GetErrorCode(); |
413 | 0 | } |
414 | | |
415 | | |
416 | | void SfxApplication::NewDocDirectExec_Impl( SfxRequest& rReq ) |
417 | 0 | { |
418 | 0 | const SfxStringItem* pFactoryItem = rReq.GetArg<SfxStringItem>(SID_NEWDOCDIRECT); |
419 | 0 | OUString aFactName; |
420 | 0 | if ( pFactoryItem ) |
421 | 0 | aFactName = pFactoryItem->GetValue(); |
422 | 0 | else |
423 | 0 | aFactName = SvtModuleOptions().GetDefaultModuleName(); |
424 | |
|
425 | 0 | SfxRequest aReq( SID_OPENDOC, SfxCallMode::SYNCHRON, GetPool() ); |
426 | 0 | aReq.AppendItem( SfxStringItem( SID_FILE_NAME, "private:factory/" + aFactName ) ); |
427 | 0 | aReq.AppendItem( SfxFrameItem( SID_DOCFRAME, GetFrame() ) ); |
428 | 0 | aReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_default"_ustr ) ); |
429 | | |
430 | | // TODO/LATER: Should the other arguments be transferred as well? |
431 | 0 | const SfxStringItem* pDefaultPathItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILEPATH); |
432 | 0 | if ( pDefaultPathItem ) |
433 | 0 | aReq.AppendItem( *pDefaultPathItem ); |
434 | 0 | const SfxStringItem* pDefaultNameItem = rReq.GetArg<SfxStringItem>(SID_DEFAULTFILENAME); |
435 | 0 | if ( pDefaultNameItem ) |
436 | 0 | aReq.AppendItem( *pDefaultNameItem ); |
437 | |
|
438 | 0 | SfxGetpApp()->ExecuteSlot( aReq ); |
439 | 0 | const SfxViewFrameItem* pItem(dynamic_cast<const SfxViewFrameItem*>(aReq.GetReturnValue().getItem())); |
440 | 0 | if (nullptr != pItem) |
441 | 0 | rReq.SetReturnValue(SfxFrameItem(0, pItem->GetFrame())); |
442 | 0 | } |
443 | | |
444 | | void SfxApplication::NewDocDirectState_Impl( SfxItemSet &rSet ) |
445 | 0 | { |
446 | 0 | rSet.Put(SfxStringItem(SID_NEWDOCDIRECT, "private:factory/" + SvtModuleOptions().GetDefaultModuleName())); |
447 | 0 | } |
448 | | |
449 | | void SfxApplication::NewDocExec_Impl( SfxRequest& rReq ) |
450 | 0 | { |
451 | | // No Parameter from BASIC only Factory given? |
452 | 0 | const SfxStringItem* pTemplNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_NAME); |
453 | 0 | const SfxStringItem* pTemplFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); |
454 | 0 | const SfxStringItem* pTemplRegionNameItem = rReq.GetArg<SfxStringItem>(SID_TEMPLATE_REGIONNAME); |
455 | |
|
456 | 0 | SfxObjectShellLock xDoc; |
457 | |
|
458 | 0 | OUString aTemplateRegion, aTemplateName, aTemplateFileName; |
459 | 0 | bool bDirect = false; // through FileName instead of Region/Template |
460 | 0 | SfxErrorContext aEc(ERRCTX_SFX_NEWDOC); |
461 | 0 | if ( !pTemplNameItem && !pTemplFileNameItem ) |
462 | 0 | { |
463 | 0 | bool bNewWin = false; |
464 | 0 | weld::Window* pTopWin = GetTopWindow(); |
465 | |
|
466 | 0 | SfxObjectShell* pCurrentShell = SfxObjectShell::Current(); |
467 | 0 | Reference<XModel> xModel; |
468 | 0 | if(pCurrentShell) |
469 | 0 | xModel = pCurrentShell->GetModel(); |
470 | |
|
471 | 0 | SfxTemplateManagerDlg aTemplDlg(rReq.GetFrameWeld()); |
472 | |
|
473 | 0 | if (xModel.is()) |
474 | 0 | aTemplDlg.setDocumentModel(xModel); |
475 | |
|
476 | 0 | int nRet = aTemplDlg.run(); |
477 | 0 | if ( nRet == RET_OK ) |
478 | 0 | { |
479 | 0 | rReq.Done(); |
480 | 0 | if ( pTopWin != GetTopWindow() ) |
481 | 0 | { |
482 | | // the dialogue opens a document -> a new TopWindow appears |
483 | 0 | pTopWin = GetTopWindow(); |
484 | 0 | bNewWin = true; |
485 | 0 | } |
486 | 0 | } |
487 | |
|
488 | 0 | if (bNewWin && pTopWin) |
489 | 0 | { |
490 | | // after the destruction of the dialogue its parent comes to top, |
491 | | // but we want that the new document is on top |
492 | 0 | pTopWin->present(); |
493 | 0 | } |
494 | |
|
495 | 0 | return; |
496 | 0 | } |
497 | 0 | else |
498 | 0 | { |
499 | | // Template-Name |
500 | 0 | if ( pTemplNameItem ) |
501 | 0 | aTemplateName = pTemplNameItem->GetValue(); |
502 | | |
503 | | // Template-Region |
504 | 0 | if ( pTemplRegionNameItem ) |
505 | 0 | aTemplateRegion = pTemplRegionNameItem->GetValue(); |
506 | | |
507 | | // Template-File-Name |
508 | 0 | if ( pTemplFileNameItem ) |
509 | 0 | { |
510 | 0 | aTemplateFileName = pTemplFileNameItem->GetValue(); |
511 | 0 | bDirect = true; |
512 | 0 | } |
513 | 0 | } |
514 | | |
515 | 0 | ErrCode lErr = ERRCODE_NONE; |
516 | 0 | if ( !bDirect ) |
517 | 0 | { |
518 | 0 | SfxDocumentTemplates aTmpFac; |
519 | 0 | if( aTemplateFileName.isEmpty() ) |
520 | 0 | aTmpFac.GetFull( aTemplateRegion, aTemplateName, aTemplateFileName ); |
521 | |
|
522 | 0 | if( aTemplateFileName.isEmpty() ) |
523 | 0 | lErr = ERRCODE_SFX_TEMPLATENOTFOUND; |
524 | 0 | } |
525 | |
|
526 | 0 | INetURLObject aObj( aTemplateFileName ); |
527 | 0 | SfxErrorContext aEC( ERRCTX_SFX_LOADTEMPLATE, aObj.PathToFileName() ); |
528 | |
|
529 | 0 | if ( lErr != ERRCODE_NONE ) |
530 | 0 | { |
531 | 0 | ErrCode lFatalErr = lErr.IgnoreWarning(); |
532 | 0 | if ( lFatalErr ) |
533 | 0 | ErrorHandler::HandleError(lErr); |
534 | 0 | } |
535 | 0 | else |
536 | 0 | { |
537 | 0 | SfxCallMode eMode = SfxCallMode::SYNCHRON; |
538 | 0 | SfxPoolItemHolder aResult; |
539 | 0 | SfxStringItem aReferer( SID_REFERER, u"private:user"_ustr ); |
540 | 0 | SfxStringItem aTarget( SID_TARGETNAME, u"_default"_ustr ); |
541 | 0 | if ( !aTemplateFileName.isEmpty() ) |
542 | 0 | { |
543 | 0 | DBG_ASSERT( aObj.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" ); |
544 | |
|
545 | 0 | SfxStringItem aName( SID_FILE_NAME, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); |
546 | 0 | SfxStringItem aTemplName( SID_TEMPLATE_NAME, aTemplateName ); |
547 | 0 | SfxStringItem aTemplRegionName( SID_TEMPLATE_REGIONNAME, aTemplateRegion ); |
548 | 0 | aResult = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode, |
549 | 0 | {&aName, &aTarget, &aReferer, &aTemplName, &aTemplRegionName}); |
550 | 0 | } |
551 | 0 | else |
552 | 0 | { |
553 | 0 | SfxStringItem aName( SID_FILE_NAME, u"private:factory"_ustr ); |
554 | 0 | aResult = GetDispatcher_Impl()->ExecuteList(SID_OPENDOC, eMode, |
555 | 0 | { &aName, &aTarget, &aReferer } ); |
556 | 0 | } |
557 | |
|
558 | 0 | if (aResult) |
559 | 0 | rReq.SetReturnValue( *aResult.getItem() ); |
560 | 0 | } |
561 | 0 | } |
562 | | |
563 | | |
564 | | namespace { |
565 | | |
566 | | /** |
567 | | * Check if a given filter type should open the hyperlinked document |
568 | | * natively. |
569 | | * |
570 | | * @param rFilter filter object |
571 | | */ |
572 | | bool lcl_isFilterNativelySupported(const SfxFilter& rFilter) |
573 | 0 | { |
574 | 0 | if (rFilter.IsOwnFormat()) |
575 | 0 | return true; |
576 | | |
577 | 0 | const OUString& aName = rFilter.GetFilterName(); |
578 | | // We can handle all Excel variants natively. |
579 | 0 | return aName.startsWith("MS Excel"); |
580 | 0 | } |
581 | | |
582 | | } |
583 | | |
584 | | void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq ) |
585 | 0 | { |
586 | 0 | OUString aDocService; |
587 | 0 | const SfxStringItem* pDocSrvItem = rReq.GetArg<SfxStringItem>(SID_DOC_SERVICE); |
588 | 0 | if (pDocSrvItem) |
589 | 0 | aDocService = pDocSrvItem->GetValue(); |
590 | |
|
591 | 0 | sal_uInt16 nSID = rReq.GetSlot(); |
592 | 0 | const SfxStringItem* pFileNameItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); |
593 | 0 | if ( pFileNameItem ) |
594 | 0 | { |
595 | 0 | OUString aCommand( pFileNameItem->GetValue() ); |
596 | 0 | const SfxSlot* pSlot = GetInterface()->GetSlot( aCommand ); |
597 | 0 | if ( pSlot ) |
598 | 0 | { |
599 | 0 | pFileNameItem = nullptr; |
600 | 0 | } |
601 | 0 | else |
602 | 0 | { |
603 | 0 | if ( aCommand.startsWith("slot:") ) |
604 | 0 | { |
605 | 0 | sal_uInt16 nSlotId = static_cast<sal_uInt16>(o3tl::toInt32(aCommand.subView(5))); |
606 | 0 | if ( nSlotId == SID_OPENDOC ) |
607 | 0 | pFileNameItem = nullptr; |
608 | 0 | } |
609 | 0 | } |
610 | 0 | } |
611 | |
|
612 | 0 | if ( !pFileNameItem ) |
613 | 0 | { |
614 | | // get FileName from dialog |
615 | 0 | css::uno::Sequence<OUString> aURLList; |
616 | 0 | OUString aFilter; |
617 | 0 | std::optional<SfxAllItemSet> pSet; |
618 | 0 | OUString aPath; |
619 | 0 | const SfxStringItem* pFolderNameItem = rReq.GetArg<SfxStringItem>(SID_PATH); |
620 | 0 | if ( pFolderNameItem ) |
621 | 0 | aPath = pFolderNameItem->GetValue(); |
622 | 0 | else if ( nSID == SID_OPENTEMPLATE ) |
623 | 0 | { |
624 | 0 | aPath = SvtPathOptions().GetTemplatePath(); |
625 | 0 | if (!aPath.isEmpty()) // if not empty then get last token |
626 | 0 | aPath = aPath.copy(aPath.lastIndexOf(';')+1); // lastIndexOf+copy works whether separator (';') is there or not |
627 | 0 | } |
628 | |
|
629 | 0 | sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG; |
630 | 0 | const SfxBoolItem* pSystemDialogItem = rReq.GetArg<SfxBoolItem>(SID_FILE_DIALOG); |
631 | 0 | if ( pSystemDialogItem ) |
632 | 0 | nDialog = pSystemDialogItem->GetValue() ? SFX2_IMPL_DIALOG_SYSTEM : SFX2_IMPL_DIALOG_OOO; |
633 | |
|
634 | 0 | const SfxBoolItem* pRemoteDialogItem = rReq.GetArg<SfxBoolItem>(SID_REMOTE_DIALOG); |
635 | 0 | if ( pRemoteDialogItem && pRemoteDialogItem->GetValue()) |
636 | 0 | nDialog = SFX2_IMPL_DIALOG_REMOTE; |
637 | |
|
638 | 0 | sal_Int16 nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION_FILTEROPTIONS; |
639 | 0 | FileDialogFlags eDialogFlags = FileDialogFlags::MultiSelection; |
640 | 0 | const SfxBoolItem* pSignPDFItem = rReq.GetArg<SfxBoolItem>(SID_SIGNPDF); |
641 | 0 | if (pSignPDFItem && pSignPDFItem->GetValue()) |
642 | 0 | { |
643 | 0 | eDialogFlags |= FileDialogFlags::SignPDF; |
644 | 0 | nDialogType = ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE; |
645 | 0 | } |
646 | |
|
647 | 0 | css::uno::Sequence< OUString > aDenyList; |
648 | |
|
649 | 0 | const SfxStringListItem* pDenyListItem = rReq.GetArg<SfxStringListItem>(SID_DENY_LIST); |
650 | 0 | if ( pDenyListItem ) |
651 | 0 | pDenyListItem->GetStringList( aDenyList ); |
652 | |
|
653 | 0 | std::optional<bool> bShowFilterDialog; |
654 | 0 | weld::Window* pTopWindow = GetTopWindow(); |
655 | 0 | ErrCode nErr = sfx2::FileOpenDialog_Impl(pTopWindow, |
656 | 0 | nDialogType, |
657 | 0 | eDialogFlags, aURLList, |
658 | 0 | aFilter, pSet, &aPath, nDialog, aDenyList, bShowFilterDialog); |
659 | |
|
660 | 0 | if ( nErr == ERRCODE_ABORT ) |
661 | 0 | { |
662 | 0 | return; |
663 | 0 | } |
664 | | |
665 | 0 | rReq.SetArgs( *pSet ); |
666 | 0 | if ( !aFilter.isEmpty() ) |
667 | 0 | rReq.AppendItem( SfxStringItem( SID_FILTER_NAME, aFilter ) ); |
668 | 0 | rReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_default"_ustr ) ); |
669 | 0 | rReq.AppendItem( SfxStringItem( SID_REFERER, u"private:user"_ustr ) ); |
670 | 0 | pSet.reset(); |
671 | |
|
672 | 0 | if (aURLList.hasElements()) |
673 | 0 | { |
674 | 0 | if ( nSID == SID_OPENTEMPLATE ) |
675 | 0 | 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 | 0 | rtl::Reference<sfx2::PreventDuplicateInteraction> pHandler = new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext()); |
682 | 0 | uno::Reference<task::XInteractionHandler> xWrappedHandler; |
683 | | |
684 | | // wrap existing handler or create new UUI handler |
685 | 0 | const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER); |
686 | 0 | if (pInteractionItem) |
687 | 0 | { |
688 | 0 | pInteractionItem->GetValue() >>= xWrappedHandler; |
689 | 0 | rReq.RemoveItem( SID_INTERACTIONHANDLER ); |
690 | 0 | } |
691 | 0 | if (xWrappedHandler.is()) |
692 | 0 | pHandler->setHandler(xWrappedHandler); |
693 | 0 | else |
694 | 0 | pHandler->useDefaultUUIHandler(); |
695 | 0 | rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::Any(uno::Reference<task::XInteractionHandler>(pHandler))) ); |
696 | | |
697 | | // define rules for this handler |
698 | 0 | css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get(); |
699 | 0 | ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule(aInteraction); |
700 | 0 | pHandler->addInteractionRule(aRule); |
701 | |
|
702 | 0 | if (!aDocService.isEmpty()) |
703 | 0 | { |
704 | 0 | rReq.RemoveItem(SID_DOC_SERVICE); |
705 | 0 | rReq.AppendItem(SfxStringItem(SID_DOC_SERVICE, aDocService)); |
706 | 0 | } |
707 | | |
708 | | // Passes the checkbox state of "Edit Filter Settings" to filter dialogs through multiple layers of code. |
709 | | // Since some layers use a published API and cannot be modified directly, we use a context layer instead. |
710 | | // This is a one-time flag and is not stored in any configuration. |
711 | | // For an example of how it's used, see ScFilterOptionsObj::execute. |
712 | 0 | std::optional<css::uno::ContextLayer> oLayer; |
713 | 0 | if (bShowFilterDialog.has_value()) |
714 | 0 | { |
715 | 0 | oLayer.emplace(comphelper::NewFlagContext(u"ShowFilterDialog"_ustr, |
716 | 0 | bShowFilterDialog.value())); |
717 | 0 | } |
718 | |
|
719 | 0 | for (auto const& url : aURLList) |
720 | 0 | { |
721 | 0 | rReq.RemoveItem( SID_FILE_NAME ); |
722 | 0 | rReq.AppendItem( SfxStringItem( SID_FILE_NAME, url ) ); |
723 | | |
724 | | // Run synchronous, so that not the next document is loaded |
725 | | // when rescheduling |
726 | | // TODO/LATER: use URLList argument and always remove one document after another, each step in asynchronous execution, until finished |
727 | | // but only if reschedule is a problem |
728 | 0 | GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() ); |
729 | | |
730 | | // check for special interaction "NO MORE DOCUMENTS ALLOWED" and |
731 | | // break loop then. Otherwise we risk showing the same interaction more than once. |
732 | 0 | if ( pHandler->getInteractionInfo(aInteraction, &aRule) ) |
733 | 0 | { |
734 | 0 | if (aRule.m_nCallCount > 0) |
735 | 0 | { |
736 | 0 | if (aRule.m_xRequest.is()) |
737 | 0 | { |
738 | 0 | css::task::ErrorCodeRequest aRequest; |
739 | 0 | if (aRule.m_xRequest->getRequest() >>= aRequest) |
740 | 0 | { |
741 | 0 | if (aRequest.ErrCode == sal_Int32(sal_uInt32(ERRCODE_SFX_NOMOREDOCUMENTSALLOWED))) |
742 | 0 | break; |
743 | 0 | } |
744 | 0 | } |
745 | 0 | } |
746 | 0 | } |
747 | 0 | } |
748 | |
|
749 | 0 | return; |
750 | 0 | } |
751 | 0 | } |
752 | | |
753 | 0 | bool bHyperlinkUsed = false; |
754 | |
|
755 | 0 | if ( SID_OPENURL == nSID ) |
756 | 0 | { |
757 | | // SID_OPENURL does the same as SID_OPENDOC! |
758 | 0 | rReq.SetSlot( SID_OPENDOC ); |
759 | 0 | } |
760 | 0 | else if ( nSID == SID_OPENTEMPLATE ) |
761 | 0 | { |
762 | 0 | rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, false ) ); |
763 | 0 | } |
764 | | // pass URL to OS by using ShellExecuter or open it internal |
765 | | // if it seems to be an own format. |
766 | | /* Attention! |
767 | | There exist two possibilities to open hyperlinks: |
768 | | a) using SID_OPENHYPERLINK (new) |
769 | | b) using SID_BROWSE (old) |
770 | | */ |
771 | 0 | else if ( nSID == SID_OPENHYPERLINK ) |
772 | 0 | { |
773 | 0 | rReq.SetSlot( SID_OPENDOC ); |
774 | 0 | bHyperlinkUsed = true; |
775 | 0 | } |
776 | | |
777 | | // no else here! It's optional ... |
778 | 0 | if (!bHyperlinkUsed) |
779 | 0 | { |
780 | 0 | const SfxBoolItem* pHyperLinkUsedItem = rReq.GetArg<SfxBoolItem>(SID_BROWSE); |
781 | 0 | if ( pHyperLinkUsedItem ) |
782 | 0 | bHyperlinkUsed = pHyperLinkUsedItem->GetValue(); |
783 | | // no "official" item, so remove it from ItemSet before using UNO-API |
784 | 0 | rReq.RemoveItem( SID_BROWSE ); |
785 | 0 | } |
786 | |
|
787 | 0 | const SfxStringItem* pFileName = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); |
788 | 0 | assert(pFileName && "SID_FILE_NAME is required"); |
789 | 0 | OUString aFileName = pFileName->GetValue(); |
790 | |
|
791 | 0 | OUString aReferer; |
792 | 0 | const SfxStringItem* pRefererItem = rReq.GetArg<SfxStringItem>(SID_REFERER); |
793 | 0 | if ( pRefererItem ) |
794 | 0 | aReferer = pRefererItem->GetValue(); |
795 | |
|
796 | 0 | const SfxStringItem* pFileFlagsItem = rReq.GetArg<SfxStringItem>(SID_OPTIONS); |
797 | 0 | if ( pFileFlagsItem ) |
798 | 0 | { |
799 | 0 | const OUString aFileFlags = pFileFlagsItem->GetValue().toAsciiUpperCase(); |
800 | 0 | if ( aFileFlags.indexOf('T') >= 0 ) |
801 | 0 | { |
802 | 0 | rReq.RemoveItem( SID_TEMPLATE ); |
803 | 0 | rReq.AppendItem( SfxBoolItem( SID_TEMPLATE, true ) ); |
804 | 0 | } |
805 | |
|
806 | 0 | if ( aFileFlags.indexOf('H') >= 0 ) |
807 | 0 | { |
808 | 0 | rReq.RemoveItem( SID_HIDDEN ); |
809 | 0 | rReq.AppendItem( SfxBoolItem( SID_HIDDEN, true ) ); |
810 | 0 | } |
811 | |
|
812 | 0 | if ( aFileFlags.indexOf('R') >= 0 ) |
813 | 0 | { |
814 | 0 | rReq.RemoveItem( SID_DOC_READONLY ); |
815 | 0 | rReq.AppendItem( SfxBoolItem( SID_DOC_READONLY, true ) ); |
816 | 0 | } |
817 | |
|
818 | 0 | if ( aFileFlags.indexOf('B') >= 0 ) |
819 | 0 | { |
820 | 0 | rReq.RemoveItem( SID_PREVIEW ); |
821 | 0 | rReq.AppendItem( SfxBoolItem( SID_PREVIEW, true ) ); |
822 | 0 | } |
823 | |
|
824 | 0 | rReq.RemoveItem( SID_OPTIONS ); |
825 | 0 | } |
826 | | |
827 | | // Mark without URL cannot be handled by hyperlink code |
828 | 0 | if ( bHyperlinkUsed && !aFileName.isEmpty() && aFileName[0] != '#' ) |
829 | 0 | { |
830 | 0 | uno::Reference<document::XTypeDetection> xTypeDetection( |
831 | 0 | comphelper::getProcessServiceFactory()->createInstance(u"com.sun.star.document.TypeDetection"_ustr), UNO_QUERY); |
832 | |
|
833 | 0 | if ( xTypeDetection.is() ) |
834 | 0 | { |
835 | 0 | URL aURL; |
836 | |
|
837 | 0 | aURL.Complete = aFileName; |
838 | 0 | Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) ); |
839 | 0 | xTrans->parseStrict( aURL ); |
840 | |
|
841 | 0 | INetProtocol aINetProtocol = INetURLObject( aURL.Complete ).GetProtocol(); |
842 | 0 | auto eMode = officecfg::Office::Security::Hyperlinks::Open::get(); |
843 | |
|
844 | 0 | if ( eMode == SvtExtendedSecurityOptions::OPEN_NEVER && aINetProtocol != INetProtocol::VndSunStarHelp ) |
845 | 0 | { |
846 | 0 | SolarMutexGuard aGuard; |
847 | 0 | weld::Window *pWindow = SfxGetpApp()->GetTopWindow(); |
848 | |
|
849 | 0 | std::unique_ptr<weld::MessageDialog> xSecurityWarningBox(Application::CreateMessageDialog(pWindow, |
850 | 0 | VclMessageType::Warning, VclButtonsType::Ok, SfxResId(STR_SECURITY_WARNING_NO_HYPERLINKS))); |
851 | 0 | xSecurityWarningBox->set_title(SfxResId(RID_SECURITY_WARNING_TITLE)); |
852 | 0 | xSecurityWarningBox->run(); |
853 | 0 | return; |
854 | 0 | } |
855 | | |
856 | 0 | std::shared_ptr<const SfxFilter> pFilter{}; |
857 | | |
858 | | // attempt loading native documents only if they are from a known protocol |
859 | | // it might be sensible to limit the set of protocols even further, but that |
860 | | // may cause regressions, needs further testing |
861 | | // see tdf#136427 for details |
862 | 0 | if (aINetProtocol != INetProtocol::NotValid) { |
863 | 0 | const OUString aTypeName { xTypeDetection->queryTypeByURL( aURL.Main ) }; |
864 | 0 | SfxFilterMatcher& rMatcher = SfxGetpApp()->GetFilterMatcher(); |
865 | 0 | pFilter = rMatcher.GetFilter4EA( aTypeName ); |
866 | 0 | } |
867 | |
|
868 | 0 | bool bStartPresentation = false; |
869 | 0 | if (pFilter) |
870 | 0 | { |
871 | 0 | const SfxUInt16Item* pSlide = rReq.GetArg<SfxUInt16Item>(SID_DOC_STARTPRESENTATION); |
872 | 0 | if (pSlide |
873 | 0 | && (pFilter->GetWildcard().Matches(u".pptx") |
874 | 0 | || pFilter->GetWildcard().Matches(u".ppt") |
875 | 0 | || pFilter->GetWildcard().Matches(u".ppsx") |
876 | 0 | || pFilter->GetWildcard().Matches(u".pps"))) |
877 | 0 | { |
878 | 0 | bStartPresentation = true; |
879 | 0 | } |
880 | 0 | } |
881 | |
|
882 | 0 | if (!pFilter || (!lcl_isFilterNativelySupported(*pFilter) && !bStartPresentation)) |
883 | 0 | { |
884 | | // hyperlink does not link to own type => special handling (http, ftp) browser and (other external protocols) OS |
885 | 0 | if ( aINetProtocol == INetProtocol::Mailto ) |
886 | 0 | { |
887 | | // don't dispatch mailto hyperlink to desktop dispatcher |
888 | 0 | rReq.RemoveItem( SID_TARGETNAME ); |
889 | 0 | rReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_self"_ustr ) ); |
890 | 0 | } |
891 | 0 | else if ( aINetProtocol == INetProtocol::Ftp || |
892 | 0 | aINetProtocol == INetProtocol::Http || |
893 | 0 | aINetProtocol == INetProtocol::Https ) |
894 | 0 | { |
895 | 0 | sfx2::openUriExternally(aURL.Complete, true, rReq.GetFrameWeld()); |
896 | 0 | return; |
897 | 0 | } |
898 | 0 | else |
899 | 0 | { |
900 | | // check for "internal" protocols that should not be forwarded to the system |
901 | | // add special protocols that always should be treated as internal |
902 | 0 | std::vector < OUString > aProtocols { u"private:*"_ustr, u"vnd.sun.star.*"_ustr }; |
903 | | |
904 | | // get registered protocol handlers from configuration |
905 | 0 | Reference < XNameAccess > xAccess(officecfg::Office::ProtocolHandler::HandlerSet::get()); |
906 | 0 | const Sequence < OUString > aNames = xAccess->getElementNames(); |
907 | 0 | for ( const auto& rName : aNames ) |
908 | 0 | { |
909 | 0 | Reference < XPropertySet > xSet; |
910 | 0 | Any aRet = xAccess->getByName( rName ); |
911 | 0 | aRet >>= xSet; |
912 | 0 | if ( xSet.is() ) |
913 | 0 | { |
914 | | // copy protocols |
915 | 0 | aRet = xSet->getPropertyValue(u"Protocols"_ustr); |
916 | 0 | Sequence < OUString > aTmp; |
917 | 0 | aRet >>= aTmp; |
918 | |
|
919 | 0 | aProtocols.insert(aProtocols.end(),std::cbegin(aTmp),std::cend(aTmp)); |
920 | 0 | } |
921 | 0 | } |
922 | |
|
923 | 0 | bool bFound = false; |
924 | 0 | for (const OUString & rProtocol : aProtocols) |
925 | 0 | { |
926 | 0 | WildCard aPattern(rProtocol); |
927 | 0 | if ( aPattern.Matches( aURL.Complete ) ) |
928 | 0 | { |
929 | 0 | bFound = true; |
930 | 0 | break; |
931 | 0 | } |
932 | 0 | } |
933 | |
|
934 | 0 | if ( !bFound ) |
935 | 0 | { |
936 | 0 | bool bLoadInternal = false; |
937 | 0 | try |
938 | 0 | { |
939 | 0 | sfx2::openUriExternally( |
940 | 0 | aURL.Complete, pFilter == nullptr, rReq.GetFrameWeld()); |
941 | 0 | } |
942 | 0 | catch ( css::system::SystemShellExecuteException& ) |
943 | 0 | { |
944 | 0 | rReq.RemoveItem( SID_TARGETNAME ); |
945 | 0 | rReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_default"_ustr ) ); |
946 | 0 | bLoadInternal = true; |
947 | 0 | } |
948 | 0 | if ( !bLoadInternal ) |
949 | 0 | return; |
950 | 0 | } |
951 | 0 | } |
952 | 0 | } |
953 | 0 | else |
954 | 0 | { |
955 | | // hyperlink document must be loaded into a new frame |
956 | 0 | rReq.RemoveItem( SID_TARGETNAME ); |
957 | 0 | rReq.AppendItem( SfxStringItem( SID_TARGETNAME, u"_default"_ustr ) ); |
958 | 0 | } |
959 | 0 | } |
960 | 0 | } |
961 | | |
962 | 0 | if (!SvtSecurityOptions::isSecureMacroUri(aFileName, aReferer)) |
963 | 0 | { |
964 | 0 | SfxErrorContext aCtx( ERRCTX_SFX_OPENDOC, aFileName ); |
965 | 0 | ErrorHandler::HandleError( ERRCODE_IO_ACCESSDENIED ); |
966 | 0 | return; |
967 | 0 | } |
968 | | |
969 | 0 | SfxFrame* pTargetFrame = nullptr; |
970 | 0 | Reference< XFrame > xTargetFrame; |
971 | |
|
972 | 0 | const SfxFrameItem* pFrameItem = rReq.GetArg<SfxFrameItem>(SID_DOCFRAME); |
973 | 0 | if ( pFrameItem ) |
974 | 0 | pTargetFrame = pFrameItem->GetFrame(); |
975 | |
|
976 | 0 | if ( !pTargetFrame ) |
977 | 0 | { |
978 | 0 | const SfxUnoFrameItem* pUnoFrameItem = rReq.GetArg<SfxUnoFrameItem>(SID_FILLFRAME); |
979 | 0 | if ( pUnoFrameItem ) |
980 | 0 | xTargetFrame = pUnoFrameItem->GetFrame(); |
981 | 0 | } |
982 | |
|
983 | 0 | if (!pTargetFrame && !xTargetFrame.is()) |
984 | 0 | { |
985 | 0 | if (const SfxViewFrame* pViewFrame = SfxViewFrame::Current()) |
986 | 0 | pTargetFrame = &pViewFrame->GetFrame(); |
987 | 0 | } |
988 | | |
989 | | // check if caller has set a callback |
990 | 0 | std::unique_ptr<SfxLinkItem> pLinkItem; |
991 | | |
992 | | // remove from Itemset, because it confuses the parameter transformation |
993 | 0 | if (auto pParamLinkItem = rReq.GetArg<SfxLinkItem>(SID_DONELINK)) |
994 | 0 | pLinkItem.reset(pParamLinkItem->Clone()); |
995 | |
|
996 | 0 | rReq.RemoveItem( SID_DONELINK ); |
997 | | |
998 | | // check if the view must be hidden |
999 | 0 | bool bHidden = false; |
1000 | 0 | const SfxBoolItem* pHidItem = rReq.GetArg<SfxBoolItem>(SID_HIDDEN); |
1001 | 0 | if ( pHidItem ) |
1002 | 0 | bHidden = pHidItem->GetValue(); |
1003 | | |
1004 | | // This request is a UI call. We have to set the right values inside the MediaDescriptor |
1005 | | // for: InteractionHandler, StatusIndicator, MacroExecutionMode and DocTemplate. |
1006 | | // But we have to look for already existing values or for real hidden requests. |
1007 | 0 | const SfxBoolItem* pPreviewItem = rReq.GetArg<SfxBoolItem>(SID_PREVIEW); |
1008 | 0 | if (!bHidden && ( !pPreviewItem || !pPreviewItem->GetValue() ) ) |
1009 | 0 | { |
1010 | 0 | const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER); |
1011 | 0 | const SfxUInt16Item* pMacroExecItem = rReq.GetArg<SfxUInt16Item>(SID_MACROEXECMODE); |
1012 | 0 | const SfxUInt16Item* pDocTemplateItem = rReq.GetArg<SfxUInt16Item>(SID_UPDATEDOCMODE); |
1013 | |
|
1014 | 0 | if (!pInteractionItem) |
1015 | 0 | { |
1016 | 0 | Reference < task::XInteractionHandler2 > xHdl = task::InteractionHandler::createWithParent( ::comphelper::getProcessComponentContext(), nullptr ); |
1017 | 0 | rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::Any(xHdl)) ); |
1018 | 0 | } |
1019 | 0 | if (!pMacroExecItem) |
1020 | 0 | rReq.AppendItem( SfxUInt16Item(SID_MACROEXECMODE,css::document::MacroExecMode::USE_CONFIG) ); |
1021 | 0 | if (!pDocTemplateItem) |
1022 | 0 | rReq.AppendItem( SfxUInt16Item(SID_UPDATEDOCMODE,css::document::UpdateDocMode::ACCORDING_TO_CONFIG) ); |
1023 | 0 | } |
1024 | | |
1025 | | // extract target name |
1026 | 0 | OUString aTarget; |
1027 | 0 | const SfxStringItem* pTargetItem = rReq.GetArg<SfxStringItem>(SID_TARGETNAME); |
1028 | 0 | if ( pTargetItem ) |
1029 | 0 | aTarget = pTargetItem->GetValue(); |
1030 | 0 | else |
1031 | 0 | { |
1032 | 0 | const SfxBoolItem* pNewViewItem = rReq.GetArg<SfxBoolItem>(SID_OPEN_NEW_VIEW); |
1033 | 0 | if ( pNewViewItem && pNewViewItem->GetValue() ) |
1034 | 0 | aTarget = "_blank" ; |
1035 | 0 | } |
1036 | |
|
1037 | 0 | if ( bHidden ) |
1038 | 0 | { |
1039 | 0 | aTarget = "_blank"; |
1040 | 0 | DBG_ASSERT( rReq.IsSynchronCall() || pLinkItem, "Hidden load process must be done synchronously!" ); |
1041 | 0 | } |
1042 | |
|
1043 | 0 | Reference < XController > xController; |
1044 | | // if a frame is given, it must be used for the starting point of the targeting mechanism |
1045 | | // this code is also used if asynchronous loading is possible, because loadComponent always is synchron |
1046 | 0 | if ( !xTargetFrame.is() ) |
1047 | 0 | { |
1048 | 0 | if ( pTargetFrame ) |
1049 | 0 | { |
1050 | 0 | xTargetFrame = pTargetFrame->GetFrameInterface(); |
1051 | 0 | } |
1052 | 0 | else |
1053 | 0 | { |
1054 | 0 | xTargetFrame = Desktop::create(::comphelper::getProcessComponentContext()); |
1055 | 0 | } |
1056 | 0 | } |
1057 | | |
1058 | | // make URL ready |
1059 | 0 | const SfxStringItem* pURLItem = rReq.GetArg<SfxStringItem>(SID_FILE_NAME); |
1060 | 0 | aFileName = pURLItem->GetValue(); |
1061 | 0 | if( aFileName.startsWith("#") ) // Mark without URL |
1062 | 0 | { |
1063 | 0 | SfxViewFrame *pView = pTargetFrame ? pTargetFrame->GetCurrentViewFrame() : nullptr; |
1064 | 0 | if (!pView) |
1065 | 0 | pView = SfxViewFrame::Current(); |
1066 | 0 | if (pView) |
1067 | 0 | pView->GetViewShell()->JumpToMark( aFileName.copy(1) ); |
1068 | 0 | rReq.SetReturnValue( SfxViewFrameItem( pView ) ); |
1069 | 0 | return; |
1070 | 0 | } |
1071 | | |
1072 | | // convert items to properties for framework API calls |
1073 | 0 | Sequence < PropertyValue > aArgs; |
1074 | 0 | TransformItems( SID_OPENDOC, *rReq.GetArgs(), aArgs ); |
1075 | | // Any Referer (that was relevant in the above call to |
1076 | | // SvtSecurityOptions::isSecureMacroUri) is no longer relevant, assuming |
1077 | | // this "open" request is initiated directly by the user: |
1078 | 0 | auto pArg = std::find_if(std::cbegin(aArgs), std::cend(aArgs), |
1079 | 0 | [](const PropertyValue& rArg) { return rArg.Name == "Referer"; }); |
1080 | 0 | if (pArg != std::cend(aArgs)) |
1081 | 0 | { |
1082 | 0 | auto nIndex = static_cast<sal_Int32>(std::distance(std::cbegin(aArgs), pArg)); |
1083 | 0 | comphelper::removeElementAt(aArgs, nIndex); |
1084 | 0 | } |
1085 | | |
1086 | | // TODO/LATER: either remove LinkItem or create an asynchronous process for it |
1087 | 0 | if( bHidden || pLinkItem || rReq.IsSynchronCall() ) |
1088 | 0 | { |
1089 | | // if loading must be done synchron, we must wait for completion to get a return value |
1090 | | // find frame by myself; I must know the exact frame to get the controller for the return value from it |
1091 | 0 | Reference < XComponent > xComp; |
1092 | |
|
1093 | 0 | try |
1094 | 0 | { |
1095 | 0 | xComp = ::comphelper::SynchronousDispatch::dispatch( xTargetFrame, aFileName, aTarget, aArgs ); |
1096 | 0 | } |
1097 | 0 | catch(const RuntimeException&) |
1098 | 0 | { |
1099 | 0 | throw; |
1100 | 0 | } |
1101 | 0 | catch(const css::uno::Exception&) |
1102 | 0 | { |
1103 | 0 | } |
1104 | | |
1105 | 0 | Reference < XModel > xModel( xComp, UNO_QUERY ); |
1106 | 0 | if ( xModel.is() ) |
1107 | 0 | xController = xModel->getCurrentController(); |
1108 | 0 | else |
1109 | 0 | xController.set( xComp, UNO_QUERY ); |
1110 | |
|
1111 | 0 | } |
1112 | 0 | else |
1113 | 0 | { |
1114 | 0 | URL aURL; |
1115 | 0 | aURL.Complete = aFileName; |
1116 | 0 | Reference< util::XURLTransformer > xTrans( util::URLTransformer::create( ::comphelper::getProcessComponentContext() ) ); |
1117 | 0 | xTrans->parseStrict( aURL ); |
1118 | |
|
1119 | 0 | Reference < XDispatchProvider > xProv( xTargetFrame, UNO_QUERY ); |
1120 | 0 | Reference < XDispatch > xDisp = xProv.is() ? xProv->queryDispatch( aURL, aTarget, FrameSearchFlag::ALL ) : Reference < XDispatch >(); |
1121 | 0 | if ( xDisp.is() ) |
1122 | 0 | xDisp->dispatch( aURL, aArgs ); |
1123 | 0 | } |
1124 | | |
1125 | 0 | if ( xController.is() ) |
1126 | 0 | { |
1127 | | // try to find the SfxFrame for the controller |
1128 | 0 | SfxFrame* pCntrFrame = nullptr; |
1129 | 0 | for ( SfxViewShell* pShell = SfxViewShell::GetFirst( false ); pShell; pShell = SfxViewShell::GetNext( *pShell, false ) ) |
1130 | 0 | { |
1131 | 0 | if ( pShell->GetController() == xController ) |
1132 | 0 | { |
1133 | 0 | pCntrFrame = &pShell->GetViewFrame().GetFrame(); |
1134 | 0 | break; |
1135 | 0 | } |
1136 | 0 | } |
1137 | |
|
1138 | 0 | if ( pCntrFrame ) |
1139 | 0 | { |
1140 | 0 | SfxObjectShell* pSh = pCntrFrame->GetCurrentDocument(); |
1141 | 0 | DBG_ASSERT( pSh, "Controller without ObjectShell ?!" ); |
1142 | |
|
1143 | 0 | rReq.SetReturnValue( SfxViewFrameItem( pCntrFrame->GetCurrentViewFrame() ) ); |
1144 | 0 | } |
1145 | 0 | } |
1146 | |
|
1147 | 0 | if (pLinkItem) |
1148 | 0 | { |
1149 | 0 | const SfxPoolItem* pRetValue(rReq.GetReturnValue().getItem()); |
1150 | 0 | if (pRetValue) |
1151 | 0 | { |
1152 | 0 | pLinkItem->GetValue().Call(pRetValue); |
1153 | 0 | } |
1154 | 0 | } |
1155 | 0 | } |
1156 | | |
1157 | | void SfxApplication::OpenRemoteExec_Impl( SfxRequest& rReq ) |
1158 | 0 | { |
1159 | 0 | rReq.AppendItem( SfxBoolItem( SID_REMOTE_DIALOG, true ) ); |
1160 | 0 | GetDispatcher_Impl()->Execute( SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs() ); |
1161 | 0 | } |
1162 | | |
1163 | | void SfxApplication::SignPDFExec_Impl(SfxRequest& rReq) |
1164 | 0 | { |
1165 | 0 | rReq.AppendItem(SfxBoolItem(SID_SIGNPDF, true)); |
1166 | 0 | GetDispatcher_Impl()->Execute(SID_OPENDOC, SfxCallMode::SYNCHRON, *rReq.GetArgs()); |
1167 | 0 | } |
1168 | | |
1169 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |