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