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 <config_features.h>
21 
22 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
23 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
24 #include <com/sun/star/util/CloseVetoException.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/beans/PropertyValue.hpp>
27 #include <com/sun/star/document/XCmisDocument.hpp>
28 #include <com/sun/star/drawing/LineStyle.hpp>
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/security/XCertificate.hpp>
31 #include <com/sun/star/task/ErrorCodeIOException.hpp>
32 #include <com/sun/star/task/InteractionHandler.hpp>
33 #include <com/sun/star/task/XStatusIndicator.hpp>
34 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <comphelper/servicehelper.hxx>
37 #include <com/sun/star/drawing/XDrawView.hpp>
38 
39 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
40 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
41 #include <tools/diagnose_ex.h>
42 #include <tools/urlobj.hxx>
43 #include <svl/whiter.hxx>
44 #include <svl/intitem.hxx>
45 #include <svl/eitem.hxx>
46 #include <svl/visitem.hxx>
47 #include <svtools/sfxecode.hxx>
48 #include <svtools/ehdl.hxx>
49 #include <sal/log.hxx>
50 #include <sfx2/app.hxx>
51 
52 #include <comphelper/string.hxx>
53 #include <basic/sbxcore.hxx>
54 #include <basic/sberrors.hxx>
55 #include <unotools/moduleoptions.hxx>
56 #include <unotools/saveopt.hxx>
57 #include <svtools/DocumentToGraphicRenderer.hxx>
58 #include <vcl/gdimtf.hxx>
59 #include <vcl/svapp.hxx>
60 #include <vcl/weld.hxx>
61 #include <comphelper/documentconstants.hxx>
62 #include <comphelper/storagehelper.hxx>
63 #include <comphelper/lok.hxx>
64 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
65 #include <tools/link.hxx>
66 
67 #include <sfx2/signaturestate.hxx>
68 #include <sfx2/sfxresid.hxx>
69 #include <sfx2/request.hxx>
70 #include <sfx2/printer.hxx>
71 #include <sfx2/viewsh.hxx>
72 #include <sfx2/dinfdlg.hxx>
73 #include <sfx2/docfilt.hxx>
74 #include <sfx2/docfile.hxx>
75 #include <sfx2/dispatch.hxx>
76 #include <sfx2/objitem.hxx>
77 #include <sfx2/objsh.hxx>
78 #include <objshimp.hxx>
79 #include <sfx2/module.hxx>
80 #include <sfx2/viewfrm.hxx>
81 #include <versdlg.hxx>
82 #include <sfx2/strings.hrc>
83 #include <sfx2/docfac.hxx>
84 #include <sfx2/fcontnr.hxx>
85 #include <sfx2/msgpool.hxx>
86 #include <sfx2/objface.hxx>
87 #include <checkin.hxx>
88 #include <sfx2/infobar.hxx>
89 #include <sfx2/sfxuno.hxx>
90 #include <sfx2/sfxsids.hrc>
91 #include <SfxRedactionHelper.hxx>
92 
93 #include <com/sun/star/util/XCloseable.hpp>
94 #include <com/sun/star/document/XDocumentProperties.hpp>
95 
96 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
97 #include <com/sun/star/frame/XDesktop2.hpp>
98 #include <com/sun/star/frame/Desktop.hpp>
99 
100 #include <guisaveas.hxx>
101 #include <saveastemplatedlg.hxx>
102 #include <memory>
103 #include <cppuhelper/implbase.hxx>
104 #include <unotools/ucbstreamhelper.hxx>
105 #include <unotools/streamwrap.hxx>
106 #include <comphelper/sequenceashashmap.hxx>
107 
108 #include <autoredactdialog.hxx>
109 
110 #include <boost/property_tree/json_parser.hpp>
111 
112 using namespace ::com::sun::star;
113 using namespace ::com::sun::star::lang;
114 using namespace ::com::sun::star::uno;
115 using namespace ::com::sun::star::ui::dialogs;
116 using namespace ::com::sun::star::awt;
117 using namespace ::com::sun::star::container;
118 using namespace ::com::sun::star::beans;
119 using namespace ::com::sun::star::document;
120 using namespace ::com::sun::star::security;
121 using namespace ::com::sun::star::task;
122 using namespace ::com::sun::star::graphic;
123 
124 #define ShellClass_SfxObjectShell
125 #include <sfxslots.hxx>
126 
SFX_IMPL_SUPERCLASS_INTERFACE(SfxObjectShell,SfxShell)127 SFX_IMPL_SUPERCLASS_INTERFACE(SfxObjectShell, SfxShell)
128 
129 void SfxObjectShell::InitInterface_Impl()
130 {
131 }
132 
133 namespace {
134 
135 class SfxClosePreventer_Impl : public ::cppu::WeakImplHelper< css::util::XCloseListener >
136 {
137     bool m_bGotOwnership;
138     bool m_bPreventClose;
139 
140 public:
141     SfxClosePreventer_Impl();
142 
HasOwnership() const143     bool HasOwnership() const { return m_bGotOwnership; }
144 
SetPreventClose(bool bPrevent)145     void SetPreventClose( bool bPrevent ) { m_bPreventClose = bPrevent; }
146 
147     virtual void SAL_CALL queryClosing( const lang::EventObject& aEvent, sal_Bool bDeliverOwnership ) override;
148 
149     virtual void SAL_CALL notifyClosing( const lang::EventObject& aEvent ) override ;
150 
151     virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) override ;
152 
153 } ;
154 
155 }
156 
SfxClosePreventer_Impl()157 SfxClosePreventer_Impl::SfxClosePreventer_Impl()
158 : m_bGotOwnership( false )
159 , m_bPreventClose( true )
160 {
161 }
162 
queryClosing(const lang::EventObject &,sal_Bool bDeliverOwnership)163 void SAL_CALL SfxClosePreventer_Impl::queryClosing( const lang::EventObject&, sal_Bool bDeliverOwnership )
164 {
165     if ( m_bPreventClose )
166     {
167         if ( !m_bGotOwnership )
168             m_bGotOwnership = bDeliverOwnership;
169 
170         throw util::CloseVetoException();
171     }
172 }
173 
notifyClosing(const lang::EventObject &)174 void SAL_CALL SfxClosePreventer_Impl::notifyClosing( const lang::EventObject& )
175 {}
176 
disposing(const lang::EventObject &)177 void SAL_CALL SfxClosePreventer_Impl::disposing( const lang::EventObject& )
178 {}
179 
180 namespace {
181 
182 class SfxInstanceCloseGuard_Impl
183 {
184     rtl::Reference<SfxClosePreventer_Impl> m_xPreventer;
185     uno::Reference< util::XCloseable > m_xCloseable;
186 
187 public:
SfxInstanceCloseGuard_Impl()188     SfxInstanceCloseGuard_Impl() {}
189 
190     ~SfxInstanceCloseGuard_Impl();
191 
192     bool Init_Impl( const uno::Reference< util::XCloseable >& xCloseable );
193 };
194 
195 }
196 
Init_Impl(const uno::Reference<util::XCloseable> & xCloseable)197 bool SfxInstanceCloseGuard_Impl::Init_Impl( const uno::Reference< util::XCloseable >& xCloseable )
198 {
199     bool bResult = false;
200 
201     // do not allow reinit after the successful init
202     if ( xCloseable.is() && !m_xCloseable.is() )
203     {
204         try
205         {
206             m_xPreventer = new SfxClosePreventer_Impl();
207             xCloseable->addCloseListener( m_xPreventer );
208             m_xCloseable = xCloseable;
209             bResult = true;
210         }
211         catch( uno::Exception& )
212         {
213             OSL_FAIL( "Could not register close listener!" );
214         }
215     }
216 
217     return bResult;
218 }
219 
~SfxInstanceCloseGuard_Impl()220 SfxInstanceCloseGuard_Impl::~SfxInstanceCloseGuard_Impl()
221 {
222     if ( !m_xCloseable.is() || !m_xPreventer.is() )
223         return;
224 
225     try
226     {
227         m_xCloseable->removeCloseListener( m_xPreventer );
228     }
229     catch( uno::Exception& )
230     {
231     }
232 
233     try
234     {
235         if ( m_xPreventer.is() )
236         {
237             m_xPreventer->SetPreventClose( false );
238 
239             if ( m_xPreventer->HasOwnership() )
240                 m_xCloseable->close( true ); // TODO: do it asynchronously
241         }
242     }
243     catch( uno::Exception& )
244     {
245     }
246 }
247 
248 
PrintExec_Impl(SfxRequest & rReq)249 void SfxObjectShell::PrintExec_Impl(SfxRequest &rReq)
250 {
251     SfxViewFrame *pFrame = SfxViewFrame::GetFirst(this);
252     if ( pFrame )
253     {
254         rReq.SetSlot( SID_PRINTDOC );
255         pFrame->GetViewShell()->ExecuteSlot(rReq);
256     }
257 }
258 
259 
PrintState_Impl(SfxItemSet & rSet)260 void SfxObjectShell::PrintState_Impl(SfxItemSet &rSet)
261 {
262     bool bPrinting = false;
263     SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this );
264     if ( pFrame )
265     {
266         SfxPrinter *pPrinter = pFrame->GetViewShell()->GetPrinter();
267         bPrinting = pPrinter && pPrinter->IsPrinting();
268     }
269     rSet.Put( SfxBoolItem( SID_PRINTOUT, bPrinting ) );
270 }
271 
APISaveAs_Impl(const OUString & aFileName,SfxItemSet & rItemSet,const css::uno::Sequence<css::beans::PropertyValue> & rArgs)272 bool SfxObjectShell::APISaveAs_Impl(const OUString& aFileName, SfxItemSet& rItemSet,
273                                     const css::uno::Sequence<css::beans::PropertyValue>& rArgs)
274 {
275     bool bOk = false;
276 
277     if ( GetMedium() )
278     {
279         OUString aFilterName;
280         const SfxStringItem* pFilterNameItem = rItemSet.GetItem<SfxStringItem>(SID_FILTER_NAME, false);
281         if( pFilterNameItem )
282         {
283             aFilterName = pFilterNameItem->GetValue();
284         }
285         else
286         {
287             const SfxStringItem* pContentTypeItem = rItemSet.GetItem<SfxStringItem>(SID_CONTENTTYPE, false);
288             if ( pContentTypeItem )
289             {
290                 std::shared_ptr<const SfxFilter> pFilter = SfxFilterMatcher( GetFactory().GetFactoryName() ).GetFilter4Mime( pContentTypeItem->GetValue(), SfxFilterFlags::EXPORT );
291                 if ( pFilter )
292                     aFilterName = pFilter->GetName();
293             }
294         }
295 
296         // in case no filter defined use default one
297         if( aFilterName.isEmpty() )
298         {
299             std::shared_ptr<const SfxFilter> pFilt = SfxFilter::GetDefaultFilterFromFactory(GetFactory().GetFactoryName());
300 
301             DBG_ASSERT( pFilt, "No default filter!\n" );
302             if( pFilt )
303                 aFilterName = pFilt->GetFilterName();
304 
305             rItemSet.Put(SfxStringItem(SID_FILTER_NAME, aFilterName));
306         }
307 
308 
309         {
310             SfxObjectShellRef xLock( this ); // ???
311 
312             // use the title that is provided in the media descriptor
313             const SfxStringItem* pDocTitleItem = rItemSet.GetItem<SfxStringItem>(SID_DOCINFO_TITLE, false);
314             if ( pDocTitleItem )
315                 getDocProperties()->setTitle( pDocTitleItem->GetValue() );
316 
317             bOk = CommonSaveAs_Impl(INetURLObject(aFileName), aFilterName, rItemSet, rArgs);
318         }
319     }
320 
321     return bOk;
322 }
323 
CheckOut()324 void SfxObjectShell::CheckOut( )
325 {
326     try
327     {
328         uno::Reference< document::XCmisDocument > xCmisDoc( GetModel(), uno::UNO_QUERY_THROW );
329         xCmisDoc->checkOut( );
330 
331         // Remove the info bar
332         SfxViewFrame* pViewFrame = GetFrame();
333         pViewFrame->RemoveInfoBar( u"checkout" );
334     }
335     catch ( const uno::RuntimeException& e )
336     {
337         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrame()->GetFrameWeld(),
338                                                   VclMessageType::Warning, VclButtonsType::Ok, e.Message));
339         xBox->run();
340     }
341 }
342 
CancelCheckOut()343 void SfxObjectShell::CancelCheckOut( )
344 {
345     try
346     {
347         uno::Reference< document::XCmisDocument > xCmisDoc( GetModel(), uno::UNO_QUERY_THROW );
348         xCmisDoc->cancelCheckOut( );
349 
350         uno::Reference< util::XModifiable > xModifiable( GetModel( ), uno::UNO_QUERY );
351         if ( xModifiable.is( ) )
352             xModifiable->setModified( false );
353     }
354     catch ( const uno::RuntimeException& e )
355     {
356         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrame()->GetFrameWeld(),
357                                                   VclMessageType::Warning, VclButtonsType::Ok, e.Message));
358         xBox->run();
359     }
360 }
361 
CheckIn()362 void SfxObjectShell::CheckIn( )
363 {
364     try
365     {
366         uno::Reference< document::XCmisDocument > xCmisDoc( GetModel(), uno::UNO_QUERY_THROW );
367         // Pop up dialog to ask for comment and major
368         SfxCheckinDialog checkinDlg(GetFrame()->GetFrameWeld());
369         if (checkinDlg.run() == RET_OK)
370         {
371             xCmisDoc->checkIn(checkinDlg.IsMajor(), checkinDlg.GetComment());
372             uno::Reference< util::XModifiable > xModifiable( GetModel( ), uno::UNO_QUERY );
373             if ( xModifiable.is( ) )
374                 xModifiable->setModified( false );
375         }
376     }
377     catch ( const uno::RuntimeException& e )
378     {
379         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrame()->GetFrameWeld(),
380                                                   VclMessageType::Warning, VclButtonsType::Ok, e.Message));
381         xBox->run();
382     }
383 }
384 
GetCmisVersions() const385 uno::Sequence< document::CmisVersion > SfxObjectShell::GetCmisVersions( ) const
386 {
387     try
388     {
389         uno::Reference< document::XCmisDocument > xCmisDoc( GetModel(), uno::UNO_QUERY_THROW );
390         return xCmisDoc->getAllVersions( );
391     }
392     catch ( const uno::RuntimeException& e )
393     {
394         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrame()->GetFrameWeld(),
395                                                   VclMessageType::Warning, VclButtonsType::Ok, e.Message));
396         xBox->run();
397     }
398     return uno::Sequence< document::CmisVersion > ( );
399 }
400 
IsSignPDF() const401 bool SfxObjectShell::IsSignPDF() const
402 {
403     if (pMedium && !pMedium->IsOriginallyReadOnly())
404     {
405         const std::shared_ptr<const SfxFilter>& pFilter = pMedium->GetFilter();
406         if (pFilter && pFilter->GetName() == "draw_pdf_import")
407             return true;
408     }
409 
410     return false;
411 }
412 
GetSignPDFCertificate() const413 uno::Reference<security::XCertificate> SfxObjectShell::GetSignPDFCertificate() const
414 {
415     uno::Reference<frame::XModel> xModel = GetBaseModel();
416     if (!xModel.is())
417     {
418         return uno::Reference<security::XCertificate>();
419     }
420 
421     uno::Reference<drawing::XShapes> xShapes(xModel->getCurrentSelection(), uno::UNO_QUERY);
422     if (!xShapes.is() || xShapes->getCount() < 1)
423     {
424         return uno::Reference<security::XCertificate>();
425     }
426 
427     uno::Reference<beans::XPropertySet> xShapeProps(xShapes->getByIndex(0), uno::UNO_QUERY);
428     if (!xShapeProps.is())
429     {
430         return uno::Reference<security::XCertificate>();
431     }
432 
433     if (!xShapeProps->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
434     {
435         return uno::Reference<security::XCertificate>();
436     }
437 
438     comphelper::SequenceAsHashMap aMap(xShapeProps->getPropertyValue("InteropGrabBag"));
439     auto it = aMap.find("SignatureCertificate");
440     if (it == aMap.end())
441     {
442         return uno::Reference<security::XCertificate>();
443     }
444 
445     return uno::Reference<security::XCertificate>(it->second, uno::UNO_QUERY);
446 }
447 
sendErrorToLOK(ErrCode error)448 static void sendErrorToLOK(ErrCode error)
449 {
450     if (error.GetClass() == ErrCodeClass::NONE)
451         return;
452 
453     boost::property_tree::ptree aTree;
454     aTree.put("code", error);
455     aTree.put("kind", "");
456     aTree.put("cmd", "");
457 
458     std::unique_ptr<ErrorInfo> pInfo = ErrorInfo::GetErrorInfo(error);
459     OUString aErr;
460     if (ErrorStringFactory::CreateString(pInfo.get(), aErr))
461         aTree.put("message", aErr.toUtf8());
462 
463     std::stringstream aStream;
464     boost::property_tree::write_json(aStream, aTree);
465 
466     SfxViewShell::Current()->libreOfficeKitViewCallback(LOK_CALLBACK_ERROR, aStream.str().c_str());
467 }
468 
ExecFile_Impl(SfxRequest & rReq)469 void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
470 {
471     weld::Window* pDialogParent = rReq.GetFrameWeld();
472     if (!pDialogParent)
473     {
474         SfxViewFrame* pFrame = GetFrame();
475         if (!pFrame)
476             pFrame = SfxViewFrame::GetFirst(this);
477         if (pFrame)
478             pDialogParent = pFrame->GetFrameWeld();
479     }
480 
481     sal_uInt16 nId = rReq.GetSlot();
482 
483     if( SID_SIGNATURE == nId || SID_MACRO_SIGNATURE == nId )
484     {
485         if ( QueryHiddenInformation( HiddenWarningFact::WhenSigning, nullptr ) == RET_YES )
486         {
487             if (SID_SIGNATURE == nId)
488             {
489                 uno::Reference<security::XCertificate> xCertificate = GetSignPDFCertificate();
490                 if (xCertificate.is())
491                 {
492                     SignDocumentContentUsingCertificate(xCertificate);
493 
494                     // Reload to show how the PDF actually looks like after signing. This also
495                     // changes "finish signing" on the infobar back to "sign document" as a side
496                     // effect.
497                     SfxViewFrame* pFrame = GetFrame();
498                     if (pFrame)
499                     {
500                         // Store current page before reload.
501                         SfxAllItemSet aSet(SfxGetpApp()->GetPool());
502                         uno::Reference<drawing::XDrawView> xController(
503                             GetBaseModel()->getCurrentController(), uno::UNO_QUERY);
504                         uno::Reference<beans::XPropertySet> xPage(xController->getCurrentPage(),
505                                                                   uno::UNO_QUERY);
506                         sal_Int32 nPage{};
507                         xPage->getPropertyValue("Number") >>= nPage;
508                         if (nPage > 0)
509                         {
510                             // nPage is 1-based.
511                             aSet.Put(SfxInt32Item(SID_PAGE_NUMBER, nPage - 1));
512                         }
513                         SfxRequest aReq(SID_RELOAD, SfxCallMode::SLOT, aSet);
514                         pFrame->ExecReload_Impl(aReq);
515                     }
516                 }
517                 else
518                 {
519                     SignDocumentContent(pDialogParent);
520                 }
521             }
522             else
523             {
524                 SignScriptingContent(pDialogParent);
525             }
526         }
527         return;
528     }
529 
530     if ( !GetMedium() && nId != SID_CLOSEDOC )
531     {
532         rReq.Ignore();
533         return;
534     }
535 
536     // this guard is created here to have it destruction at the end of the method
537     SfxInstanceCloseGuard_Impl aModelGuard;
538 
539     bool bIsPDFExport = false;
540     bool bIsAutoRedact = false;
541     std::vector<std::pair<RedactionTarget, OUString>> aRedactionTargets;
542     switch(nId)
543     {
544         case SID_VERSION:
545         {
546             SfxViewFrame* pFrame = GetFrame();
547             if ( !pFrame )
548                 pFrame = SfxViewFrame::GetFirst( this );
549             if ( !pFrame )
550                 return;
551 
552             if ( !IsOwnStorageFormat( *GetMedium() ) )
553                 return;
554 
555             SfxVersionDialog aDlg(pDialogParent, pFrame, IsSaveVersionOnClose());
556             aDlg.run();
557             SetSaveVersionOnClose(aDlg.IsSaveVersionOnClose());
558             rReq.Done();
559             return;
560         }
561 
562         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
563         case SID_DOCINFO:
564         {
565             const SfxDocumentInfoItem* pDocInfItem = rReq.GetArg<SfxDocumentInfoItem>(SID_DOCINFO);
566             if ( pDocInfItem )
567             {
568                 // parameter, e.g. from replayed macro
569                 pDocInfItem->UpdateDocumentInfo(getDocProperties(), true);
570                 SetUseUserData( pDocInfItem->IsUseUserData() );
571                 SetUseThumbnailSave( pDocInfItem->IsUseThumbnailSave() );
572             }
573             else
574             {
575                 // no argument containing DocInfo; check optional arguments
576                 bool bReadOnly = IsReadOnly();
577                 const SfxBoolItem* pROItem = rReq.GetArg<SfxBoolItem>(SID_DOC_READONLY);
578                 if ( pROItem )
579                     // override readonly attribute of document
580                     // e.g. if a readonly document is saved elsewhere and user asks for editing DocInfo before
581                     bReadOnly = pROItem->GetValue();
582 
583                 // URL for dialog
584                 const OUString aURL( HasName() ? GetMedium()->GetName() : GetFactory().GetFactoryURL() );
585 
586                 Reference< XCmisDocument > xCmisDoc( GetModel(), uno::UNO_QUERY );
587                 uno::Sequence< document::CmisProperty> aCmisProperties = xCmisDoc->getCmisProperties();
588 
589                 SfxDocumentInfoItem aDocInfoItem( aURL, getDocProperties(), aCmisProperties,
590                     IsUseUserData(), IsUseThumbnailSave() );
591                 if ( !GetSlotState( SID_DOCTEMPLATE ) )
592                     // templates not supported
593                     aDocInfoItem.SetTemplate(false);
594 
595                 SfxItemSet aSet(GetPool(), svl::Items<SID_DOCINFO, SID_DOCINFO, SID_DOC_READONLY, SID_DOC_READONLY,
596                                 SID_EXPLORER_PROPS_START, SID_EXPLORER_PROPS_START, SID_BASEURL, SID_BASEURL>{} );
597                 aSet.Put( aDocInfoItem );
598                 aSet.Put( SfxBoolItem( SID_DOC_READONLY, bReadOnly ) );
599                 aSet.Put( SfxStringItem( SID_EXPLORER_PROPS_START, GetTitle() ) );
600                 aSet.Put( SfxStringItem( SID_BASEURL, GetMedium()->GetBaseURL() ) );
601 
602                 // creating dialog is done via virtual method; application will
603                 // add its own statistics page
604                 std::shared_ptr<SfxDocumentInfoDialog> xDlg(CreateDocumentInfoDialog(rReq.GetFrameWeld(), aSet));
605                 auto aFunc = [this, xDlg, xCmisDoc](sal_Int32 nResult, SfxRequest& rRequest)
606                 {
607                     if (RET_OK == nResult)
608                     {
609                         const SfxDocumentInfoItem* pDocInfoItem = SfxItemSet::GetItem<SfxDocumentInfoItem>(xDlg->GetOutputItemSet(), SID_DOCINFO, false);
610                         if ( pDocInfoItem )
611                         {
612                             // user has done some changes to DocumentInfo
613                             pDocInfoItem->UpdateDocumentInfo(getDocProperties());
614                             const uno::Sequence< document::CmisProperty >& aNewCmisProperties =
615                                 pDocInfoItem->GetCmisProperties( );
616                             if ( aNewCmisProperties.hasElements( ) )
617                                 xCmisDoc->updateCmisProperties( aNewCmisProperties );
618                             SetUseUserData( pDocInfoItem->IsUseUserData() );
619                             SetUseThumbnailSave( pDocInfoItem-> IsUseThumbnailSave() );
620                             // add data from dialog for possible recording purpose
621                             rRequest.AppendItem( SfxDocumentInfoItem( GetTitle(),
622                                 getDocProperties(), aNewCmisProperties, IsUseUserData(), IsUseThumbnailSave() ) );
623                         }
624                         rRequest.Done();
625                     }
626                     else
627                     {
628                         // nothing done; no recording
629                         rRequest.Ignore();
630                     }
631                 };
632 
633                 if (!rReq.IsSynchronCall())
634                 {
635                     std::shared_ptr<SfxRequest> pReq = std::make_shared<SfxRequest>(rReq);
636                     SfxTabDialogController::runAsync(xDlg, [pReq, aFunc](sal_Int32 nResult)
637                     {
638                         aFunc(nResult, *pReq);
639                     });
640                     rReq.Ignore();
641                 }
642                 else
643                 {
644                     aFunc(xDlg->run(), rReq);
645                 }
646             }
647 
648             return;
649         }
650 
651         case SID_AUTOREDACTDOC:
652         {
653             // Actual redaction takes place on a newly generated Draw document
654             if (!SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::DRAW))
655             {
656                 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
657                     pDialogParent, VclMessageType::Warning, VclButtonsType::Ok,
658                     SfxResId(STR_REDACTION_NO_DRAW_WARNING)));
659 
660                 xBox->run();
661 
662                 return;
663             }
664 
665             SfxAutoRedactDialog aDlg(pDialogParent);
666             sal_Int16 nResult = aDlg.run();
667 
668             if (nResult != RET_OK || !aDlg.hasTargets() || !aDlg.isValidState())
669             {
670                 //Do nothing
671                 return;
672             }
673 
674             // else continue with normal redaction
675             bIsAutoRedact = true;
676             aDlg.getTargets(aRedactionTargets);
677 
678             [[fallthrough]];
679         }
680 
681         case SID_REDACTDOC:
682         {
683             css::uno::Reference<css::frame::XModel> xModel = GetModel();
684             if(!xModel.is())
685                 return;
686 
687             uno::Reference< lang::XComponent > xSourceDoc( xModel );
688 
689             // Actual redaction takes place on a newly generated Draw document
690             if (!SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::DRAW))
691             {
692                 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
693                     pDialogParent, VclMessageType::Warning, VclButtonsType::Ok,
694                     SfxResId(STR_REDACTION_NO_DRAW_WARNING)));
695 
696                 xBox->run();
697 
698                 return;
699             }
700 
701             DocumentToGraphicRenderer aRenderer(xSourceDoc, false);
702 
703             // Get the page margins of the original doc
704             PageMargins aPageMargins = {-1, -1, -1, -1};
705             if (aRenderer.isWriter())
706                 aPageMargins = SfxRedactionHelper::getPageMarginsForWriter(xModel);
707             else if (aRenderer.isCalc())
708                 aPageMargins = SfxRedactionHelper::getPageMarginsForCalc(xModel);
709 
710             sal_Int32 nPages = aRenderer.getPageCount();
711             std::vector< GDIMetaFile > aMetaFiles;
712             std::vector< ::Size > aPageSizes;
713 
714             // Convert the pages of the document to gdimetafiles
715             SfxRedactionHelper::getPageMetaFilesFromDoc(aMetaFiles, aPageSizes, nPages, aRenderer);
716 
717             // Create an empty Draw component.
718             uno::Reference<frame::XDesktop2> xDesktop = css::frame::Desktop::create(comphelper::getProcessComponentContext());
719             uno::Reference<lang::XComponent> xComponent = xDesktop->loadComponentFromURL("private:factory/sdraw", "_default", 0, {});
720 
721             if (!xComponent.is())
722             {
723                 SAL_WARN("sfx.doc", "SID_REDACTDOC: Failed to load new draw component. loadComponentFromURL returned an empty reference.");
724 
725                 return;
726             }
727 
728             // Add the doc pages to the new draw document
729             SfxRedactionHelper::addPagesToDraw(xComponent, nPages, aMetaFiles, aPageSizes, aPageMargins, aRedactionTargets, bIsAutoRedact);
730 
731             // Show the Redaction toolbar
732             SfxViewFrame* pViewFrame = SfxViewFrame::Current();
733             if (!pViewFrame)
734                 return;
735             SfxRedactionHelper::showRedactionToolbar(pViewFrame);
736 
737             return;
738         }
739 
740         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
741         case SID_DIRECTEXPORTDOCASPDF:
742         {
743             uno::Reference< lang::XComponent > xComponent( GetCurrentComponent(), uno::UNO_QUERY );
744             if (!xComponent.is())
745                 return;
746 
747             uno::Reference< lang::XServiceInfo > xServiceInfo( xComponent, uno::UNO_QUERY);
748 
749             // Redaction finalization takes place in Draw
750             if ( xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.drawing.DrawingDocument")
751                  && SfxRedactionHelper::isRedactMode(rReq) )
752             {
753                 OUString sRedactionStyle(SfxRedactionHelper::getStringParam(rReq, SID_REDACTION_STYLE));
754 
755                 // Access the draw pages
756                 uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(xComponent, uno::UNO_QUERY);
757                 uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
758 
759                 sal_Int32 nPageCount = xDrawPages->getCount();
760                 for (sal_Int32 nPageNum = 0; nPageNum < nPageCount; ++nPageNum)
761                 {
762                     // Get the page
763                     uno::Reference< drawing::XDrawPage > xPage( xDrawPages->getByIndex( nPageNum ), uno::UNO_QUERY );
764 
765                     if (!xPage.is())
766                         continue;
767 
768                     // Go through all shapes
769                     sal_Int32 nShapeCount = xPage->getCount();
770                     for (sal_Int32 nShapeNum = 0; nShapeNum < nShapeCount; ++nShapeNum)
771                     {
772                         uno::Reference< drawing::XShape > xCurrShape(xPage->getByIndex(nShapeNum), uno::UNO_QUERY);
773                         if (!xCurrShape.is())
774                             continue;
775 
776                         uno::Reference< beans::XPropertySet > xPropSet(xCurrShape, uno::UNO_QUERY);
777                         if (!xPropSet.is())
778                             continue;
779 
780                         uno::Reference< beans::XPropertySetInfo> xInfo = xPropSet->getPropertySetInfo();
781                         if (!xInfo.is())
782                             continue;
783 
784                         OUString sShapeName;
785                         if (xInfo->hasPropertyByName("Name"))
786                         {
787                             uno::Any aAnyShapeName = xPropSet->getPropertyValue("Name");
788                             aAnyShapeName >>= sShapeName;
789                         }
790                         else
791                             continue;
792 
793                         // Rectangle redaction
794                         if (sShapeName == "RectangleRedactionShape"
795                                 && xInfo->hasPropertyByName("FillTransparence") && xInfo->hasPropertyByName("FillColor"))
796                         {
797                             xPropSet->setPropertyValue("FillTransparence", css::uno::makeAny(static_cast<sal_Int16>(0)));
798                             if (sRedactionStyle == "White")
799                             {
800                                 xPropSet->setPropertyValue("FillColor", css::uno::makeAny(COL_WHITE));
801                                 xPropSet->setPropertyValue("LineStyle", css::uno::makeAny(css::drawing::LineStyle::LineStyle_SOLID));
802                                 xPropSet->setPropertyValue("LineColor", css::uno::makeAny(COL_BLACK));
803                             }
804                             else
805                             {
806                                 xPropSet->setPropertyValue("FillColor", css::uno::makeAny(COL_BLACK));
807                                 xPropSet->setPropertyValue("LineStyle", css::uno::makeAny(css::drawing::LineStyle::LineStyle_NONE));
808                             }
809                         }
810                         // Freeform redaction
811                         else if (sShapeName == "FreeformRedactionShape"
812                                  && xInfo->hasPropertyByName("LineTransparence") && xInfo->hasPropertyByName("LineColor"))
813                         {
814                             xPropSet->setPropertyValue("LineTransparence", css::uno::makeAny(static_cast<sal_Int16>(0)));
815 
816                             if (sRedactionStyle == "White")
817                             {
818                                 xPropSet->setPropertyValue("LineColor", css::uno::makeAny(COL_WHITE));
819                             }
820                             else
821                             {
822                                 xPropSet->setPropertyValue("LineColor", css::uno::makeAny(COL_BLACK));
823                             }
824                         }
825                     }
826                 }
827             }
828         }
829             [[fallthrough]];
830         case SID_EXPORTDOCASPDF:
831             bIsPDFExport = true;
832             [[fallthrough]];
833         case SID_EXPORTDOCASEPUB:
834         case SID_DIRECTEXPORTDOCASEPUB:
835         case SID_EXPORTDOC:
836         case SID_SAVEASDOC:
837         case SID_SAVEASREMOTE:
838         case SID_SAVEDOC:
839         {
840             // derived class may decide to abort this
841             if( !QuerySlotExecutable( nId ) )
842             {
843                 rReq.SetReturnValue( SfxBoolItem( 0, false ) );
844                 return;
845             }
846 
847             //!! detailed analysis of an error code
848             SfxObjectShellRef xLock( this );
849 
850             // the model can not be closed till the end of this method
851             // if somebody tries to close it during this time the model will be closed
852             // at the end of the method
853             aModelGuard.Init_Impl( uno::Reference< util::XCloseable >( GetModel(), uno::UNO_QUERY ) );
854 
855             ErrCode nErrorCode = ERRCODE_NONE;
856 
857             // by default versions should be preserved always except in case of an explicit
858             // SaveAs via GUI, so the flag must be set accordingly
859             pImpl->bPreserveVersions = (nId == SID_SAVEDOC);
860             try
861             {
862                 SfxErrorContext aEc( ERRCTX_SFX_SAVEASDOC, GetTitle() ); // ???
863 
864                 if ( nId == SID_SAVEASDOC || nId == SID_SAVEASREMOTE )
865                 {
866                     // in case of plugin mode the SaveAs operation means SaveTo
867                     const SfxBoolItem* pViewOnlyItem = SfxItemSet::GetItem<SfxBoolItem>(GetMedium()->GetItemSet(), SID_VIEWONLY, false);
868                     if ( pViewOnlyItem && pViewOnlyItem->GetValue() )
869                         rReq.AppendItem( SfxBoolItem( SID_SAVETO, true ) );
870                 }
871 
872                 // TODO/LATER: do the following GUI related actions in standalone method
873 
874                 // Introduce a status indicator for GUI operation
875                 const SfxUnoAnyItem* pStatusIndicatorItem = rReq.GetArg<SfxUnoAnyItem>(SID_PROGRESS_STATUSBAR_CONTROL);
876                 if ( !pStatusIndicatorItem )
877                 {
878                     // get statusindicator
879                     uno::Reference< task::XStatusIndicator > xStatusIndicator;
880                     uno::Reference < frame::XController > xCtrl( GetModel()->getCurrentController() );
881                     if ( xCtrl.is() )
882                     {
883                         uno::Reference< task::XStatusIndicatorFactory > xStatFactory( xCtrl->getFrame(), uno::UNO_QUERY );
884                         if( xStatFactory.is() )
885                             xStatusIndicator = xStatFactory->createStatusIndicator();
886                     }
887 
888                     OSL_ENSURE( xStatusIndicator.is(), "Can not retrieve default status indicator!" );
889 
890                     if ( xStatusIndicator.is() )
891                     {
892                         SfxUnoAnyItem aStatIndItem( SID_PROGRESS_STATUSBAR_CONTROL, uno::makeAny( xStatusIndicator ) );
893 
894                         if ( nId == SID_SAVEDOC )
895                         {
896                             // in case of saving it is not possible to transport the parameters from here
897                             // but it is not clear here whether the saving will be done or saveAs operation
898                             GetMedium()->GetItemSet()->Put( aStatIndItem );
899                         }
900 
901                         rReq.AppendItem( aStatIndItem );
902                     }
903                 }
904                 else if ( nId == SID_SAVEDOC )
905                 {
906                     // in case of saving it is not possible to transport the parameters from here
907                     // but it is not clear here whether the saving will be done or saveAs operation
908                     GetMedium()->GetItemSet()->Put( *pStatusIndicatorItem );
909                 }
910 
911                 // Introduce an interaction handler for GUI operation
912                 const SfxUnoAnyItem* pInteractionHandlerItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER);
913                 if ( !pInteractionHandlerItem )
914                 {
915                     uno::Reference<css::awt::XWindow> xParentWindow;
916                     uno::Reference<frame::XController> xCtrl(GetModel()->getCurrentController());
917                     if (xCtrl.is())
918                         xParentWindow = xCtrl->getFrame()->getContainerWindow();
919 
920                     uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
921 
922                     uno::Reference< task::XInteractionHandler2 > xInteract(
923                         task::InteractionHandler::createWithParent(xContext, xParentWindow) );
924 
925                     SfxUnoAnyItem aInteractionItem( SID_INTERACTIONHANDLER, uno::makeAny( xInteract ) );
926                     if ( nId == SID_SAVEDOC )
927                     {
928                         // in case of saving it is not possible to transport the parameters from here
929                         // but it is not clear here whether the saving will be done or saveAs operation
930                         GetMedium()->GetItemSet()->Put( aInteractionItem );
931                     }
932 
933                     rReq.AppendItem( aInteractionItem );
934                 }
935                 else if ( nId == SID_SAVEDOC )
936                 {
937                     // in case of saving it is not possible to transport the parameters from here
938                     // but it is not clear here whether the saving will be done or saveAs operation
939                     GetMedium()->GetItemSet()->Put( *pInteractionHandlerItem );
940                 }
941 
942 
943                 const SfxStringItem* pOldPasswordItem = SfxItemSet::GetItem<SfxStringItem>(GetMedium()->GetItemSet(), SID_PASSWORD, false);
944                 const SfxUnoAnyItem* pOldEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(GetMedium()->GetItemSet(), SID_ENCRYPTIONDATA, false);
945                 bool bPreselectPassword = (pOldPasswordItem && pOldEncryptionDataItem);
946 
947                 uno::Sequence< beans::PropertyValue > aDispatchArgs;
948                 if ( rReq.GetArgs() )
949                     TransformItems( nId,
950                                     *rReq.GetArgs(),
951                                      aDispatchArgs );
952 
953                 bool bForceSaveAs = nId == SID_SAVEDOC && IsReadOnlyMedium();
954                 const SfxSlot* pSlot = GetModule()->GetSlotPool()->GetSlot( bForceSaveAs ? SID_SAVEASDOC : nId );
955                 if ( !pSlot )
956                     throw uno::Exception("no slot", nullptr);
957 
958                 SfxStoringHelper aHelper;
959 
960                 if ( QueryHiddenInformation( bIsPDFExport ? HiddenWarningFact::WhenCreatingPDF : HiddenWarningFact::WhenSaving, nullptr ) != RET_YES )
961                 {
962                     // the user has decided not to store the document
963                     throw task::ErrorCodeIOException(
964                         "SfxObjectShell::ExecFile_Impl: ERRCODE_IO_ABORT",
965                         uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT));
966                 }
967 
968                 aHelper.GUIStoreModel( GetModel(),
969                                        OUString::createFromAscii( pSlot->GetUnoName() ),
970                                        aDispatchArgs,
971                                        bPreselectPassword,
972                                        GetDocumentSignatureState() );
973 
974 
975                 // merge aDispatchArgs to the request
976                 SfxAllItemSet aResultParams( GetPool() );
977                 TransformParameters( nId,
978                                      aDispatchArgs,
979                                      aResultParams );
980                 rReq.SetArgs( aResultParams );
981 
982                 // the StoreAsURL/StoreToURL method have called this method with false
983                 // so it has to be restored to true here since it is a call from GUI
984                 GetMedium()->SetUpdatePickList( true );
985 
986                 // TODO: in future it must be done in following way
987                 // if document is opened from GUI, it immediately appears in the picklist
988                 // if the document is a new one then it appears in the picklist immediately
989                 // after SaveAs operation triggered from GUI
990             }
991             catch( const task::ErrorCodeIOException& aErrorEx )
992             {
993                 TOOLS_WARN_EXCEPTION( "sfx.doc", "Fatal IO error during save");
994                 nErrorCode = ErrCode(aErrorEx.ErrCode);
995             }
996             catch( Exception& )
997             {
998                 nErrorCode = ERRCODE_IO_GENERAL;
999             }
1000 
1001             // by default versions should be preserved always except in case of an explicit
1002             // SaveAs via GUI, so the flag must be reset to guarantee this
1003             pImpl->bPreserveVersions = true;
1004             ErrCode lErr=GetErrorCode();
1005 
1006             if ( !lErr && nErrorCode )
1007                 lErr = nErrorCode;
1008 
1009             if ( lErr && nErrorCode == ERRCODE_NONE )
1010             {
1011                 const SfxBoolItem* pWarnItem = rReq.GetArg<SfxBoolItem>(SID_FAIL_ON_WARNING);
1012                 if ( pWarnItem && pWarnItem->GetValue() )
1013                     nErrorCode = lErr;
1014             }
1015 
1016             // may be nErrorCode should be shown in future
1017             if ( lErr != ERRCODE_IO_ABORT )
1018             {
1019                 if (comphelper::LibreOfficeKit::isActive())
1020                     sendErrorToLOK(lErr);
1021                 else
1022                 {
1023                     SfxErrorContext aEc(ERRCTX_SFX_SAVEASDOC,GetTitle());
1024                     ErrorHandler::HandleError(lErr, pDialogParent);
1025                 }
1026             }
1027 
1028             if (nId == SID_DIRECTEXPORTDOCASPDF &&
1029                     SfxRedactionHelper::isRedactMode(rReq))
1030             {
1031                 // Return the finalized redaction shapes back to normal (gray & transparent)
1032                 uno::Reference< lang::XComponent > xComponent( GetCurrentComponent(), uno::UNO_QUERY );
1033                 if (!xComponent.is())
1034                     return;
1035 
1036                 uno::Reference< lang::XServiceInfo > xServiceInfo( xComponent, uno::UNO_QUERY);
1037 
1038                 // Redaction finalization takes place in Draw
1039                 if ( xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.drawing.DrawingDocument") )
1040                 {
1041                     // Access the draw pages
1042                     uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(xComponent, uno::UNO_QUERY);
1043                     uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
1044 
1045                     sal_Int32 nPageCount = xDrawPages->getCount();
1046                     for (sal_Int32 nPageNum = 0; nPageNum < nPageCount; ++nPageNum)
1047                     {
1048                         // Get the page
1049                         uno::Reference< drawing::XDrawPage > xPage( xDrawPages->getByIndex( nPageNum ), uno::UNO_QUERY );
1050 
1051                         if (!xPage.is())
1052                             continue;
1053 
1054                         // Go through all shapes
1055                         sal_Int32 nShapeCount = xPage->getCount();
1056                         for (sal_Int32 nShapeNum = 0; nShapeNum < nShapeCount; ++nShapeNum)
1057                         {
1058                             uno::Reference< drawing::XShape > xCurrShape(xPage->getByIndex(nShapeNum), uno::UNO_QUERY);
1059                             if (!xCurrShape.is())
1060                                 continue;
1061 
1062                             uno::Reference< beans::XPropertySet > xPropSet(xCurrShape, uno::UNO_QUERY);
1063                             if (!xPropSet.is())
1064                                 continue;
1065 
1066                             uno::Reference< beans::XPropertySetInfo> xInfo = xPropSet->getPropertySetInfo();
1067                             if (!xInfo.is())
1068                                 continue;
1069 
1070                             // Not a shape we converted?
1071                             if (!xInfo->hasPropertyByName("Name"))
1072                                 continue;
1073 
1074                             OUString sShapeName;
1075                             if (xInfo->hasPropertyByName("Name"))
1076                             {
1077                                 uno::Any aAnyShapeName = xPropSet->getPropertyValue("Name");
1078                                 aAnyShapeName >>= sShapeName;
1079                             }
1080                             else
1081                                 continue;
1082 
1083                             // Rectangle redaction
1084                             if (sShapeName == "RectangleRedactionShape"
1085                                     && xInfo->hasPropertyByName("FillTransparence") && xInfo->hasPropertyByName("FillColor"))
1086                             {
1087                                 xPropSet->setPropertyValue("FillTransparence", css::uno::makeAny(static_cast<sal_Int16>(50)));
1088                                 xPropSet->setPropertyValue("FillColor", css::uno::makeAny(COL_GRAY7));
1089                                 xPropSet->setPropertyValue("LineStyle", css::uno::makeAny(css::drawing::LineStyle::LineStyle_NONE));
1090 
1091                             }
1092                             // Freeform redaction
1093                             else if (sShapeName == "FreeformRedactionShape")
1094                             {
1095                                 xPropSet->setPropertyValue("LineTransparence", css::uno::makeAny(static_cast<sal_Int16>(50)));
1096                                 xPropSet->setPropertyValue("LineColor", css::uno::makeAny(COL_GRAY7));
1097                             }
1098                         }
1099                     }
1100 
1101 
1102                 }
1103             }
1104 
1105             if ( nId == SID_EXPORTDOCASPDF )
1106             {
1107                 // This function is used by the SendMail function that needs information if an export
1108                 // file was written or not. This could be due to cancellation of the export
1109                 // or due to an error. So IO abort must be handled like an error!
1110                 nErrorCode = ( lErr != ERRCODE_IO_ABORT ) && ( nErrorCode == ERRCODE_NONE ) ? nErrorCode : lErr;
1111             }
1112 
1113             if ( ( nId == SID_SAVEASDOC || nId == SID_SAVEASREMOTE ) && nErrorCode == ERRCODE_NONE )
1114             {
1115                 const SfxBoolItem* saveTo = rReq.GetArg<SfxBoolItem>(SID_SAVETO);
1116                 if (saveTo == nullptr || !saveTo->GetValue())
1117                 {
1118                     SfxViewFrame *pFrame = GetFrame();
1119                     if (pFrame)
1120                         pFrame->RemoveInfoBar(u"readonly");
1121                     SetReadOnlyUI(false);
1122                 }
1123             }
1124 
1125             rReq.SetReturnValue( SfxBoolItem(0, nErrorCode == ERRCODE_NONE ) );
1126 
1127             ResetError();
1128 
1129             Invalidate();
1130             break;
1131         }
1132 
1133         case SID_SAVEACOPY:
1134         {
1135             SfxAllItemSet aArgs( GetPool() );
1136             aArgs.Put( SfxBoolItem( SID_SAVEACOPYITEM, true ) );
1137             SfxRequest aSaveACopyReq( SID_EXPORTDOC, SfxCallMode::API, aArgs );
1138             ExecFile_Impl( aSaveACopyReq );
1139             if ( !aSaveACopyReq.IsDone() )
1140             {
1141                 rReq.Ignore();
1142                 return;
1143             }
1144             break;
1145         }
1146 
1147         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1148 
1149         case SID_CLOSEDOC:
1150         {
1151             // Evaluate Parameter
1152             const SfxBoolItem* pSaveItem = rReq.GetArg<SfxBoolItem>(SID_CLOSEDOC_SAVE);
1153             const SfxStringItem* pNameItem = rReq.GetArg<SfxStringItem>(SID_CLOSEDOC_FILENAME);
1154             if ( pSaveItem )
1155             {
1156                 if ( pSaveItem->GetValue() )
1157                 {
1158                     if ( !pNameItem )
1159                     {
1160 #if HAVE_FEATURE_SCRIPTING
1161                         SbxBase::SetError( ERRCODE_BASIC_WRONG_ARGS );
1162 #endif
1163                         rReq.Ignore();
1164                         return;
1165                     }
1166                     SfxAllItemSet aArgs( GetPool() );
1167                     SfxStringItem aTmpItem( SID_FILE_NAME, pNameItem->GetValue() );
1168                     aArgs.Put( aTmpItem, aTmpItem.Which() );
1169                     SfxRequest aSaveAsReq( SID_SAVEASDOC, SfxCallMode::API, aArgs );
1170                     ExecFile_Impl( aSaveAsReq );
1171                     if ( !aSaveAsReq.IsDone() )
1172                     {
1173                         rReq.Ignore();
1174                         return;
1175                     }
1176                 }
1177                 else
1178                     SetModified(false);
1179             }
1180 
1181             // Cancelled by the user?
1182             if (!PrepareClose())
1183             {
1184                 rReq.SetReturnValue( SfxBoolItem(0, false) );
1185                 rReq.Done();
1186                 return;
1187             }
1188 
1189             SetModified( false );
1190             ErrCode lErr = GetErrorCode();
1191 
1192             if (comphelper::LibreOfficeKit::isActive())
1193                 sendErrorToLOK(lErr);
1194             else
1195                 ErrorHandler::HandleError(lErr, pDialogParent);
1196 
1197             rReq.SetReturnValue( SfxBoolItem(0, true) );
1198             rReq.Done();
1199             rReq.ReleaseArgs(); // because the pool is destroyed in Close
1200             DoClose();
1201             return;
1202         }
1203 
1204         // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1205         case SID_DOCTEMPLATE:
1206         {
1207             // save as document templates
1208             SfxSaveAsTemplateDialog aDlg(pDialogParent, GetModel());
1209             (void)aDlg.run();
1210             break;
1211         }
1212 
1213         case SID_CHECKOUT:
1214         {
1215             CheckOut( );
1216             break;
1217         }
1218         case SID_CANCELCHECKOUT:
1219         {
1220             std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr,
1221                                                       VclMessageType::Question, VclButtonsType::YesNo, SfxResId(STR_QUERY_CANCELCHECKOUT)));
1222             if (xBox->run() == RET_YES)
1223             {
1224                 CancelCheckOut( );
1225 
1226                 // Reload the document as we may still have local changes
1227                 SfxViewFrame *pFrame = GetFrame();
1228                 if ( pFrame )
1229                     pFrame->GetDispatcher()->Execute(SID_RELOAD);
1230             }
1231             break;
1232         }
1233         case SID_CHECKIN:
1234         {
1235             CheckIn( );
1236             break;
1237         }
1238     }
1239 
1240     // Prevent entry in the Pick-lists
1241     if ( rReq.IsAPI() )
1242         GetMedium()->SetUpdatePickList( false );
1243 
1244     // Ignore()-branches have already returned
1245     rReq.Done();
1246 }
1247 
1248 
GetState_Impl(SfxItemSet & rSet)1249 void SfxObjectShell::GetState_Impl(SfxItemSet &rSet)
1250 {
1251     SfxWhichIter aIter( rSet );
1252 
1253     for ( sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich() )
1254     {
1255         switch ( nWhich )
1256         {
1257             case SID_DOCTEMPLATE :
1258             {
1259                 if ( isExportLocked())
1260                     rSet.DisableItem( nWhich );
1261                 break;
1262             }
1263 
1264             case SID_CHECKOUT:
1265                 {
1266                     bool bShow = false;
1267                     Reference< XCmisDocument > xCmisDoc( GetModel(), uno::UNO_QUERY );
1268                     const uno::Sequence< document::CmisProperty> aCmisProperties = xCmisDoc->getCmisProperties();
1269 
1270                     if ( xCmisDoc->isVersionable( ) && aCmisProperties.hasElements( ) )
1271                     {
1272                         // Loop over the CMIS Properties to find cmis:isVersionSeriesCheckedOut
1273                         bool bIsGoogleFile = false;
1274                         bool bCheckedOut = false;
1275                         for ( const auto& rCmisProperty : aCmisProperties )
1276                         {
1277                             if ( rCmisProperty.Id == "cmis:isVersionSeriesCheckedOut" )
1278                             {
1279                                 uno::Sequence< sal_Bool > bTmp;
1280                                 rCmisProperty.Value >>= bTmp;
1281                                 bCheckedOut = bTmp[0];
1282                             }
1283                             // using title to know if it's a Google Drive file
1284                             // maybe there's a safer way.
1285                             if ( rCmisProperty.Name == "title" )
1286                                 bIsGoogleFile = true;
1287                         }
1288                         bShow = !bCheckedOut && !bIsGoogleFile;
1289                     }
1290 
1291                     if ( !bShow )
1292                     {
1293                         rSet.DisableItem( nWhich );
1294                         rSet.Put( SfxVisibilityItem( nWhich, false ) );
1295                     }
1296                 }
1297                 break;
1298 
1299             case SID_CANCELCHECKOUT:
1300             case SID_CHECKIN:
1301                 {
1302                     bool bShow = false;
1303                     Reference< XCmisDocument > xCmisDoc( GetModel(), uno::UNO_QUERY );
1304                     uno::Sequence< document::CmisProperty> aCmisProperties = xCmisDoc->getCmisProperties( );
1305 
1306                     if ( xCmisDoc->isVersionable( ) && aCmisProperties.hasElements( ) )
1307                     {
1308                         // Loop over the CMIS Properties to find cmis:isVersionSeriesCheckedOut
1309                         bool bCheckedOut = false;
1310                         auto pProp = std::find_if(aCmisProperties.begin(), aCmisProperties.end(),
1311                             [](const document::CmisProperty& rProp) { return rProp.Id == "cmis:isVersionSeriesCheckedOut"; });
1312                         if (pProp != aCmisProperties.end())
1313                         {
1314                             uno::Sequence< sal_Bool > bTmp;
1315                             pProp->Value >>= bTmp;
1316                             bCheckedOut = bTmp[0];
1317                         }
1318                         bShow = bCheckedOut;
1319                     }
1320 
1321                     if ( !bShow )
1322                     {
1323                         rSet.DisableItem( nWhich );
1324                         rSet.Put( SfxVisibilityItem( nWhich, false ) );
1325                     }
1326                 }
1327                 break;
1328 
1329             case SID_VERSION:
1330                 {
1331                     SfxObjectShell *pDoc = this;
1332                     SfxViewFrame* pFrame = GetFrame();
1333                     if ( !pFrame )
1334                         pFrame = SfxViewFrame::GetFirst( this );
1335 
1336                     if ( !pFrame || !pDoc->HasName() ||
1337                         !IsOwnStorageFormat( *pDoc->GetMedium() ) )
1338                         rSet.DisableItem( nWhich );
1339                     break;
1340                 }
1341             case SID_SAVEDOC:
1342                 {
1343                     if ( IsReadOnly() || isSaveLocked())
1344                     {
1345                         rSet.DisableItem(nWhich);
1346                         break;
1347                     }
1348                     rSet.Put(SfxStringItem(nWhich, SfxResId(STR_SAVEDOC)));
1349                 }
1350                 break;
1351 
1352             case SID_DOCINFO:
1353                 break;
1354 
1355             case SID_CLOSEDOC:
1356             {
1357                 rSet.Put(SfxStringItem(nWhich, SfxResId(STR_CLOSEDOC)));
1358                 break;
1359             }
1360 
1361             case SID_SAVEASDOC:
1362             {
1363                 if (!(pImpl->nLoadedFlags & SfxLoadedFlags::MAINDOCUMENT)
1364                     || isExportLocked())
1365                 {
1366                     rSet.DisableItem( nWhich );
1367                     break;
1368                 }
1369                 if ( /*!pCombinedFilters ||*/ !GetMedium() )
1370                     rSet.DisableItem( nWhich );
1371                 else
1372                     rSet.Put( SfxStringItem( nWhich, SfxResId(STR_SAVEASDOC) ) );
1373                 break;
1374             }
1375 
1376             case SID_SAVEACOPY:
1377             {
1378                 if (!(pImpl->nLoadedFlags & SfxLoadedFlags::MAINDOCUMENT) || isExportLocked())
1379                 {
1380                     rSet.DisableItem( nWhich );
1381                     break;
1382                 }
1383                 if ( /*!pCombinedFilters ||*/ !GetMedium() )
1384                     rSet.DisableItem( nWhich );
1385                 else
1386                     rSet.Put( SfxStringItem( nWhich, SfxResId(STR_SAVEACOPY) ) );
1387                 break;
1388             }
1389 
1390             case SID_EXPORTDOC:
1391             case SID_EXPORTDOCASPDF:
1392             case SID_DIRECTEXPORTDOCASPDF:
1393             case SID_EXPORTDOCASEPUB:
1394             case SID_DIRECTEXPORTDOCASEPUB:
1395             case SID_REDACTDOC:
1396             case SID_AUTOREDACTDOC:
1397             case SID_SAVEASREMOTE:
1398             {
1399                 if (isExportLocked())
1400                     rSet.DisableItem( nWhich );
1401                 break;
1402             }
1403 
1404             case SID_DOC_MODIFIED:
1405             {
1406                 rSet.Put( SfxBoolItem( SID_DOC_MODIFIED, IsModified() ) );
1407                 break;
1408             }
1409 
1410             case SID_MODIFIED:
1411             {
1412                 rSet.Put( SfxBoolItem( SID_MODIFIED, IsModified() ) );
1413                 break;
1414             }
1415 
1416             case SID_DOCINFO_TITLE:
1417             {
1418                 rSet.Put( SfxStringItem(
1419                     SID_DOCINFO_TITLE, getDocProperties()->getTitle() ) );
1420                 break;
1421             }
1422             case SID_FILE_NAME:
1423             {
1424                 if( GetMedium() && HasName() )
1425                     rSet.Put( SfxStringItem(
1426                         SID_FILE_NAME, GetMedium()->GetName() ) );
1427                 break;
1428             }
1429             case SID_SIGNATURE:
1430             {
1431                 SfxViewFrame *pFrame = SfxViewFrame::GetFirst(this);
1432                 if ( pFrame )
1433                 {
1434                     SignatureState eState = GetDocumentSignatureState();
1435                     InfobarType aInfobarType(InfobarType::INFO);
1436                     OUString sMessage("");
1437 
1438                     switch (eState)
1439                     {
1440                     case SignatureState::BROKEN:
1441                         sMessage = SfxResId(STR_SIGNATURE_BROKEN);
1442                         aInfobarType = InfobarType::DANGER;
1443                         break;
1444                     case SignatureState::INVALID:
1445                         sMessage = SfxResId(STR_SIGNATURE_INVALID);
1446                         // Warning only, I've tried Danger and it looked too scary
1447                         aInfobarType = InfobarType::WARNING;
1448                         break;
1449                     case SignatureState::NOTVALIDATED:
1450                         sMessage = SfxResId(STR_SIGNATURE_NOTVALIDATED);
1451                         aInfobarType = InfobarType::WARNING;
1452                         break;
1453                     case SignatureState::PARTIAL_OK:
1454                         sMessage = SfxResId(STR_SIGNATURE_PARTIAL_OK);
1455                         aInfobarType = InfobarType::WARNING;
1456                         break;
1457                     case SignatureState::OK:
1458                         sMessage = SfxResId(STR_SIGNATURE_OK);
1459                         aInfobarType = InfobarType::INFO;
1460                         break;
1461                     case SignatureState::NOTVALIDATED_PARTIAL_OK:
1462                         sMessage = SfxResId(STR_SIGNATURE_NOTVALIDATED_PARTIAL_OK);
1463                         aInfobarType = InfobarType::WARNING;
1464                         break;
1465                     //FIXME SignatureState::Unknown, own message?
1466                     default:
1467                         break;
1468                     }
1469 
1470                     // new info bar
1471                     if ( !pFrame->HasInfoBarWithID(u"signature") )
1472                     {
1473                         if ( !sMessage.isEmpty() )
1474                         {
1475                             auto pInfoBar = pFrame->AppendInfoBar("signature", "", sMessage, aInfobarType);
1476                             if (pInfoBar == nullptr || pInfoBar->isDisposed())
1477                                 return;
1478                             weld::Button& rBtn = pInfoBar->addButton();
1479                             rBtn.set_label(SfxResId(STR_SIGNATURE_SHOW));
1480                             rBtn.connect_clicked(LINK(this, SfxObjectShell, SignDocumentHandler));
1481                         }
1482                     }
1483                     else // info bar exists already
1484                     {
1485                         if ( eState == SignatureState::NOSIGNATURES )
1486                             pFrame->RemoveInfoBar(u"signature");
1487                         else
1488                             pFrame->UpdateInfoBar(u"signature", "", sMessage, aInfobarType);
1489                     }
1490                 }
1491 
1492                 rSet.Put( SfxUInt16Item( SID_SIGNATURE, static_cast<sal_uInt16>(GetDocumentSignatureState()) ) );
1493                 break;
1494             }
1495             case SID_MACRO_SIGNATURE:
1496             {
1497                 // the slot makes sense only if there is a macro in the document
1498                 if ( pImpl->documentStorageHasMacros() || pImpl->aMacroMode.hasMacroLibrary() )
1499                     rSet.Put( SfxUInt16Item( SID_MACRO_SIGNATURE, static_cast<sal_uInt16>(GetScriptingSignatureState()) ) );
1500                 else
1501                     rSet.DisableItem( nWhich );
1502                 break;
1503             }
1504             case SID_DOC_REPAIR:
1505             {
1506                 SfxUndoManager* pIUndoMgr = GetUndoManager();
1507                 if (pIUndoMgr)
1508                     rSet.Put( SfxBoolItem(nWhich, pIUndoMgr->IsEmptyActions()) );
1509                 else
1510                     rSet.DisableItem( nWhich );
1511                 break;
1512             }
1513         }
1514     }
1515 }
1516 
IMPL_LINK_NOARG(SfxObjectShell,SignDocumentHandler,weld::Button &,void)1517 IMPL_LINK_NOARG(SfxObjectShell, SignDocumentHandler, weld::Button&, void)
1518 {
1519     SfxViewFrame *pFrame = SfxViewFrame::GetFirst(this);
1520     if (!pFrame)
1521     {
1522         SAL_WARN("sfx.appl", "There should be some SfxViewFrame associated here");
1523         return;
1524     }
1525     pFrame->MakeActive_Impl(false);
1526     GetDispatcher()->Execute(SID_SIGNATURE);
1527 }
1528 
ExecProps_Impl(SfxRequest & rReq)1529 void SfxObjectShell::ExecProps_Impl(SfxRequest &rReq)
1530 {
1531     switch ( rReq.GetSlot() )
1532     {
1533         case SID_MODIFIED:
1534         {
1535             SetModified( rReq.GetArgs()->Get(SID_MODIFIED).GetValue() );
1536             rReq.Done();
1537             break;
1538         }
1539 
1540         case SID_DOCTITLE:
1541             SetTitle( rReq.GetArgs()->Get(SID_DOCTITLE).GetValue() );
1542             rReq.Done();
1543             break;
1544 
1545         case SID_DOCINFO_AUTHOR :
1546             getDocProperties()->setAuthor( static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(rReq.GetSlot())).GetValue() );
1547             break;
1548 
1549         case SID_DOCINFO_COMMENTS :
1550             getDocProperties()->setDescription( static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(rReq.GetSlot())).GetValue() );
1551             break;
1552 
1553         case SID_DOCINFO_KEYWORDS :
1554         {
1555             const OUString aStr = static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(rReq.GetSlot())).GetValue();
1556             getDocProperties()->setKeywords(
1557                 ::comphelper::string::convertCommaSeparated(aStr) );
1558             break;
1559         }
1560     }
1561 }
1562 
1563 
StateProps_Impl(SfxItemSet & rSet)1564 void SfxObjectShell::StateProps_Impl(SfxItemSet &rSet)
1565 {
1566     SfxWhichIter aIter(rSet);
1567     for ( sal_uInt16 nSID = aIter.FirstWhich(); nSID; nSID = aIter.NextWhich() )
1568     {
1569         switch ( nSID )
1570         {
1571             case SID_DOCINFO_AUTHOR :
1572             {
1573                 rSet.Put( SfxStringItem( nSID,
1574                             getDocProperties()->getAuthor() ) );
1575                 break;
1576             }
1577 
1578             case SID_DOCINFO_COMMENTS :
1579             {
1580                 rSet.Put( SfxStringItem( nSID,
1581                             getDocProperties()->getDescription()) );
1582                 break;
1583             }
1584 
1585             case SID_DOCINFO_KEYWORDS :
1586             {
1587                 rSet.Put( SfxStringItem( nSID, ::comphelper::string::
1588                     convertCommaSeparated(getDocProperties()->getKeywords())) );
1589                 break;
1590             }
1591 
1592             case SID_DOCPATH:
1593             {
1594                 OSL_FAIL( "Not supported anymore!" );
1595                 break;
1596             }
1597 
1598             case SID_DOCFULLNAME:
1599             {
1600                 rSet.Put( SfxStringItem( SID_DOCFULLNAME, GetTitle(SFX_TITLE_FULLNAME) ) );
1601                 break;
1602             }
1603 
1604             case SID_DOCTITLE:
1605             {
1606                 rSet.Put( SfxStringItem( SID_DOCTITLE, GetTitle() ) );
1607                 break;
1608             }
1609 
1610             case SID_DOC_READONLY:
1611             {
1612                 rSet.Put( SfxBoolItem( SID_DOC_READONLY, IsReadOnly() ) );
1613                 break;
1614             }
1615 
1616             case SID_DOC_SAVED:
1617             {
1618                 rSet.Put( SfxBoolItem( SID_DOC_SAVED, !IsModified() ) );
1619                 break;
1620             }
1621 
1622             case SID_CLOSING:
1623             {
1624                 rSet.Put( SfxBoolItem( SID_CLOSING, false ) );
1625                 break;
1626             }
1627 
1628             case SID_DOC_LOADING:
1629                 rSet.Put( SfxBoolItem( nSID, ! ( pImpl->nLoadedFlags & SfxLoadedFlags::MAINDOCUMENT ) ) );
1630                 break;
1631 
1632             case SID_IMG_LOADING:
1633                 rSet.Put( SfxBoolItem( nSID, ! ( pImpl->nLoadedFlags & SfxLoadedFlags::IMAGES ) ) );
1634                 break;
1635         }
1636     }
1637 }
1638 
1639 
ExecView_Impl(SfxRequest & rReq)1640 void SfxObjectShell::ExecView_Impl(SfxRequest &rReq)
1641 {
1642     switch ( rReq.GetSlot() )
1643     {
1644         case SID_ACTIVATE:
1645         {
1646             SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this );
1647             if ( pFrame )
1648                 pFrame->GetFrame().Appear();
1649             rReq.SetReturnValue( SfxObjectItem( 0, pFrame ) );
1650             rReq.Done();
1651             break;
1652         }
1653     }
1654 }
1655 
1656 
StateView_Impl(SfxItemSet &)1657 void SfxObjectShell::StateView_Impl(SfxItemSet& /*rSet*/)
1658 {
1659 }
1660 
1661 /// Does this ZIP storage have a signature stream?
HasSignatureStream(const uno::Reference<embed::XStorage> & xStorage)1662 static bool HasSignatureStream(const uno::Reference<embed::XStorage>& xStorage)
1663 {
1664     if (!xStorage.is())
1665         return false;
1666 
1667     if (xStorage->hasByName("META-INF"))
1668     {
1669         // ODF case.
1670         try
1671         {
1672             uno::Reference<embed::XStorage> xMetaInf
1673                 = xStorage->openStorageElement("META-INF", embed::ElementModes::READ);
1674             if (xMetaInf.is())
1675             {
1676                 return xMetaInf->hasByName("documentsignatures.xml")
1677                        || xMetaInf->hasByName("macrosignatures.xml")
1678                        || xMetaInf->hasByName("packagesignatures.xml");
1679             }
1680         }
1681         catch (const css::io::IOException&)
1682         {
1683             TOOLS_WARN_EXCEPTION("sfx.doc", "HasSignatureStream: failed to open META-INF");
1684         }
1685     }
1686 
1687     // OOXML case.
1688     return xStorage->hasByName("_xmlsignatures");
1689 }
1690 
GetDocumentSignatureInformation(bool bScriptingContent,const uno::Reference<security::XDocumentDigitalSignatures> & xSigner)1691 uno::Sequence< security::DocumentSignatureInformation > SfxObjectShell::GetDocumentSignatureInformation( bool bScriptingContent, const uno::Reference< security::XDocumentDigitalSignatures >& xSigner )
1692 {
1693     uno::Sequence< security::DocumentSignatureInformation > aResult;
1694     uno::Reference< security::XDocumentDigitalSignatures > xLocSigner = xSigner;
1695 
1696     bool bSupportsSigning = GetMedium() && GetMedium()->GetFilter() && GetMedium()->GetFilter()->GetSupportsSigning();
1697     if (GetMedium() && !GetMedium()->GetName().isEmpty() && ((IsOwnStorageFormat(*GetMedium()) && GetMedium()->GetStorage().is()) || bSupportsSigning))
1698     {
1699         try
1700         {
1701             if ( !xLocSigner.is() )
1702             {
1703                 OUString aVersion;
1704                 try
1705                 {
1706                     uno::Reference < beans::XPropertySet > xPropSet( GetStorage(), uno::UNO_QUERY_THROW );
1707                     xPropSet->getPropertyValue("Version") >>= aVersion;
1708                 }
1709                 catch( uno::Exception& )
1710                 {
1711                 }
1712 
1713                 xLocSigner.set( security::DocumentDigitalSignatures::createWithVersion(comphelper::getProcessComponentContext(), aVersion) );
1714 
1715             }
1716 
1717             if ( bScriptingContent )
1718                 aResult = xLocSigner->verifyScriptingContentSignatures( GetMedium()->GetZipStorageToSign_Impl(),
1719                                                                 uno::Reference< io::XInputStream >() );
1720             else
1721             {
1722                 if (GetMedium()->GetStorage(false).is())
1723                 {
1724                     // Something ZIP-based.
1725                     // Only call into xmlsecurity if we see a signature stream,
1726                     // as libxmlsec init is expensive.
1727                     if (HasSignatureStream(GetMedium()->GetZipStorageToSign_Impl()))
1728                         aResult = xLocSigner->verifyDocumentContentSignatures( GetMedium()->GetZipStorageToSign_Impl(),
1729                                                                         uno::Reference< io::XInputStream >() );
1730                 }
1731                 else
1732                 {
1733                     // Not ZIP-based, e.g. PDF.
1734 
1735                     // Create temp file if needed.
1736                     GetMedium()->CreateTempFile(/*bReplace=*/false);
1737 
1738                     std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(GetMedium()->GetName(), StreamMode::READ));
1739                     uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream));
1740                     uno::Reference<io::XInputStream> xInputStream(xStream, uno::UNO_QUERY);
1741                     aResult = xLocSigner->verifyDocumentContentSignatures(uno::Reference<embed::XStorage>(), xInputStream);
1742                 }
1743             }
1744         }
1745         catch( css::uno::Exception& )
1746         {
1747             TOOLS_WARN_EXCEPTION("sfx.doc", "Failed to get document signature information");
1748         }
1749     }
1750 
1751     return aResult;
1752 }
1753 
ImplGetSignatureState(bool bScriptingContent)1754 SignatureState SfxObjectShell::ImplGetSignatureState( bool bScriptingContent )
1755 {
1756     SignatureState* pState = bScriptingContent ? &pImpl->nScriptingSignatureState : &pImpl->nDocumentSignatureState;
1757 
1758     if ( *pState == SignatureState::UNKNOWN )
1759     {
1760         *pState = SignatureState::NOSIGNATURES;
1761 
1762         uno::Sequence< security::DocumentSignatureInformation > aInfos = GetDocumentSignatureInformation( bScriptingContent );
1763         *pState = DocumentSignatures::getSignatureState(aInfos);
1764     }
1765 
1766     if ( *pState == SignatureState::OK || *pState == SignatureState::NOTVALIDATED
1767         || *pState == SignatureState::PARTIAL_OK)
1768     {
1769         if ( IsModified() )
1770             *pState = SignatureState::INVALID;
1771     }
1772 
1773     return *pState;
1774 }
1775 
PrepareForSigning(weld::Window * pDialogParent)1776 bool SfxObjectShell::PrepareForSigning(weld::Window* pDialogParent)
1777 {
1778     // check whether the document is signed
1779     ImplGetSignatureState(); // document signature
1780     if (GetMedium() && GetMedium()->GetFilter() && GetMedium()->GetFilter()->IsOwnFormat())
1781         ImplGetSignatureState( true ); // script signature
1782     bool bHasSign = ( pImpl->nScriptingSignatureState != SignatureState::NOSIGNATURES || pImpl->nDocumentSignatureState != SignatureState::NOSIGNATURES );
1783 
1784     // the target ODF version on saving (only valid when signing ODF of course)
1785     SvtSaveOptions aSaveOpt;
1786     SvtSaveOptions::ODFSaneDefaultVersion nVersion = aSaveOpt.GetODFSaneDefaultVersion();
1787 
1788     // the document is not new and is not modified
1789     OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
1790 
1791     if ( IsModified() || !GetMedium() || GetMedium()->GetName().isEmpty()
1792       || (GetMedium()->GetFilter()->IsOwnFormat() && aODFVersion.compareTo(u"" ODFVER_012_TEXT) < 0 && !bHasSign))
1793     {
1794         // the document might need saving ( new, modified or in ODF1.1 format without signature )
1795 
1796         if (nVersion >= SvtSaveOptions::ODFSVER_012)
1797         {
1798             OUString sQuestion(bHasSign ? SfxResId(STR_XMLSEC_QUERY_SAVESIGNEDBEFORESIGN) : SfxResId(RID_SVXSTR_XMLSEC_QUERY_SAVEBEFORESIGN));
1799             std::unique_ptr<weld::MessageDialog> xQuestion(Application::CreateMessageDialog(pDialogParent,
1800                                                            VclMessageType::Question, VclButtonsType::YesNo, sQuestion));
1801 
1802 
1803             if (xQuestion->run() == RET_YES)
1804             {
1805                 sal_uInt16 nId = SID_SAVEDOC;
1806                 if ( !GetMedium() || GetMedium()->GetName().isEmpty() )
1807                     nId = SID_SAVEASDOC;
1808                 SfxRequest aSaveRequest( nId, SfxCallMode::SLOT, GetPool() );
1809                 //ToDo: Review. We needed to call SetModified, otherwise the document would not be saved.
1810                 SetModified();
1811                 ExecFile_Impl( aSaveRequest );
1812 
1813                 // Check if it is stored a format which supports signing
1814                 if (GetMedium() && GetMedium()->GetFilter() && !GetMedium()->GetName().isEmpty()
1815                     && ((!GetMedium()->GetFilter()->IsOwnFormat()
1816                          && !GetMedium()->GetFilter()->GetSupportsSigning())
1817                         || (GetMedium()->GetFilter()->IsOwnFormat()
1818                             && !GetMedium()->HasStorage_Impl())))
1819                 {
1820                     std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
1821                         pDialogParent, VclMessageType::Info, VclButtonsType::Ok,
1822                         SfxResId(STR_INFO_WRONGDOCFORMAT)));
1823 
1824                     xBox->run();
1825                     return false;
1826                 }
1827             }
1828             else
1829             {
1830                 // When the document is modified then we must not show the
1831                 // digital signatures dialog
1832                 // If we have come here then the user denied to save.
1833                 if (!bHasSign)
1834                     return false;
1835             }
1836         }
1837         else
1838         {
1839             std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pDialogParent,
1840                                                       VclMessageType::Warning, VclButtonsType::Ok, SfxResId(STR_XMLSEC_ODF12_EXPECTED)));
1841             xBox->run();
1842             return false;
1843         }
1844 
1845         if ( IsModified() || !GetMedium() || GetMedium()->GetName().isEmpty() )
1846             return false;
1847     }
1848 
1849     // the document is not modified currently, so it can not become modified after signing
1850     pImpl->m_bAllowModifiedBackAfterSigning = false;
1851     if ( IsEnableSetModified() )
1852     {
1853         EnableSetModified( false );
1854         pImpl->m_bAllowModifiedBackAfterSigning = true;
1855     }
1856 
1857     // we have to store to the original document, the original medium should be closed for this time
1858     if ( ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
1859     {
1860         GetMedium()->CloseAndRelease();
1861         return true;
1862     }
1863     return false;
1864 }
1865 
RecheckSignature(bool bAlsoRecheckScriptingSignature)1866 void SfxObjectShell::RecheckSignature(bool bAlsoRecheckScriptingSignature)
1867 {
1868     if (bAlsoRecheckScriptingSignature)
1869         pImpl->nScriptingSignatureState = SignatureState::UNKNOWN; // Re-Check
1870 
1871     pImpl->nDocumentSignatureState = SignatureState::UNKNOWN; // Re-Check
1872 
1873     Invalidate(SID_SIGNATURE);
1874     Invalidate(SID_MACRO_SIGNATURE);
1875     Broadcast(SfxHint(SfxHintId::TitleChanged));
1876 }
1877 
AfterSigning(bool bSignSuccess,bool bSignScriptingContent)1878 void SfxObjectShell::AfterSigning(bool bSignSuccess, bool bSignScriptingContent)
1879 {
1880     pImpl->m_bSavingForSigning = true;
1881     DoSaveCompleted( GetMedium() );
1882     pImpl->m_bSavingForSigning = false;
1883 
1884     if ( bSignSuccess )
1885         RecheckSignature(bSignScriptingContent);
1886 
1887     if ( pImpl->m_bAllowModifiedBackAfterSigning )
1888         EnableSetModified();
1889 }
1890 
CheckIsReadonly(bool bSignScriptingContent)1891 bool SfxObjectShell::CheckIsReadonly(bool bSignScriptingContent)
1892 {
1893     if (GetMedium()->IsOriginallyReadOnly())
1894     {
1895         // If the file is physically read-only, we just show the existing signatures
1896         try
1897         {
1898             OUString aODFVersion(
1899                 comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
1900             uno::Reference<security::XDocumentDigitalSignatures> xSigner(
1901                 security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
1902                     comphelper::getProcessComponentContext(), aODFVersion, HasValidSignatures()));
1903             if (bSignScriptingContent)
1904                 xSigner->showScriptingContentSignatures(GetMedium()->GetZipStorageToSign_Impl(),
1905                                                         uno::Reference<io::XInputStream>());
1906             else
1907             {
1908                 uno::Reference<embed::XStorage> xStorage = GetMedium()->GetZipStorageToSign_Impl();
1909                 if (xStorage.is())
1910                     xSigner->showDocumentContentSignatures(xStorage,
1911                                                            uno::Reference<io::XInputStream>());
1912                 else
1913                 {
1914                     std::unique_ptr<SvStream> pStream(
1915                         utl::UcbStreamHelper::CreateStream(GetName(), StreamMode::READ));
1916                     uno::Reference<io::XInputStream> xStream(new utl::OStreamWrapper(*pStream));
1917                     xSigner->showDocumentContentSignatures(uno::Reference<embed::XStorage>(),
1918                                                            xStream);
1919                 }
1920             }
1921         }
1922         catch (const uno::Exception&)
1923         {
1924             SAL_WARN("sfx.doc", "Couldn't use signing functionality!");
1925         }
1926         return true;
1927     }
1928     return false;
1929 }
1930 
HasValidSignatures() const1931 bool SfxObjectShell::HasValidSignatures() const
1932 {
1933     return pImpl->nDocumentSignatureState == SignatureState::OK
1934            || pImpl->nDocumentSignatureState == SignatureState::NOTVALIDATED
1935            || pImpl->nDocumentSignatureState == SignatureState::PARTIAL_OK;
1936 }
1937 
GetDocumentSignatureState()1938 SignatureState SfxObjectShell::GetDocumentSignatureState()
1939 {
1940     return ImplGetSignatureState();
1941 }
1942 
SignDocumentContent(weld::Window * pDialogParent)1943 void SfxObjectShell::SignDocumentContent(weld::Window* pDialogParent)
1944 {
1945     if (!PrepareForSigning(pDialogParent))
1946         return;
1947 
1948     if (CheckIsReadonly(false))
1949         return;
1950 
1951     bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, false, HasValidSignatures());
1952 
1953     AfterSigning(bSignSuccess, false);
1954 }
1955 
SignDocumentContentUsingCertificate(const Reference<XCertificate> & xCertificate)1956 bool SfxObjectShell::SignDocumentContentUsingCertificate(const Reference<XCertificate>& xCertificate)
1957 {
1958     // 1. PrepareForSigning
1959 
1960     // check whether the document is signed
1961     ImplGetSignatureState(false); // document signature
1962     if (GetMedium() && GetMedium()->GetFilter() && GetMedium()->GetFilter()->IsOwnFormat())
1963         ImplGetSignatureState( true ); // script signature
1964     bool bHasSign = ( pImpl->nScriptingSignatureState != SignatureState::NOSIGNATURES || pImpl->nDocumentSignatureState != SignatureState::NOSIGNATURES );
1965 
1966     // the target ODF version on saving (only valid when signing ODF of course)
1967     SvtSaveOptions aSaveOpt;
1968     SvtSaveOptions::ODFSaneDefaultVersion nVersion = aSaveOpt.GetODFSaneDefaultVersion();
1969 
1970     // the document is not new and is not modified
1971     OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(GetStorage()));
1972 
1973     if (IsModified() || !GetMedium() || GetMedium()->GetName().isEmpty()
1974       || (GetMedium()->GetFilter()->IsOwnFormat() && aODFVersion.compareTo(u"" ODFVER_012_TEXT) < 0 && !bHasSign))
1975     {
1976         if (nVersion >= SvtSaveOptions::ODFSVER_012)
1977         {
1978             sal_uInt16 nId = SID_SAVEDOC;
1979             if ( !GetMedium() || GetMedium()->GetName().isEmpty() )
1980                 nId = SID_SAVEASDOC;
1981             SfxRequest aSaveRequest( nId, SfxCallMode::SLOT, GetPool() );
1982             //ToDo: Review. We needed to call SetModified, otherwise the document would not be saved.
1983             SetModified();
1984             ExecFile_Impl( aSaveRequest );
1985 
1986             // Check if it is stored a format which supports signing
1987             if (GetMedium() && GetMedium()->GetFilter() && !GetMedium()->GetName().isEmpty()
1988                 && ((!GetMedium()->GetFilter()->IsOwnFormat()
1989                      && !GetMedium()->GetFilter()->GetSupportsSigning())
1990                     || (GetMedium()->GetFilter()->IsOwnFormat()
1991                         && !GetMedium()->HasStorage_Impl())))
1992             {
1993                 return false;
1994             }
1995         }
1996         else
1997         {
1998             return false;
1999         }
2000 
2001         if ( IsModified() || !GetMedium() || GetMedium()->GetName().isEmpty() )
2002             return false;
2003     }
2004 
2005     // the document is not modified currently, so it can not become modified after signing
2006     pImpl->m_bAllowModifiedBackAfterSigning = false;
2007     if ( IsEnableSetModified() )
2008     {
2009         EnableSetModified( false );
2010         pImpl->m_bAllowModifiedBackAfterSigning = true;
2011     }
2012 
2013     // we have to store to the original document, the original medium should be closed for this time
2014     bool bResult = ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium);
2015 
2016     if (!bResult)
2017         return false;
2018 
2019     GetMedium()->CloseAndRelease();
2020 
2021     // 2. Check Read-Only
2022     if (GetMedium()->IsOriginallyReadOnly())
2023         return false;
2024 
2025     // 3. Sign
2026     bool bSignSuccess = GetMedium()->SignDocumentContentUsingCertificate(
2027         GetBaseModel(), HasValidSignatures(), xCertificate);
2028 
2029     // 4. AfterSigning
2030     AfterSigning(bSignSuccess, false);
2031 
2032     return true;
2033 }
2034 
SignSignatureLine(weld::Window * pDialogParent,const OUString & aSignatureLineId,const Reference<XCertificate> & xCert,const Reference<XGraphic> & xValidGraphic,const Reference<XGraphic> & xInvalidGraphic,const OUString & aComment)2035 void SfxObjectShell::SignSignatureLine(weld::Window* pDialogParent,
2036                                        const OUString& aSignatureLineId,
2037                                        const Reference<XCertificate>& xCert,
2038                                        const Reference<XGraphic>& xValidGraphic,
2039                                        const Reference<XGraphic>& xInvalidGraphic,
2040                                        const OUString& aComment)
2041 {
2042     if (!PrepareForSigning(pDialogParent))
2043         return;
2044 
2045     if (CheckIsReadonly(false))
2046         return;
2047 
2048     bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent,
2049         false, HasValidSignatures(), aSignatureLineId, xCert, xValidGraphic, xInvalidGraphic, aComment);
2050 
2051     AfterSigning(bSignSuccess, false);
2052 
2053     // Reload the document to get the updated graphic
2054     // FIXME: Update just the signature line graphic instead of reloading the document
2055     SfxViewFrame *pFrame = GetFrame();
2056     if (pFrame)
2057         pFrame->GetDispatcher()->Execute(SID_RELOAD);
2058 }
2059 
GetScriptingSignatureState()2060 SignatureState SfxObjectShell::GetScriptingSignatureState()
2061 {
2062     return ImplGetSignatureState( true );
2063 }
2064 
SignScriptingContent(weld::Window * pDialogParent)2065 void SfxObjectShell::SignScriptingContent(weld::Window* pDialogParent)
2066 {
2067     if (!PrepareForSigning(pDialogParent))
2068         return;
2069 
2070     if (CheckIsReadonly(true))
2071         return;
2072 
2073     bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, true, HasValidSignatures());
2074 
2075     AfterSigning(bSignSuccess, true);
2076 }
2077 
getUnoTunnelId()2078 const uno::Sequence<sal_Int8>& SfxObjectShell::getUnoTunnelId()
2079 {
2080     static const UnoTunnelIdInit theSfxObjectShellUnoTunnelId;
2081     return theSfxObjectShellUnoTunnelId.getSeq();
2082 }
2083 
2084 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2085