LibreOffice Module sfx2 (master) 1
mailmodel.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <com/sun/star/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>
46
47#include <sfx2/mailmodelapi.hxx>
48#include <sfx2/sfxresid.hxx>
49#include <sfx2/strings.hrc>
50
51#include <unotools/tempfile.hxx>
52#include <tools/urlobj.hxx>
57#include <comphelper/string.hxx>
58#include <vcl/svapp.hxx>
60
61
62using namespace ::com::sun::star;
63using namespace ::com::sun::star::beans;
64using namespace ::com::sun::star::frame;
65using namespace ::com::sun::star::io;
66using namespace ::com::sun::star::lang;
67using namespace ::com::sun::star::ucb;
68using namespace ::com::sun::star::uno;
69using namespace ::com::sun::star::util;
70using namespace ::com::sun::star::system;
71
72namespace {
73
74// - class PrepareListener_Impl ------------------------------------------
75class PrepareListener_Impl : public ::cppu::WeakImplHelper< css::frame::XStatusListener >
76{
77 bool m_bState;
78public:
79 PrepareListener_Impl();
80
81 // css.frame.XStatusListener
82 virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& aEvent) override;
83
84 // css.lang.XEventListener
85 virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
86
87 bool IsSet() const {return m_bState;}
88};
89
90}
91
92PrepareListener_Impl::PrepareListener_Impl() :
93 m_bState( false )
94{
95}
96
97void PrepareListener_Impl::statusChanged(const css::frame::FeatureStateEvent& rEvent)
98{
99 if( rEvent.IsEnabled )
100 rEvent.State >>= m_bState;
101 else
102 m_bState = false;
103}
104
105void PrepareListener_Impl::disposing(const css::lang::EventObject& /*rEvent*/)
106{
107}
108
109// class SfxMailModel -----------------------------------------------
110
111const char16_t PDF_DOCUMENT_TYPE[] = u"pdf_Portable_Document_Format";
112
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 )
121{
122 SaveResult eRet( SAVE_ERROR );
123
124 try
125 {
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 );
130
131 if ( !xFilterCFG.is() )
132 return eRet;
133
134 uno::Any aAny = xFilterCFG->getByName( rFilterName );
135
136 if ( aAny >>= aProps )
137 {
138 for( const auto& rProp : std::as_const(aProps) )
139 {
140 if( rProp.Name == "UIComponent" )
141 {
142 OUString aServiceName;
143 rProp.Value >>= aServiceName;
144 if( !aServiceName.isEmpty() )
145 {
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 );
150
151 if( xFilterDialog.is() && xFilterProperties.is() )
152 {
153 uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY );
154
155 if ( rType == PDF_DOCUMENT_TYPE )
156 {
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 ))
163 };
164
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)
168 };
169
170 //when executing the dialog will merge the persistent FilterData properties
171 xFilterProperties->setPropertyValues( aPropsForDialog );
172 }
173
174 if( xExporter.is() )
175 xExporter->setSourceDocument( xModel );
176
177 if( xFilterDialog->execute() )
178 {
179 //get the filter data
180 const uno::Sequence< beans::PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
181
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())
186 {
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;
192 }
193 eRet = SAVE_SUCCESSFUL;
194 }
195 else
196 {
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 )
202 {
203 try
204 {
205 xModifiable->setModified( false );
206 }
207 catch( css::beans::PropertyVetoException& )
208 {
209 }
210 }
211 eRet = SAVE_CANCELLED;
212 }
213 }
214 break;
215 }
216 }
217 }
218 }
219 }
220 catch( css::uno::RuntimeException& )
221 {
222 throw;
223 }
224 catch( uno::Exception& )
225 {
226 }
227
228 return eRet;
229}
230
232{
233 return maAttachedDocuments.empty();
234}
235
237 const OUString& aSaveFileName,
238 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
239 const OUString& rType,
240 OUString& rFileNamePath )
241{
242 SaveResult eRet( SAVE_ERROR );
243 bool bSendAsPDF = ( rType == PDF_DOCUMENT_TYPE );
244
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;
249
250 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager( css::frame::ModuleManager::create(xContext) );
251
252 OUString aModule;
253 try
254 {
255 aModule = xModuleManager->identify( xFrameOrModel );
256 }
257 catch ( css::uno::RuntimeException& )
258 {
259 throw;
260 }
261 catch ( css::uno::Exception& )
262 {
263 }
264
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() )
268 {
269 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
270 if ( xController.is() )
271 xModel = xController->getModel();
272 }
273
274 // We need at least a valid module name and model reference
275 if ( !aModule.isEmpty() && xModel.is() )
276 {
277 bool bModified( false );
278 bool bHasLocation( false );
279 bool bStoreTo( false );
280
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 );
283
284 if ( xModifiable.is() )
285 bModified = xModifiable->isModified();
286 if ( xStorable.is() )
287 {
288 OUString aLocation = xStorable->getLocation();
289 INetURLObject aFileObj( aLocation );
290
291 bool bPrivateProtocol = ( aFileObj.GetProtocol() == INetProtocol::PrivSoffice );
292
293 bHasLocation = !aLocation.isEmpty() && !bPrivateProtocol;
294 OSL_ASSERT( !bPrivateProtocol );
295 }
296 if ( !rType.isEmpty() )
297 bStoreTo = true;
298
299 if ( xStorable.is() )
300 {
301 OUString aFilterName;
302 OUString aTypeName( rType );
303 OUString aFileName;
304 OUString aExtension;
305
306 css::uno::Reference< css::container::XContainerQuery > xContainerQuery(
307 xSMGR->createInstance( "com.sun.star.document.FilterFactory" ),
308 css::uno::UNO_QUERY );
309
310 if ( bStoreTo )
311 {
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 )
320 {
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
328 }
329
330 css::uno::Reference< css::container::XEnumeration > xEnumeration =
331 xContainerQuery->createSubSetEnumerationByProperties( aQuery );
332
333 if ( xEnumeration->hasMoreElements() )
334 {
335 ::comphelper::SequenceAsHashMap aFilterPropsHM( xEnumeration->nextElement() );
336 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
337 "Name",
338 OUString() );
339 }
340
341 if ( bHasLocation )
342 {
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 )
349 {
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;
354 }
355 }
356 }
357 else
358 {
359 if ( bHasLocation )
360 {
361 // Retrieve filter from media descriptor
362 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
363 aFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
364 "FilterName",
365 OUString() );
366 }
367
368 if ( !bHasLocation || aFilterName.isEmpty())
369 {
370 // Retrieve the user defined default filter
371 try
372 {
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() )
380 {
381 ::comphelper::SequenceAsHashMap aFilterPropsHM2( xNameAccess->getByName( aFilterName ) );
382 aTypeName = aFilterPropsHM2.getUnpackedValueOrDefault(
383 "Type",
384 OUString() );
385 }
386 }
387 catch ( css::container::NoSuchElementException& )
388 {
389 }
390 catch ( css::beans::UnknownPropertyException& )
391 {
392 }
393 }
394 }
395
396 // No filter found => error
397 // No type and no location => error
398 if (( aFilterName.isEmpty() ) ||
399 ( aTypeName.isEmpty() && !bHasLocation ))
400 return eRet;
401
402 // Determine file name and extension
403 if ( bHasLocation && !bStoreTo )
404 {
405 INetURLObject aFileObj( xStorable->getLocation() );
406 aExtension = aFileObj.getExtension();
407 }
408 else
409 {
410 css::uno::Reference< container::XNameAccess > xTypeDetection(
411 xSMGR->createInstance( "com.sun.star.document.TypeDetection" ),
412 css::uno::UNO_QUERY );
413
414
415 if ( xTypeDetection.is() )
416 {
417 try
418 {
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];
425 }
426 catch ( css::container::NoSuchElementException& )
427 {
428 }
429 }
430 }
431
432 // Use provided save file name. If empty determine file name
433 aFileName = aSaveFileName;
434 if ( aFileName.isEmpty() )
435 {
436 if ( !bHasLocation )
437 {
438 // Create a noname file name with the correct extension
439 aFileName = "noname";
440 }
441 else
442 {
443 // Determine file name from model
444 INetURLObject aFileObj( xStorable->getLocation() );
446 }
447 }
448
449 // No file name => error
450 if ( aFileName.isEmpty() )
451 return eRet;
452
453 OSL_ASSERT( !aFilterName.isEmpty() );
454 OSL_ASSERT( !aFileName.isEmpty() );
455
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 INetURLObject aFilePathObj( ::utl::CreateTempURL(nullptr, true) );
461 aFilePathObj.insertName( aFileName );
462 aFilePathObj.setExtension( aExtension );
463
464 OUString aFileURL = aFilePathObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
465
466 sal_Int32 nNumArgs(1);
467 static constexpr OUStringLiteral aPasswordPropName( u"Password" );
468 css::uno::Sequence< css::beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
469 "FilterName", aFilterName) };
470
471 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
472 OUString aPassword = aMediaDescrPropsHM.getUnpackedValueOrDefault(
473 aPasswordPropName,
474 OUString() );
475 if ( !aPassword.isEmpty() )
476 {
477 aArgs.realloc( ++nNumArgs );
478 auto pArgs = aArgs.getArray();
479 pArgs[nNumArgs-1].Name = aPasswordPropName;
480 pArgs[nNumArgs-1].Value <<= aPassword;
481 }
482
483 bool bNeedsPreparation = false;
484 css::util::URL aPrepareURL;
485 css::uno::Reference< css::frame::XDispatch > xPrepareDispatch;
486 css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( xFrame, css::uno::UNO_QUERY );
487 css::uno::Reference< css::util::XURLTransformer > xURLTransformer( css::util::URLTransformer::create( xContext ) );
488 if( !bSendAsPDF )
489 {
490 try
491 {
492 // check if the document needs to be prepared for sending as mail (embedding of links, removal of invisible content)
493
494 aPrepareURL.Complete = ".uno:PrepareMailExport";
495 xURLTransformer->parseStrict( aPrepareURL );
496
497 if ( xDispatchProvider.is() )
498 {
499 xPrepareDispatch.set( xDispatchProvider->queryDispatch( aPrepareURL, OUString(), 0 ));
500 if ( xPrepareDispatch.is() )
501 {
502 rtl::Reference<PrepareListener_Impl> pPrepareListener = new PrepareListener_Impl;
503 xPrepareDispatch->addStatusListener( pPrepareListener, aPrepareURL );
504 bNeedsPreparation = pPrepareListener->IsSet();
505 xPrepareDispatch->removeStatusListener( pPrepareListener, aPrepareURL );
506 }
507 }
508 }
509 catch ( css::uno::RuntimeException& )
510 {
511 throw;
512 }
513 catch ( css::uno::Exception& )
514 {
515 }
516 }
517
518 if ( bModified || !bHasLocation || bStoreTo || bNeedsPreparation )
519 {
520 // Document is modified, is newly created or should be stored in a special format
521 try
522 {
523 if( bNeedsPreparation && xPrepareDispatch.is() )
524 {
525 try
526 {
527 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
528 xPrepareDispatch->dispatch( aPrepareURL, aDispatchArgs );
529 }
530 catch ( css::uno::RuntimeException& )
531 {
532 throw;
533 }
534 catch ( css::uno::Exception& )
535 {
536 }
537 }
538
539 //check if this is the pdf output filter (i#64555)
540 if( bSendAsPDF )
541 {
542 SaveResult eShowPDFFilterDialog = ShowFilterOptionsDialog(
543 xSMGR, xModel, aFilterName, rType, bModified, nNumArgs, aArgs );
544
545 // don't continue on dialog cancel or error
546 if ( eShowPDFFilterDialog != SAVE_SUCCESSFUL )
547 return eShowPDFFilterDialog;
548 }
549
550 xStorable->storeToURL( aFileURL, aArgs );
551 rFileNamePath = aFileURL;
552 eRet = SAVE_SUCCESSFUL;
553
554 if( !bSendAsPDF )
555 {
556 css::util::URL aURL;
557 // #i30432# notify that export is finished - the Writer may want to restore removed content
558 aURL.Complete = ".uno:MailExportFinished";
559 xURLTransformer->parseStrict( aURL );
560
561 if ( xDispatchProvider.is() )
562 {
563 css::uno::Reference< css::frame::XDispatch > xDispatch(
564 xDispatchProvider->queryDispatch( aURL, OUString(), 0 ));
565 if ( xDispatch.is() )
566 {
567 try
568 {
569 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
570 xDispatch->dispatch( aURL, aDispatchArgs );
571 }
572 catch ( css::uno::RuntimeException& )
573 {
574 throw;
575 }
576 catch ( css::uno::Exception& )
577 {
578 }
579 }
580 }
581 }
582 // If the model is not modified, it could be modified by the dispatch calls.
583 // Therefore set back to modified = false. This should not hurt if we call
584 // on a non-modified model.
585 if ( !bModified )
586 {
587 try
588 {
589 xModifiable->setModified( false );
590 }
591 catch( css::beans::PropertyVetoException& )
592 {
593 }
594 }
595 }
596 catch ( css::io::IOException& )
597 {
598 eRet = SAVE_ERROR;
599 }
600 }
601 else
602 {
603 // We need 1:1 copy of the document to preserve an added signature.
604 aArgs.realloc( ++nNumArgs );
605 auto pArgs = aArgs.getArray();
606 pArgs[nNumArgs-1].Name = "CopyStreamIfPossible";
607 pArgs[nNumArgs-1].Value <<= true;
608
609 try
610 {
611 xStorable->storeToURL( aFileURL, aArgs );
612 rFileNamePath = aFileURL;
613 eRet = SAVE_SUCCESSFUL;
614 }
615 catch ( css::io::IOException& )
616 {
617 eRet = SAVE_ERROR;
618 }
619 }
620 }
621 }
622
623 return eRet;
624}
625
627{
628}
629
631{
632}
633
634void SfxMailModel::AddToAddress( const OUString& rAddress )
635{
636 // don't add an empty address
637 if ( !rAddress.isEmpty() )
638 {
639 if ( !mpToList )
640 // create the list
641 mpToList.reset(new AddressList_Impl);
642
643 // add address to list
644 mpToList->push_back( rAddress );
645 }
646}
647
649 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
650 const OUString& sAttachmentTitle )
651{
652 OUString sFileName;
653
654 SaveResult eSaveResult = SaveDocumentAsFormat( sAttachmentTitle, xFrameOrModel, OUString()/*sDocumentType*/, sFileName );
655 if ( eSaveResult == SAVE_SUCCESSFUL && !sFileName.isEmpty() )
656 maAttachedDocuments.push_back(sFileName);
657 return eSaveResult == SAVE_SUCCESSFUL ? SEND_MAIL_OK : SEND_MAIL_ERROR;
658}
659
660SfxMailModel::SendMailResult SfxMailModel::Send( const css::uno::Reference< css::frame::XFrame >& xFrame )
661{
662 OSL_ENSURE(!maAttachedDocuments.empty(),"No document added!");
664 if ( !maAttachedDocuments.empty() )
665 {
666 css::uno::Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
667
668 css::uno::Reference< XSimpleMailClientSupplier > xSimpleMailClientSupplier;
669
670 // Prefer the SimpleSystemMail service if available
671 try {
672 xSimpleMailClientSupplier = SimpleSystemMail::create( xContext );
673 }
674 catch ( const uno::Exception & )
675 {}
676
677 if ( ! xSimpleMailClientSupplier.is() )
678 {
679 try {
680 xSimpleMailClientSupplier = SimpleCommandMail::create( xContext );
681 }
682 catch ( const uno::Exception & )
683 {}
684 }
685
686 if ( xSimpleMailClientSupplier.is() )
687 {
688 css::uno::Reference< XSimpleMailClient > xSimpleMailClient = xSimpleMailClientSupplier->querySimpleMailClient();
689
690 if ( !xSimpleMailClient.is() )
691 {
692 // no mail client support => message box!
693 return SEND_MAIL_ERROR;
694 }
695
696 // we have a simple mail client
697 css::uno::Reference< XSimpleMailMessage > xSimpleMailMessage = xSimpleMailClient->createSimpleMailMessage();
698 if ( xSimpleMailMessage.is() )
699 {
700 sal_Int32 nSendFlags = SimpleMailClientFlags::DEFAULTS;
701 if ( maFromAddress.isEmpty() )
702 {
703 // from address not set, try figure out users e-mail address
705 }
706 xSimpleMailMessage->setOriginator( maFromAddress );
707
708 size_t nToCount = mpToList ? mpToList->size() : 0;
709
710 // set recipient (only one) for this simple mail server!!
711 if ( nToCount >= 1 )
712 {
713 xSimpleMailMessage->setRecipient( mpToList->at( 0 ) );
714 nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE;
715 }
716
717 // all other recipient must be handled with CC recipients!
718 if ( nToCount > 1 )
719 {
720 Sequence< OUString > aCcRecipientSeq( nToCount - 1 );
721 std::copy_n(std::next(mpToList->begin()), aCcRecipientSeq.getLength(),
722 aCcRecipientSeq.getArray());
723 xSimpleMailMessage->setCcRecipient( aCcRecipientSeq );
724 }
725
726 Sequence< OUString > aAttachmentSeq(maAttachedDocuments.data(),maAttachedDocuments.size());
727
728 if ( xSimpleMailMessage->getSubject().isEmpty() ) {
729 INetURLObject url(
731 OUString subject(
732 url.getBase(
735 if (subject.isEmpty()) {
736 subject = maAttachedDocuments[0];
737 }
738 if ( maAttachedDocuments.size() > 1 )
739 subject += ", ...";
740 xSimpleMailMessage->setSubject( subject );
741 }
742 xSimpleMailMessage->setAttachement( aAttachmentSeq );
743
744 bool bSend( false );
745 try
746 {
747 xSimpleMailClient->sendSimpleMailMessage( xSimpleMailMessage, nSendFlags );
748 bSend = true;
749 }
750 catch ( IllegalArgumentException& )
751 {
752 }
753 catch ( Exception& )
754 {
755 }
756
757 if ( !bSend )
758 {
759 css::uno::Reference< css::awt::XWindow > xParentWindow = xFrame->getContainerWindow();
760
761 SolarMutexGuard aGuard;
762
763 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(Application::GetFrameWeld(xParentWindow), "sfx/ui/errorfindemaildialog.ui"));
764 std::unique_ptr<weld::MessageDialog> xBox(xBuilder->weld_message_dialog("ErrorFindEmailDialog"));
765 xBox->run();
766 eResult = SEND_MAIL_CANCELLED;
767 }
768 else
769 eResult = SEND_MAIL_OK;
770 }
771 }
772 }
773 else
774 eResult = SEND_MAIL_CANCELLED;
775
776 return eResult;
777}
778
779SfxMailModel::SendMailResult SfxMailModel::SaveAndSend( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& rTypeName )
780{
781 SaveResult eSaveResult;
783 OUString aFileName;
784
785 eSaveResult = SaveDocumentAsFormat( OUString(), xFrame, rTypeName, aFileName );
786
787 if ( eSaveResult == SAVE_SUCCESSFUL )
788 {
789 maAttachedDocuments.push_back( aFileName );
790 return Send( xFrame );
791 }
792 else if ( eSaveResult == SAVE_CANCELLED )
793 eResult = SEND_MAIL_CANCELLED;
794
795 return eResult;
796}
797
798// functions -------------------------------------------------------------
799
800bool CreateFromAddress_Impl( OUString& rFrom )
801
802/* [Description]
803
804 This function tries to create a From-address with the help of IniManagers.
805 For this the fields 'first name', 'Name' and 'Email' are read from the
806 application-ini-data. If these fields are not set, FALSE is returned.
807
808 [Return value]
809
810 sal_True: Address could be created.
811 sal_False: Address could not be created.
812*/
813
814{
815 SvtUserOptions aUserCFG;
816 OUString aName = aUserCFG.GetLastName ();
817 OUString aFirstName = aUserCFG.GetFirstName ();
818 if ( !aFirstName.isEmpty() || !aName.isEmpty() )
819 {
820 if ( !aFirstName.isEmpty() )
821 {
822 rFrom = comphelper::string::strip(aFirstName, ' ');
823
824 if ( !aName.isEmpty() )
825 rFrom += " ";
826 }
827 rFrom += comphelper::string::strip(aName, ' ');
828 // remove illegal characters
829 rFrom = rFrom.replaceAll("<", "").replaceAll(">", "").replaceAll("@", "");
830 }
831 OUString aEmailName = aUserCFG.GetEmail();
832
833 // remove illegal characters
834 aEmailName = aEmailName.replaceAll("<", "").replaceAll(">", "");
835
836 if ( !aEmailName.isEmpty() )
837 {
838 if ( !rFrom.isEmpty() )
839 rFrom += " ";
840 rFrom += "<" + comphelper::string::strip(aEmailName, ' ') + ">";
841 }
842 else
843 rFrom.clear();
844 return !rFrom.isEmpty();
845}
846
847/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static weld::Window * GetFrameWeld(const css::uno::Reference< css::awt::XWindow > &rWindow)
static std::unique_ptr< weld::Builder > CreateBuilder(weld::Widget *pParent, const OUString &rUIFile, bool bMobile=false, sal_uInt64 nLOKWindowId=0)
OUString getName(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString getExtension(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
OUString getBase(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool insertName(std::u16string_view rTheName, bool bAppendFinalSlash=false, sal_Int32 nIndex=LAST_SEGMENT, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
INetProtocol GetProtocol() const
bool setExtension(std::u16string_view rTheExtension, sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
SendMailResult AttachDocument(const css::uno::Reference< css::uno::XInterface > &xFrameOrModel, const OUString &sAttachmentTitle)
attaches a document to the current attachment list, can be called more than once.
Definition: mailmodel.cxx:648
void AddToAddress(const OUString &rAddress)
Definition: mailmodel.cxx:634
std::unique_ptr< AddressList_Impl > mpToList
bool IsEmpty() const
Definition: mailmodel.cxx:231
::std::vector< OUString > maAttachedDocuments
static SaveResult ShowFilterOptionsDialog(const css::uno::Reference< css::lang::XMultiServiceFactory > &xSMGR, const css::uno::Reference< css::frame::XModel > &xModel, const OUString &rFilterName, std::u16string_view rType, bool bModified, sal_Int32 &rNumArgs, css::uno::Sequence< css::beans::PropertyValue > &rArgs)
Definition: mailmodel.cxx:113
SendMailResult Send(const css::uno::Reference< css::frame::XFrame > &xFrame)
Definition: mailmodel.cxx:660
SendMailResult SaveAndSend(const css::uno::Reference< css::frame::XFrame > &xFrame, const OUString &rType)
Definition: mailmodel.cxx:779
static SaveResult SaveDocumentAsFormat(const OUString &aSaveFileName, const css::uno::Reference< css::uno::XInterface > &xFrameOrModel, const OUString &rType, OUString &rFileNamePath)
Definition: mailmodel.cxx:236
OUString maFromAddress
OUString GetFirstName() const
OUString GetEmail() const
OUString GetLastName() const
TValueType getUnpackedValueOrDefault(const OUString &sKey, const TValueType &aDefault) const
Reference< XDispatch > xDispatch
URL aURL
float u
OUString aName
const char16_t PDF_DOCUMENT_TYPE[]
Definition: mailmodel.cxx:111
bool CreateFromAddress_Impl(OUString &rFrom)
Definition: mailmodel.cxx:800
::std::vector< OUString > AddressList_Impl
@ Exception
OString strip(const OString &rIn, char c)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
OUString SfxResId(TranslateId aId)
Definition: sfxresid.cxx:22
Object Value
Reference< XController > xController
Reference< XFrame > xFrame
Reference< XModel > xModel