sd: keep a non-owning pointer to the OverridingShell
[LibreOffice.git] / sfx2 / source / dialog / mailmodel.cxx
blob23101a56a63348d85a792f960043b971b03418ef
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/beans/PropertyValue.hpp>
21 #include <com/sun/star/beans/XPropertyAccess.hpp>
22 #include <com/sun/star/container/XContainerQuery.hpp>
23 #include <com/sun/star/document/XExporter.hpp>
24 #include <com/sun/star/embed/XStorage.hpp>
25 #include <com/sun/star/frame/XDispatchProvider.hpp>
26 #include <com/sun/star/frame/XDispatch.hpp>
27 #include <com/sun/star/frame/XStatusListener.hpp>
28 #include <com/sun/star/frame/XFrame.hpp>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/frame/ModuleManager.hpp>
31 #include <com/sun/star/frame/XStorable.hpp>
32 #include <com/sun/star/io/IOException.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/system/SimpleSystemMail.hpp>
35 #include <com/sun/star/system/SimpleCommandMail.hpp>
36 #include <com/sun/star/system/XSimpleMailClientSupplier.hpp>
37 #include <com/sun/star/system/SimpleMailClientFlags.hpp>
38 #include <com/sun/star/ucb/CommandAbortedException.hpp>
39 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
40 #include <com/sun/star/uno/Reference.h>
41 #include <com/sun/star/util/URLTransformer.hpp>
42 #include <com/sun/star/util/XURLTransformer.hpp>
43 #include <com/sun/star/util/XModifiable.hpp>
44 #include <vcl/weld.hxx>
45 #include <osl/diagnose.h>
47 #include <sfx2/mailmodelapi.hxx>
48 #include <sfx2/sfxresid.hxx>
49 #include <sfx2/strings.hrc>
51 #include <unotools/tempfile.hxx>
52 #include <tools/urlobj.hxx>
53 #include <unotools/useroptions.hxx>
54 #include <comphelper/processfactory.hxx>
55 #include <comphelper/propertyvalue.hxx>
56 #include <comphelper/sequenceashashmap.hxx>
57 #include <comphelper/string.hxx>
58 #include <vcl/svapp.hxx>
59 #include <cppuhelper/implbase.hxx>
62 using namespace ::com::sun::star;
63 using namespace ::com::sun::star::beans;
64 using namespace ::com::sun::star::frame;
65 using namespace ::com::sun::star::io;
66 using namespace ::com::sun::star::lang;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::util;
69 using namespace ::com::sun::star::system;
71 namespace {
73 // - class PrepareListener_Impl ------------------------------------------
74 class PrepareListener_Impl : public ::cppu::WeakImplHelper< css::frame::XStatusListener >
76 bool m_bState;
77 public:
78 PrepareListener_Impl();
80 // css.frame.XStatusListener
81 virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& aEvent) override;
83 // css.lang.XEventListener
84 virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
86 bool IsSet() const {return m_bState;}
91 PrepareListener_Impl::PrepareListener_Impl() :
92 m_bState( false )
96 void PrepareListener_Impl::statusChanged(const css::frame::FeatureStateEvent& rEvent)
98 if( rEvent.IsEnabled )
99 rEvent.State >>= m_bState;
100 else
101 m_bState = false;
104 void PrepareListener_Impl::disposing(const css::lang::EventObject& /*rEvent*/)
108 // class SfxMailModel -----------------------------------------------
110 const char16_t PDF_DOCUMENT_TYPE[] = u"pdf_Portable_Document_Format";
112 SfxMailModel::SaveResult SfxMailModel::ShowFilterOptionsDialog(
113 const uno::Reference< lang::XMultiServiceFactory >& xSMGR,
114 const uno::Reference< frame::XModel >& xModel,
115 const OUString& rFilterName,
116 std::u16string_view rType,
117 bool bModified,
118 sal_Int32& rNumArgs,
119 css::uno::Sequence< css::beans::PropertyValue >& rArgs )
121 SaveResult eRet( SAVE_ERROR );
125 uno::Sequence < beans::PropertyValue > aProps;
126 css::uno::Reference< css::container::XNameAccess > xFilterCFG(
127 xSMGR->createInstance( u"com.sun.star.document.FilterFactory"_ustr ), uno::UNO_QUERY );
128 css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY );
130 if ( !xFilterCFG.is() )
131 return eRet;
133 uno::Any aAny = xFilterCFG->getByName( rFilterName );
135 if ( aAny >>= aProps )
137 for (const auto& rProp : aProps)
139 if( rProp.Name == "UIComponent" )
141 OUString aServiceName;
142 rProp.Value >>= aServiceName;
143 if( !aServiceName.isEmpty() )
145 uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog(
146 xSMGR->createInstance( aServiceName ), uno::UNO_QUERY );
147 uno::Reference< beans::XPropertyAccess > xFilterProperties(
148 xFilterDialog, uno::UNO_QUERY );
150 if( xFilterDialog.is() && xFilterProperties.is() )
152 uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY );
154 if ( rType == PDF_DOCUMENT_TYPE )
156 //add an internal property, used to tell the dialog we want to set a different
157 //string for the ok button
158 //used in filter/source/pdf/impdialog.cxx
159 uno::Sequence< beans::PropertyValue > aFilterDataValue{
160 comphelper::makePropertyValue(u"_OkButtonString"_ustr,
161 SfxResId(STR_PDF_EXPORT_SEND ))
164 //add to the filterdata property, the only one the PDF export filter dialog will care for
165 uno::Sequence< beans::PropertyValue > aPropsForDialog{
166 comphelper::makePropertyValue(u"FilterData"_ustr, aFilterDataValue)
169 //when executing the dialog will merge the persistent FilterData properties
170 xFilterProperties->setPropertyValues( aPropsForDialog );
173 if( xExporter.is() )
174 xExporter->setSourceDocument( xModel );
176 if( xFilterDialog->execute() )
178 //get the filter data
179 const uno::Sequence< beans::PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
181 //add them to the args
182 auto pProp = std::find_if(aPropsFromDialog.begin(), aPropsFromDialog.end(),
183 [](const beans::PropertyValue& rDialogProp) { return rDialogProp.Name == "FilterData"; });
184 if (pProp != aPropsFromDialog.end())
186 //found the filterdata, add to the storing argument
187 rArgs.realloc( ++rNumArgs );
188 auto pArgs = rArgs.getArray();
189 pArgs[rNumArgs-1].Name = pProp->Name;
190 pArgs[rNumArgs-1].Value = pProp->Value;
192 eRet = SAVE_SUCCESSFUL;
194 else
196 // cancel from dialog, then do not send
197 // If the model is not modified, it could be modified by the dispatch calls.
198 // Therefore set back to modified = false. This should not hurt if we call
199 // on a non-modified model.
200 if ( !bModified )
204 xModifiable->setModified( false );
206 catch( css::beans::PropertyVetoException& )
210 eRet = SAVE_CANCELLED;
213 break;
219 catch( css::uno::RuntimeException& )
221 throw;
223 catch( uno::Exception& )
227 return eRet;
230 bool SfxMailModel::IsEmpty() const
232 return maAttachedDocuments.empty();
235 SfxMailModel::SaveResult SfxMailModel::SaveDocumentAsFormat(
236 const OUString& aSaveFileName,
237 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
238 const OUString& rType,
239 OUString& rFileNamePath )
241 SaveResult eRet( SAVE_ERROR );
242 bool bSendAsPDF = ( rType == PDF_DOCUMENT_TYPE );
244 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory();
245 const css::uno::Reference< css::uno::XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
246 if (!xContext.is())
247 return eRet;
249 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager( css::frame::ModuleManager::create(xContext) );
251 OUString aModule;
254 aModule = xModuleManager->identify( xFrameOrModel );
256 catch ( css::uno::RuntimeException& )
258 throw;
260 catch ( css::uno::Exception& )
264 css::uno::Reference< css::frame::XFrame > xFrame( xFrameOrModel, css::uno::UNO_QUERY );
265 css::uno::Reference< css::frame::XModel > xModel( xFrameOrModel, css::uno::UNO_QUERY );
266 if ( xFrame.is() )
268 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
269 if ( xController.is() )
270 xModel = xController->getModel();
273 // We need at least a valid module name and model reference
274 if ( !aModule.isEmpty() && xModel.is() )
276 bool bModified( false );
277 bool bHasLocation( false );
278 bool bStoreTo( false );
280 css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY );
281 css::uno::Reference< css::frame::XStorable > xStorable( xModel, css::uno::UNO_QUERY );
283 if ( xModifiable.is() )
284 bModified = xModifiable->isModified();
285 if ( xStorable.is() )
287 OUString aLocation = xStorable->getLocation();
288 INetURLObject aFileObj( aLocation );
290 bool bPrivateProtocol = ( aFileObj.GetProtocol() == INetProtocol::PrivSoffice );
292 bHasLocation = !aLocation.isEmpty() && !bPrivateProtocol;
293 OSL_ASSERT( !bPrivateProtocol );
295 if ( !rType.isEmpty() )
296 bStoreTo = true;
298 if ( xStorable.is() )
300 OUString aFilterName;
301 OUString aTypeName( rType );
302 OUString aFileName;
303 OUString aExtension;
305 css::uno::Reference< css::container::XContainerQuery > xContainerQuery(
306 xSMGR->createInstance( u"com.sun.star.document.FilterFactory"_ustr ),
307 css::uno::UNO_QUERY );
309 if ( bStoreTo )
311 // Retrieve filter from type
312 css::uno::Sequence< css::beans::NamedValue > aQuery( bSendAsPDF ? 3 : 2 );
313 auto pQuery = aQuery.getArray();
314 pQuery[0].Name = "Type";
315 pQuery[0].Value <<= aTypeName;
316 pQuery[1].Name = "DocumentService";
317 pQuery[1].Value <<= aModule;
318 if( bSendAsPDF )
320 // #i91419#
321 // FIXME: we want just an export filter. However currently we need
322 // exact flag value as detailed in the filter configuration to get it
323 // this seems to be a bug
324 // without flags we get an import filter here, which is also unwanted
325 pQuery[2].Name = "Flags";
326 pQuery[2].Value <<= sal_Int32(0x80042); // SfxFilterFlags: EXPORT ALIEN 3RDPARTY
329 css::uno::Reference< css::container::XEnumeration > xEnumeration =
330 xContainerQuery->createSubSetEnumerationByProperties( aQuery );
332 if ( xEnumeration->hasMoreElements() )
334 ::comphelper::SequenceAsHashMap aFilterPropsHM( xEnumeration->nextElement() );
335 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
336 u"Name"_ustr,
337 OUString() );
340 if ( bHasLocation )
342 // Retrieve filter from media descriptor
343 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
344 OUString aOrgFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
345 u"FilterName"_ustr,
346 OUString() );
347 if ( aOrgFilterName == aFilterName )
349 // We should save the document in the original format. Therefore this
350 // is not a storeTo operation. To support signing in this case, reset
351 // bStoreTo flag.
352 bStoreTo = false;
356 else
358 if ( bHasLocation )
360 // Retrieve filter from media descriptor
361 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
362 aFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
363 u"FilterName"_ustr,
364 OUString() );
367 if ( !bHasLocation || aFilterName.isEmpty())
369 // Retrieve the user defined default filter
372 ::comphelper::SequenceAsHashMap aFilterPropsHM( xModuleManager->getByName( aModule ) );
373 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
374 u"ooSetupFactoryDefaultFilter"_ustr,
375 OUString() );
376 css::uno::Reference< css::container::XNameAccess > xNameAccess(
377 xContainerQuery, css::uno::UNO_QUERY );
378 if ( xNameAccess.is() )
380 ::comphelper::SequenceAsHashMap aFilterPropsHM2( xNameAccess->getByName( aFilterName ) );
381 aTypeName = aFilterPropsHM2.getUnpackedValueOrDefault(
382 u"Type"_ustr,
383 OUString() );
386 catch ( css::container::NoSuchElementException& )
389 catch ( css::beans::UnknownPropertyException& )
395 // No filter found => error
396 // No type and no location => error
397 if (( aFilterName.isEmpty() ) ||
398 ( aTypeName.isEmpty() && !bHasLocation ))
399 return eRet;
401 // Determine file name and extension
402 if ( bHasLocation && !bStoreTo )
404 INetURLObject aFileObj( xStorable->getLocation() );
405 aExtension = aFileObj.getExtension();
407 else
409 css::uno::Reference< container::XNameAccess > xTypeDetection(
410 xSMGR->createInstance( u"com.sun.star.document.TypeDetection"_ustr ),
411 css::uno::UNO_QUERY );
414 if ( xTypeDetection.is() )
418 ::comphelper::SequenceAsHashMap aTypeNamePropsHM( xTypeDetection->getByName( aTypeName ) );
419 uno::Sequence< OUString > aExtensions = aTypeNamePropsHM.getUnpackedValueOrDefault(
420 u"Extensions"_ustr,
421 ::uno::Sequence< OUString >() );
422 if ( aExtensions.hasElements() )
423 aExtension = aExtensions[0];
425 catch ( css::container::NoSuchElementException& )
431 // Use provided save file name. If empty determine file name
432 aFileName = aSaveFileName;
433 if ( aFileName.isEmpty() )
435 if ( !bHasLocation )
437 // Create a noname file name with the correct extension
438 aFileName = "noname";
440 else
442 // Determine file name from model
443 INetURLObject aFileObj( xStorable->getLocation() );
444 aFileName = aFileObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::NONE );
448 // No file name => error
449 if ( aFileName.isEmpty() )
450 return eRet;
452 OSL_ASSERT( !aFilterName.isEmpty() );
453 OSL_ASSERT( !aFileName.isEmpty() );
455 // Creates a temporary directory to store a predefined file into it.
456 // This makes it possible to store the file for "send document as e-mail"
457 // with the original file name. We cannot use the original file as
458 // some mail programs need exclusive access.
459 INetURLObject aFilePathObj( ::utl::CreateTempURL(nullptr, true) );
460 aFilePathObj.insertName( aFileName );
461 aFilePathObj.setExtension( aExtension );
463 OUString aFileURL = aFilePathObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
465 sal_Int32 nNumArgs(1);
466 static constexpr OUString aPasswordPropName( u"Password"_ustr );
467 css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
468 u"FilterName"_ustr, aFilterName) };
470 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
471 OUString aPassword = aMediaDescrPropsHM.getUnpackedValueOrDefault(
472 aPasswordPropName,
473 OUString() );
474 if ( !aPassword.isEmpty() )
476 aArgs.realloc( ++nNumArgs );
477 auto pArgs = aArgs.getArray();
478 pArgs[nNumArgs-1].Name = aPasswordPropName;
479 pArgs[nNumArgs-1].Value <<= aPassword;
482 bool bNeedsPreparation = false;
483 css::util::URL aPrepareURL;
484 css::uno::Reference< css::frame::XDispatch > xPrepareDispatch;
485 css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( xFrame, css::uno::UNO_QUERY );
486 css::uno::Reference< css::util::XURLTransformer > xURLTransformer( css::util::URLTransformer::create( xContext ) );
487 if( !bSendAsPDF )
491 // check if the document needs to be prepared for sending as mail (embedding of links, removal of invisible content)
493 aPrepareURL.Complete = ".uno:PrepareMailExport";
494 xURLTransformer->parseStrict( aPrepareURL );
496 if ( xDispatchProvider.is() )
498 xPrepareDispatch.set( xDispatchProvider->queryDispatch( aPrepareURL, OUString(), 0 ));
499 if ( xPrepareDispatch.is() )
501 rtl::Reference<PrepareListener_Impl> pPrepareListener = new PrepareListener_Impl;
502 xPrepareDispatch->addStatusListener( pPrepareListener, aPrepareURL );
503 bNeedsPreparation = pPrepareListener->IsSet();
504 xPrepareDispatch->removeStatusListener( pPrepareListener, aPrepareURL );
508 catch ( css::uno::RuntimeException& )
510 throw;
512 catch ( css::uno::Exception& )
517 if ( bModified || !bHasLocation || bStoreTo || bNeedsPreparation )
519 // Document is modified, is newly created or should be stored in a special format
522 if( bNeedsPreparation && xPrepareDispatch.is() )
526 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
527 xPrepareDispatch->dispatch( aPrepareURL, aDispatchArgs );
529 catch ( css::uno::RuntimeException& )
531 throw;
533 catch ( css::uno::Exception& )
538 //check if this is the pdf output filter (i#64555)
539 if( bSendAsPDF )
541 SaveResult eShowPDFFilterDialog = ShowFilterOptionsDialog(
542 xSMGR, xModel, aFilterName, rType, bModified, nNumArgs, aArgs );
544 // don't continue on dialog cancel or error
545 if ( eShowPDFFilterDialog != SAVE_SUCCESSFUL )
546 return eShowPDFFilterDialog;
549 xStorable->storeToURL( aFileURL, aArgs );
550 rFileNamePath = aFileURL;
551 eRet = SAVE_SUCCESSFUL;
553 if( !bSendAsPDF )
555 css::util::URL aURL;
556 // #i30432# notify that export is finished - the Writer may want to restore removed content
557 aURL.Complete = ".uno:MailExportFinished";
558 xURLTransformer->parseStrict( aURL );
560 if ( xDispatchProvider.is() )
562 css::uno::Reference< css::frame::XDispatch > xDispatch(
563 xDispatchProvider->queryDispatch( aURL, OUString(), 0 ));
564 if ( xDispatch.is() )
568 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
569 xDispatch->dispatch( aURL, aDispatchArgs );
571 catch ( css::uno::RuntimeException& )
573 throw;
575 catch ( css::uno::Exception& )
581 // If the model is not modified, it could be modified by the dispatch calls.
582 // Therefore set back to modified = false. This should not hurt if we call
583 // on a non-modified model.
584 if ( !bModified )
588 xModifiable->setModified( false );
590 catch( css::beans::PropertyVetoException& )
595 catch ( css::io::IOException& )
597 eRet = SAVE_ERROR;
600 else
602 // We need 1:1 copy of the document to preserve an added signature.
603 aArgs.realloc( ++nNumArgs );
604 auto pArgs = aArgs.getArray();
605 pArgs[nNumArgs-1].Name = "CopyStreamIfPossible";
606 pArgs[nNumArgs-1].Value <<= true;
610 xStorable->storeToURL( aFileURL, aArgs );
611 rFileNamePath = aFileURL;
612 eRet = SAVE_SUCCESSFUL;
614 catch ( css::io::IOException& )
616 eRet = SAVE_ERROR;
622 return eRet;
625 SfxMailModel::SfxMailModel()
629 SfxMailModel::~SfxMailModel()
633 void SfxMailModel::AddToAddress( const OUString& rAddress )
635 // don't add an empty address
636 if ( !rAddress.isEmpty() )
638 if ( !mpToList )
639 // create the list
640 mpToList.reset(new AddressList_Impl);
642 // add address to list
643 mpToList->push_back( rAddress );
647 SfxMailModel::SendMailResult SfxMailModel::AttachDocument(
648 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
649 const OUString& sAttachmentTitle )
651 OUString sFileName;
653 SaveResult eSaveResult = SaveDocumentAsFormat( sAttachmentTitle, xFrameOrModel, OUString()/*sDocumentType*/, sFileName );
654 if ( eSaveResult == SAVE_SUCCESSFUL && !sFileName.isEmpty() )
655 maAttachedDocuments.push_back(sFileName);
656 return eSaveResult == SAVE_SUCCESSFUL ? SEND_MAIL_OK : SEND_MAIL_ERROR;
659 SfxMailModel::SendMailResult SfxMailModel::Send( const css::uno::Reference< css::frame::XFrame >& xFrame )
661 OSL_ENSURE(!maAttachedDocuments.empty(),"No document added!");
662 SendMailResult eResult = SEND_MAIL_ERROR;
663 if ( !maAttachedDocuments.empty() )
665 const css::uno::Reference < XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
667 css::uno::Reference< XSimpleMailClientSupplier > xSimpleMailClientSupplier;
669 // Prefer the SimpleSystemMail service if available
670 try {
671 xSimpleMailClientSupplier = SimpleSystemMail::create( xContext );
673 catch ( const uno::Exception & )
676 if ( ! xSimpleMailClientSupplier.is() )
678 try {
679 xSimpleMailClientSupplier = SimpleCommandMail::create( xContext );
681 catch ( const uno::Exception & )
685 if ( xSimpleMailClientSupplier.is() )
687 css::uno::Reference< XSimpleMailClient > xSimpleMailClient = xSimpleMailClientSupplier->querySimpleMailClient();
689 if ( !xSimpleMailClient.is() )
691 // no mail client support => message box!
692 return SEND_MAIL_ERROR;
695 // we have a simple mail client
696 css::uno::Reference< XSimpleMailMessage > xSimpleMailMessage = xSimpleMailClient->createSimpleMailMessage();
697 if ( xSimpleMailMessage.is() )
699 sal_Int32 nSendFlags = SimpleMailClientFlags::DEFAULTS;
700 if ( maFromAddress.isEmpty() )
702 // from address not set, try figure out users e-mail address
703 CreateFromAddress_Impl( maFromAddress );
705 xSimpleMailMessage->setOriginator( maFromAddress );
707 size_t nToCount = mpToList ? mpToList->size() : 0;
709 // set recipient (only one) for this simple mail server!!
710 if ( nToCount >= 1 )
712 xSimpleMailMessage->setRecipient( mpToList->at( 0 ) );
713 nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE;
716 // all other recipient must be handled with CC recipients!
717 if ( nToCount > 1 )
719 Sequence< OUString > aCcRecipientSeq( nToCount - 1 );
720 std::copy_n(std::next(mpToList->begin()), aCcRecipientSeq.getLength(),
721 aCcRecipientSeq.getArray());
722 xSimpleMailMessage->setCcRecipient( aCcRecipientSeq );
725 Sequence< OUString > aAttachmentSeq(maAttachedDocuments.data(),maAttachedDocuments.size());
727 if ( xSimpleMailMessage->getSubject().isEmpty() ) {
728 INetURLObject url(
729 maAttachedDocuments[0], INetURLObject::EncodeMechanism::WasEncoded);
730 OUString subject(
731 url.getBase(
732 INetURLObject::LAST_SEGMENT, false,
733 INetURLObject::DecodeMechanism::WithCharset));
734 if (subject.isEmpty()) {
735 subject = maAttachedDocuments[0];
737 if ( maAttachedDocuments.size() > 1 )
738 subject += ", ...";
739 xSimpleMailMessage->setSubject( subject );
741 xSimpleMailMessage->setAttachement( aAttachmentSeq );
743 bool bSend( false );
746 xSimpleMailClient->sendSimpleMailMessage( xSimpleMailMessage, nSendFlags );
747 bSend = true;
749 catch ( IllegalArgumentException& )
752 catch ( Exception& )
756 if ( !bSend )
758 css::uno::Reference< css::awt::XWindow > xParentWindow = xFrame->getContainerWindow();
760 SolarMutexGuard aGuard;
762 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(Application::GetFrameWeld(xParentWindow), u"sfx/ui/errorfindemaildialog.ui"_ustr));
763 std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog(u"ErrorFindEmailDialog"_ustr));
764 xBox->run();
765 eResult = SEND_MAIL_CANCELLED;
767 else
768 eResult = SEND_MAIL_OK;
772 else
773 eResult = SEND_MAIL_CANCELLED;
775 return eResult;
778 SfxMailModel::SendMailResult SfxMailModel::SaveAndSend( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& rTypeName )
780 SaveResult eSaveResult;
781 SendMailResult eResult = SEND_MAIL_ERROR;
782 OUString aFileName;
784 eSaveResult = SaveDocumentAsFormat( OUString(), xFrame, rTypeName, aFileName );
786 if ( eSaveResult == SAVE_SUCCESSFUL )
788 maAttachedDocuments.push_back( aFileName );
789 return Send( xFrame );
791 else if ( eSaveResult == SAVE_CANCELLED )
792 eResult = SEND_MAIL_CANCELLED;
794 return eResult;
797 // functions -------------------------------------------------------------
799 bool CreateFromAddress_Impl( OUString& rFrom )
801 /* [Description]
803 This function tries to create a From-address with the help of IniManagers.
804 For this the fields 'first name', 'Name' and 'Email' are read from the
805 application-ini-data. If these fields are not set, FALSE is returned.
807 [Return value]
809 sal_True: Address could be created.
810 sal_False: Address could not be created.
814 SvtUserOptions aUserCFG;
815 OUString aName = aUserCFG.GetLastName ();
816 OUString aFirstName = aUserCFG.GetFirstName ();
817 if ( !aFirstName.isEmpty() || !aName.isEmpty() )
819 if ( !aFirstName.isEmpty() )
821 rFrom = comphelper::string::strip(aFirstName, ' ');
823 if ( !aName.isEmpty() )
824 rFrom += " ";
826 rFrom += comphelper::string::strip(aName, ' ');
827 // remove illegal characters
828 rFrom = rFrom.replaceAll("<", "").replaceAll(">", "").replaceAll("@", "");
830 OUString aEmailName = aUserCFG.GetEmail();
832 // remove illegal characters
833 aEmailName = aEmailName.replaceAll("<", "").replaceAll(">", "");
835 if ( !aEmailName.isEmpty() )
837 if ( !rFrom.isEmpty() )
838 rFrom += " ";
839 rFrom += "<" + comphelper::string::strip(aEmailName, ' ') + ">";
841 else
842 rFrom.clear();
843 return !rFrom.isEmpty();
846 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */