LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / dialog / mailmodel.cxx
blob382a677369f4cb053f13d3705794aaabf9031adb
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::ucb;
68 using namespace ::com::sun::star::uno;
69 using namespace ::com::sun::star::util;
70 using namespace ::com::sun::star::system;
72 namespace {
74 // - class PrepareListener_Impl ------------------------------------------
75 class PrepareListener_Impl : public ::cppu::WeakImplHelper< css::frame::XStatusListener >
77 bool m_bState;
78 public:
79 PrepareListener_Impl();
81 // css.frame.XStatusListener
82 virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& aEvent) override;
84 // css.lang.XEventListener
85 virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
87 bool IsSet() const {return m_bState;}
92 PrepareListener_Impl::PrepareListener_Impl() :
93 m_bState( false )
97 void PrepareListener_Impl::statusChanged(const css::frame::FeatureStateEvent& rEvent)
99 if( rEvent.IsEnabled )
100 rEvent.State >>= m_bState;
101 else
102 m_bState = false;
105 void PrepareListener_Impl::disposing(const css::lang::EventObject& /*rEvent*/)
109 // class SfxMailModel -----------------------------------------------
111 const char16_t PDF_DOCUMENT_TYPE[] = u"pdf_Portable_Document_Format";
113 SfxMailModel::SaveResult SfxMailModel::ShowFilterOptionsDialog(
114 const uno::Reference< lang::XMultiServiceFactory >& xSMGR,
115 const uno::Reference< frame::XModel >& xModel,
116 const OUString& rFilterName,
117 std::u16string_view rType,
118 bool bModified,
119 sal_Int32& rNumArgs,
120 css::uno::Sequence< css::beans::PropertyValue >& rArgs )
122 SaveResult eRet( SAVE_ERROR );
126 uno::Sequence < beans::PropertyValue > aProps;
127 css::uno::Reference< css::container::XNameAccess > xFilterCFG(
128 xSMGR->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
129 css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY );
131 if ( !xFilterCFG.is() )
132 return eRet;
134 uno::Any aAny = xFilterCFG->getByName( rFilterName );
136 if ( aAny >>= aProps )
138 for( const auto& rProp : std::as_const(aProps) )
140 if( rProp.Name == "UIComponent" )
142 OUString aServiceName;
143 rProp.Value >>= aServiceName;
144 if( !aServiceName.isEmpty() )
146 uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog(
147 xSMGR->createInstance( aServiceName ), uno::UNO_QUERY );
148 uno::Reference< beans::XPropertyAccess > xFilterProperties(
149 xFilterDialog, uno::UNO_QUERY );
151 if( xFilterDialog.is() && xFilterProperties.is() )
153 uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY );
155 if ( rType == PDF_DOCUMENT_TYPE )
157 //add an internal property, used to tell the dialog we want to set a different
158 //string for the ok button
159 //used in filter/source/pdf/impdialog.cxx
160 uno::Sequence< beans::PropertyValue > aFilterDataValue{
161 comphelper::makePropertyValue("_OkButtonString",
162 SfxResId(STR_PDF_EXPORT_SEND ))
165 //add to the filterdata property, the only one the PDF export filter dialog will care for
166 uno::Sequence< beans::PropertyValue > aPropsForDialog{
167 comphelper::makePropertyValue("FilterData", aFilterDataValue)
170 //when executing the dialog will merge the persistent FilterData properties
171 xFilterProperties->setPropertyValues( aPropsForDialog );
174 if( xExporter.is() )
175 xExporter->setSourceDocument( xModel );
177 if( xFilterDialog->execute() )
179 //get the filter data
180 const uno::Sequence< beans::PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
182 //add them to the args
183 auto pProp = std::find_if(aPropsFromDialog.begin(), aPropsFromDialog.end(),
184 [](const beans::PropertyValue& rDialogProp) { return rDialogProp.Name == "FilterData"; });
185 if (pProp != aPropsFromDialog.end())
187 //found the filterdata, add to the storing argument
188 rArgs.realloc( ++rNumArgs );
189 auto pArgs = rArgs.getArray();
190 pArgs[rNumArgs-1].Name = pProp->Name;
191 pArgs[rNumArgs-1].Value = pProp->Value;
193 eRet = SAVE_SUCCESSFUL;
195 else
197 // cancel from dialog, then do not send
198 // If the model is not modified, it could be modified by the dispatch calls.
199 // Therefore set back to modified = false. This should not hurt if we call
200 // on a non-modified model.
201 if ( !bModified )
205 xModifiable->setModified( false );
207 catch( css::beans::PropertyVetoException& )
211 eRet = SAVE_CANCELLED;
214 break;
220 catch( css::uno::RuntimeException& )
222 throw;
224 catch( uno::Exception& )
228 return eRet;
231 bool SfxMailModel::IsEmpty() const
233 return maAttachedDocuments.empty();
236 SfxMailModel::SaveResult SfxMailModel::SaveDocumentAsFormat(
237 const OUString& aSaveFileName,
238 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
239 const OUString& rType,
240 OUString& rFileNamePath )
242 SaveResult eRet( SAVE_ERROR );
243 bool bSendAsPDF = ( rType == PDF_DOCUMENT_TYPE );
245 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory();
246 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
247 if (!xContext.is())
248 return eRet;
250 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager( css::frame::ModuleManager::create(xContext) );
252 OUString aModule;
255 aModule = xModuleManager->identify( xFrameOrModel );
257 catch ( css::uno::RuntimeException& )
259 throw;
261 catch ( css::uno::Exception& )
265 css::uno::Reference< css::frame::XFrame > xFrame( xFrameOrModel, css::uno::UNO_QUERY );
266 css::uno::Reference< css::frame::XModel > xModel( xFrameOrModel, css::uno::UNO_QUERY );
267 if ( xFrame.is() )
269 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
270 if ( xController.is() )
271 xModel = xController->getModel();
274 // We need at least a valid module name and model reference
275 if ( !aModule.isEmpty() && xModel.is() )
277 bool bModified( false );
278 bool bHasLocation( false );
279 bool bStoreTo( false );
281 css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY );
282 css::uno::Reference< css::frame::XStorable > xStorable( xModel, css::uno::UNO_QUERY );
284 if ( xModifiable.is() )
285 bModified = xModifiable->isModified();
286 if ( xStorable.is() )
288 OUString aLocation = xStorable->getLocation();
289 INetURLObject aFileObj( aLocation );
291 bool bPrivateProtocol = ( aFileObj.GetProtocol() == INetProtocol::PrivSoffice );
293 bHasLocation = !aLocation.isEmpty() && !bPrivateProtocol;
294 OSL_ASSERT( !bPrivateProtocol );
296 if ( !rType.isEmpty() )
297 bStoreTo = true;
299 if ( xStorable.is() )
301 OUString aFilterName;
302 OUString aTypeName( rType );
303 OUString aFileName;
304 OUString aExtension;
306 css::uno::Reference< css::container::XContainerQuery > xContainerQuery(
307 xSMGR->createInstance( "com.sun.star.document.FilterFactory" ),
308 css::uno::UNO_QUERY );
310 if ( bStoreTo )
312 // Retrieve filter from type
313 css::uno::Sequence< css::beans::NamedValue > aQuery( bSendAsPDF ? 3 : 2 );
314 auto pQuery = aQuery.getArray();
315 pQuery[0].Name = "Type";
316 pQuery[0].Value <<= aTypeName;
317 pQuery[1].Name = "DocumentService";
318 pQuery[1].Value <<= aModule;
319 if( bSendAsPDF )
321 // #i91419#
322 // FIXME: we want just an export filter. However currently we need
323 // exact flag value as detailed in the filter configuration to get it
324 // this seems to be a bug
325 // without flags we get an import filter here, which is also unwanted
326 pQuery[2].Name = "Flags";
327 pQuery[2].Value <<= sal_Int32(0x80042); // SfxFilterFlags: EXPORT ALIEN 3RDPARTY
330 css::uno::Reference< css::container::XEnumeration > xEnumeration =
331 xContainerQuery->createSubSetEnumerationByProperties( aQuery );
333 if ( xEnumeration->hasMoreElements() )
335 ::comphelper::SequenceAsHashMap aFilterPropsHM( xEnumeration->nextElement() );
336 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
337 "Name",
338 OUString() );
341 if ( bHasLocation )
343 // Retrieve filter from media descriptor
344 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
345 OUString aOrgFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
346 "FilterName",
347 OUString() );
348 if ( aOrgFilterName == aFilterName )
350 // We should save the document in the original format. Therefore this
351 // is not a storeTo operation. To support signing in this case, reset
352 // bStoreTo flag.
353 bStoreTo = false;
357 else
359 if ( bHasLocation )
361 // Retrieve filter from media descriptor
362 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
363 aFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
364 "FilterName",
365 OUString() );
368 if ( !bHasLocation || aFilterName.isEmpty())
370 // Retrieve the user defined default filter
373 ::comphelper::SequenceAsHashMap aFilterPropsHM( xModuleManager->getByName( aModule ) );
374 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
375 "ooSetupFactoryDefaultFilter",
376 OUString() );
377 css::uno::Reference< css::container::XNameAccess > xNameAccess(
378 xContainerQuery, css::uno::UNO_QUERY );
379 if ( xNameAccess.is() )
381 ::comphelper::SequenceAsHashMap aFilterPropsHM2( xNameAccess->getByName( aFilterName ) );
382 aTypeName = aFilterPropsHM2.getUnpackedValueOrDefault(
383 "Type",
384 OUString() );
387 catch ( css::container::NoSuchElementException& )
390 catch ( css::beans::UnknownPropertyException& )
396 // No filter found => error
397 // No type and no location => error
398 if (( aFilterName.isEmpty() ) ||
399 ( aTypeName.isEmpty() && !bHasLocation ))
400 return eRet;
402 // Determine file name and extension
403 if ( bHasLocation && !bStoreTo )
405 INetURLObject aFileObj( xStorable->getLocation() );
406 aExtension = aFileObj.getExtension();
408 else
410 css::uno::Reference< container::XNameAccess > xTypeDetection(
411 xSMGR->createInstance( "com.sun.star.document.TypeDetection" ),
412 css::uno::UNO_QUERY );
415 if ( xTypeDetection.is() )
419 ::comphelper::SequenceAsHashMap aTypeNamePropsHM( xTypeDetection->getByName( aTypeName ) );
420 uno::Sequence< OUString > aExtensions = aTypeNamePropsHM.getUnpackedValueOrDefault(
421 "Extensions",
422 ::uno::Sequence< OUString >() );
423 if ( aExtensions.hasElements() )
424 aExtension = aExtensions[0];
426 catch ( css::container::NoSuchElementException& )
432 // Use provided save file name. If empty determine file name
433 aFileName = aSaveFileName;
434 if ( aFileName.isEmpty() )
436 if ( !bHasLocation )
438 // Create a noname file name with the correct extension
439 aFileName = "noname";
441 else
443 // Determine file name from model
444 INetURLObject aFileObj( xStorable->getLocation() );
445 aFileName = aFileObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::NONE );
449 // No file name => error
450 if ( aFileName.isEmpty() )
451 return eRet;
453 OSL_ASSERT( !aFilterName.isEmpty() );
454 OSL_ASSERT( !aFileName.isEmpty() );
456 // Creates a temporary directory to store a predefined file into it.
457 // This makes it possible to store the file for "send document as e-mail"
458 // with the original file name. We cannot use the original file as
459 // some mail programs need exclusive access.
460 ::utl::TempFile aTempDir( nullptr, true );
462 INetURLObject aFilePathObj( aTempDir.GetURL() );
463 aFilePathObj.insertName( aFileName );
464 aFilePathObj.setExtension( aExtension );
466 OUString aFileURL = aFilePathObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
468 sal_Int32 nNumArgs(1);
469 static const OUStringLiteral aPasswordPropName( u"Password" );
470 css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
471 "FilterName", aFilterName) };
473 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
474 OUString aPassword = aMediaDescrPropsHM.getUnpackedValueOrDefault(
475 aPasswordPropName,
476 OUString() );
477 if ( !aPassword.isEmpty() )
479 aArgs.realloc( ++nNumArgs );
480 auto pArgs = aArgs.getArray();
481 pArgs[nNumArgs-1].Name = aPasswordPropName;
482 pArgs[nNumArgs-1].Value <<= aPassword;
485 bool bNeedsPreparation = false;
486 css::util::URL aPrepareURL;
487 css::uno::Reference< css::frame::XDispatch > xPrepareDispatch;
488 css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( xFrame, css::uno::UNO_QUERY );
489 css::uno::Reference< css::util::XURLTransformer > xURLTransformer( css::util::URLTransformer::create( xContext ) );
490 if( !bSendAsPDF )
494 // check if the document needs to be prepared for sending as mail (embedding of links, removal of invisible content)
496 aPrepareURL.Complete = ".uno:PrepareMailExport";
497 xURLTransformer->parseStrict( aPrepareURL );
499 if ( xDispatchProvider.is() )
501 xPrepareDispatch.set( xDispatchProvider->queryDispatch( aPrepareURL, OUString(), 0 ));
502 if ( xPrepareDispatch.is() )
504 rtl::Reference<PrepareListener_Impl> pPrepareListener = new PrepareListener_Impl;
505 xPrepareDispatch->addStatusListener( pPrepareListener, aPrepareURL );
506 bNeedsPreparation = pPrepareListener->IsSet();
507 xPrepareDispatch->removeStatusListener( pPrepareListener, aPrepareURL );
511 catch ( css::uno::RuntimeException& )
513 throw;
515 catch ( css::uno::Exception& )
520 if ( bModified || !bHasLocation || bStoreTo || bNeedsPreparation )
522 // Document is modified, is newly created or should be stored in a special format
525 if( bNeedsPreparation && xPrepareDispatch.is() )
529 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
530 xPrepareDispatch->dispatch( aPrepareURL, aDispatchArgs );
532 catch ( css::uno::RuntimeException& )
534 throw;
536 catch ( css::uno::Exception& )
541 //check if this is the pdf output filter (i#64555)
542 if( bSendAsPDF )
544 SaveResult eShowPDFFilterDialog = ShowFilterOptionsDialog(
545 xSMGR, xModel, aFilterName, rType, bModified, nNumArgs, aArgs );
547 // don't continue on dialog cancel or error
548 if ( eShowPDFFilterDialog != SAVE_SUCCESSFUL )
549 return eShowPDFFilterDialog;
552 xStorable->storeToURL( aFileURL, aArgs );
553 rFileNamePath = aFileURL;
554 eRet = SAVE_SUCCESSFUL;
556 if( !bSendAsPDF )
558 css::util::URL aURL;
559 // #i30432# notify that export is finished - the Writer may want to restore removed content
560 aURL.Complete = ".uno:MailExportFinished";
561 xURLTransformer->parseStrict( aURL );
563 if ( xDispatchProvider.is() )
565 css::uno::Reference< css::frame::XDispatch > xDispatch(
566 xDispatchProvider->queryDispatch( aURL, OUString(), 0 ));
567 if ( xDispatch.is() )
571 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
572 xDispatch->dispatch( aURL, aDispatchArgs );
574 catch ( css::uno::RuntimeException& )
576 throw;
578 catch ( css::uno::Exception& )
584 // If the model is not modified, it could be modified by the dispatch calls.
585 // Therefore set back to modified = false. This should not hurt if we call
586 // on a non-modified model.
587 if ( !bModified )
591 xModifiable->setModified( false );
593 catch( css::beans::PropertyVetoException& )
598 catch ( css::io::IOException& )
600 eRet = SAVE_ERROR;
603 else
605 // We need 1:1 copy of the document to preserve an added signature.
606 aArgs.realloc( ++nNumArgs );
607 auto pArgs = aArgs.getArray();
608 pArgs[nNumArgs-1].Name = "CopyStreamIfPossible";
609 pArgs[nNumArgs-1].Value <<= true;
613 xStorable->storeToURL( aFileURL, aArgs );
614 rFileNamePath = aFileURL;
615 eRet = SAVE_SUCCESSFUL;
617 catch ( css::io::IOException& )
619 eRet = SAVE_ERROR;
625 return eRet;
628 SfxMailModel::SfxMailModel()
632 SfxMailModel::~SfxMailModel()
636 void SfxMailModel::AddToAddress( const OUString& rAddress )
638 // don't add an empty address
639 if ( !rAddress.isEmpty() )
641 if ( !mpToList )
642 // create the list
643 mpToList.reset(new AddressList_Impl);
645 // add address to list
646 mpToList->push_back( rAddress );
650 SfxMailModel::SendMailResult SfxMailModel::AttachDocument(
651 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
652 const OUString& sAttachmentTitle )
654 OUString sFileName;
656 SaveResult eSaveResult = SaveDocumentAsFormat( sAttachmentTitle, xFrameOrModel, OUString()/*sDocumentType*/, sFileName );
657 if ( eSaveResult == SAVE_SUCCESSFUL && !sFileName.isEmpty() )
658 maAttachedDocuments.push_back(sFileName);
659 return eSaveResult == SAVE_SUCCESSFUL ? SEND_MAIL_OK : SEND_MAIL_ERROR;
662 SfxMailModel::SendMailResult SfxMailModel::Send( const css::uno::Reference< css::frame::XFrame >& xFrame )
664 OSL_ENSURE(!maAttachedDocuments.empty(),"No document added!");
665 SendMailResult eResult = SEND_MAIL_ERROR;
666 if ( !maAttachedDocuments.empty() )
668 css::uno::Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
670 css::uno::Reference< XSimpleMailClientSupplier > xSimpleMailClientSupplier;
672 // Prefer the SimpleSystemMail service if available
673 try {
674 xSimpleMailClientSupplier = SimpleSystemMail::create( xContext );
676 catch ( const uno::Exception & )
679 if ( ! xSimpleMailClientSupplier.is() )
681 try {
682 xSimpleMailClientSupplier = SimpleCommandMail::create( xContext );
684 catch ( const uno::Exception & )
688 if ( xSimpleMailClientSupplier.is() )
690 css::uno::Reference< XSimpleMailClient > xSimpleMailClient = xSimpleMailClientSupplier->querySimpleMailClient();
692 if ( !xSimpleMailClient.is() )
694 // no mail client support => message box!
695 return SEND_MAIL_ERROR;
698 // we have a simple mail client
699 css::uno::Reference< XSimpleMailMessage > xSimpleMailMessage = xSimpleMailClient->createSimpleMailMessage();
700 if ( xSimpleMailMessage.is() )
702 sal_Int32 nSendFlags = SimpleMailClientFlags::DEFAULTS;
703 if ( maFromAddress.isEmpty() )
705 // from address not set, try figure out users e-mail address
706 CreateFromAddress_Impl( maFromAddress );
708 xSimpleMailMessage->setOriginator( maFromAddress );
710 size_t nToCount = mpToList ? mpToList->size() : 0;
712 // set recipient (only one) for this simple mail server!!
713 if ( nToCount >= 1 )
715 xSimpleMailMessage->setRecipient( mpToList->at( 0 ) );
716 nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE;
719 // all other recipient must be handled with CC recipients!
720 if ( nToCount > 1 )
722 Sequence< OUString > aCcRecipientSeq( nToCount - 1 );
723 std::copy_n(std::next(mpToList->begin()), aCcRecipientSeq.getLength(),
724 aCcRecipientSeq.getArray());
725 xSimpleMailMessage->setCcRecipient( aCcRecipientSeq );
728 Sequence< OUString > aAttachmentSeq(maAttachedDocuments.data(),maAttachedDocuments.size());
730 if ( xSimpleMailMessage->getSubject().isEmpty() ) {
731 INetURLObject url(
732 maAttachedDocuments[0], INetURLObject::EncodeMechanism::WasEncoded);
733 OUString subject(
734 url.getBase(
735 INetURLObject::LAST_SEGMENT, false,
736 INetURLObject::DecodeMechanism::WithCharset));
737 if (subject.isEmpty()) {
738 subject = maAttachedDocuments[0];
740 if ( maAttachedDocuments.size() > 1 )
741 subject += ", ...";
742 xSimpleMailMessage->setSubject( subject );
744 xSimpleMailMessage->setAttachement( aAttachmentSeq );
746 bool bSend( false );
749 xSimpleMailClient->sendSimpleMailMessage( xSimpleMailMessage, nSendFlags );
750 bSend = true;
752 catch ( IllegalArgumentException& )
755 catch ( Exception& )
759 if ( !bSend )
761 css::uno::Reference< css::awt::XWindow > xParentWindow = xFrame->getContainerWindow();
763 SolarMutexGuard aGuard;
765 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(Application::GetFrameWeld(xParentWindow), "sfx/ui/errorfindemaildialog.ui"));
766 std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog("ErrorFindEmailDialog"));
767 xBox->run();
768 eResult = SEND_MAIL_CANCELLED;
770 else
771 eResult = SEND_MAIL_OK;
775 else
776 eResult = SEND_MAIL_CANCELLED;
778 return eResult;
781 SfxMailModel::SendMailResult SfxMailModel::SaveAndSend( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& rTypeName )
783 SaveResult eSaveResult;
784 SendMailResult eResult = SEND_MAIL_ERROR;
785 OUString aFileName;
787 eSaveResult = SaveDocumentAsFormat( OUString(), xFrame, rTypeName, aFileName );
789 if ( eSaveResult == SAVE_SUCCESSFUL )
791 maAttachedDocuments.push_back( aFileName );
792 return Send( xFrame );
794 else if ( eSaveResult == SAVE_CANCELLED )
795 eResult = SEND_MAIL_CANCELLED;
797 return eResult;
800 // functions -------------------------------------------------------------
802 bool CreateFromAddress_Impl( OUString& rFrom )
804 /* [Description]
806 This function tries to create a From-address with the help of IniManagers.
807 For this the fields 'first name', 'Name' and 'Email' are read from the
808 application-ini-data. If these fields are not set, FALSE is returned.
810 [Return value]
812 sal_True: Address could be created.
813 sal_False: Address could not be created.
817 SvtUserOptions aUserCFG;
818 OUString aName = aUserCFG.GetLastName ();
819 OUString aFirstName = aUserCFG.GetFirstName ();
820 if ( !aFirstName.isEmpty() || !aName.isEmpty() )
822 if ( !aFirstName.isEmpty() )
824 rFrom = comphelper::string::strip(aFirstName, ' ');
826 if ( !aName.isEmpty() )
827 rFrom += " ";
829 rFrom += comphelper::string::strip(aName, ' ');
830 // remove illegal characters
831 rFrom = rFrom.replaceAll("<", "").replaceAll(">", "").replaceAll("@", "");
833 OUString aEmailName = aUserCFG.GetEmail();
835 // remove illegal characters
836 aEmailName = aEmailName.replaceAll("<", "").replaceAll(">", "");
838 if ( !aEmailName.isEmpty() )
840 if ( !rFrom.isEmpty() )
841 rFrom += " ";
842 rFrom += "<" + comphelper::string::strip(aEmailName, ' ') + ">";
844 else
845 rFrom.clear();
846 return !rFrom.isEmpty();
849 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */