Bump version to 4.1-6
[LibreOffice.git] / sfx2 / source / dialog / mailmodel.cxx
blob8df390fd1f20cb2ec47c88139ea13f4bc180fea0
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/beans/XPropertySet.hpp>
23 #include <com/sun/star/container/XContainerQuery.hpp>
24 #include <com/sun/star/document/XExporter.hpp>
25 #include <com/sun/star/embed/XStorage.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <com/sun/star/embed/XTransactedObject.hpp>
28 #include <com/sun/star/frame/XDispatchProvider.hpp>
29 #include <com/sun/star/frame/XDispatch.hpp>
30 #include <com/sun/star/frame/XStatusListener.hpp>
31 #include <com/sun/star/frame/XFrame.hpp>
32 #include <com/sun/star/frame/XModel.hpp>
33 #include <com/sun/star/frame/ModuleManager.hpp>
34 #include <com/sun/star/frame/XStorable.hpp>
35 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 #include <com/sun/star/security/CertificateValidity.hpp>
37 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
38 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
39 #include <com/sun/star/system/SimpleSystemMail.hpp>
40 #include <com/sun/star/system/SimpleCommandMail.hpp>
41 #include <com/sun/star/system/XSimpleMailClientSupplier.hpp>
42 #include <com/sun/star/system/SimpleMailClientFlags.hpp>
43 #include <com/sun/star/ucb/CommandAbortedException.hpp>
44 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
45 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
46 #include <com/sun/star/uno/Reference.h>
47 #include <com/sun/star/util/URLTransformer.hpp>
48 #include <com/sun/star/util/XURLTransformer.hpp>
49 #include <com/sun/star/util/XModifiable.hpp>
50 #include <rtl/textenc.h>
51 #include <rtl/uri.h>
52 #include <rtl/uri.hxx>
53 #include <rtl/ustrbuf.hxx>
54 #include <vcl/msgbox.hxx>
56 #include <sfx2/mailmodelapi.hxx>
57 #include "sfxtypes.hxx"
58 #include "sfx2/sfxresid.hxx"
59 #include <sfx2/sfxsids.hrc>
60 #include "dialog.hrc"
62 #include <unotools/tempfile.hxx>
63 #include <unotools/configitem.hxx>
64 #include <ucbhelper/content.hxx>
65 #include <tools/urlobj.hxx>
66 #include <unotools/useroptions.hxx>
67 #include <comphelper/extract.hxx>
68 #include <comphelper/mediadescriptor.hxx>
69 #include <comphelper/processfactory.hxx>
70 #include <comphelper/sequenceashashmap.hxx>
71 #include <comphelper/sequenceasvector.hxx>
72 #include <comphelper/storagehelper.hxx>
73 #include <comphelper/string.hxx>
74 #include <toolkit/helper/vclunohelper.hxx>
75 #include <vcl/svapp.hxx>
76 #include <cppuhelper/implbase1.hxx>
78 // --------------------------------------------------------------
79 using namespace ::com::sun::star;
80 using namespace ::com::sun::star::beans;
81 using namespace ::com::sun::star::frame;
82 using namespace ::com::sun::star::io;
83 using namespace ::com::sun::star::lang;
84 using namespace ::com::sun::star::ucb;
85 using namespace ::com::sun::star::uno;
86 using namespace ::com::sun::star::util;
87 using namespace ::com::sun::star::system;
88 using namespace ::rtl;
90 // - class PrepareListener_Impl ------------------------------------------
91 class PrepareListener_Impl : public ::cppu::WeakImplHelper1< css::frame::XStatusListener >
93 bool m_bState;
94 public:
95 PrepareListener_Impl();
96 virtual ~PrepareListener_Impl();
98 // css.frame.XStatusListener
99 virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& aEvent)
100 throw(css::uno::RuntimeException);
102 // css.lang.XEventListener
103 virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent)
104 throw(css::uno::RuntimeException);
106 bool IsSet() const {return m_bState;}
109 PrepareListener_Impl::PrepareListener_Impl() :
110 m_bState( false )
114 PrepareListener_Impl::~PrepareListener_Impl()
118 void PrepareListener_Impl::statusChanged(const css::frame::FeatureStateEvent& rEvent) throw(css::uno::RuntimeException)
120 if( rEvent.IsEnabled )
121 rEvent.State >>= m_bState;
122 else
123 m_bState = sal_False;
126 void PrepareListener_Impl::disposing(const css::lang::EventObject& /*rEvent*/) throw(css::uno::RuntimeException)
130 // class SfxMailModel -----------------------------------------------
132 static const char PDF_DOCUMENT_TYPE[] = "pdf_Portable_Document_Format";
134 void SfxMailModel::ClearList( AddressList_Impl* pList )
136 if ( pList )
138 for( size_t i = 0, n = pList->size(); i < n; ++i )
139 delete pList->at(i);
140 pList->clear();
144 sal_Bool HasDocumentValidSignature( const css::uno::Reference< css::frame::XModel >& xModel )
148 css::uno::Reference< css::beans::XPropertySet > xPropSet( xModel, css::uno::UNO_QUERY );
149 if ( xPropSet.is() )
151 Any a = xPropSet->getPropertyValue( OUString( "HasValidSignatures" ));
152 sal_Bool bReturn = sal_Bool();
153 if ( a >>= bReturn )
154 return bReturn;
157 catch ( css::uno::RuntimeException& )
159 throw;
161 catch ( css::uno::Exception& )
165 return sal_False;
168 SfxMailModel::SaveResult SfxMailModel::ShowFilterOptionsDialog(
169 uno::Reference< lang::XMultiServiceFactory > xSMGR,
170 uno::Reference< frame::XModel > xModel,
171 const OUString& rFilterName,
172 const OUString& rType,
173 bool bModified,
174 sal_Int32& rNumArgs,
175 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs )
177 SaveResult eRet( SAVE_ERROR );
181 uno::Sequence < beans::PropertyValue > aProps;
182 ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > xFilterCFG =
183 uno::Reference< container::XNameAccess >(
184 xSMGR->createInstance(
185 OUString("com.sun.star.document.FilterFactory") ), uno::UNO_QUERY );
186 css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY );
188 if ( !xFilterCFG.is() )
189 return eRet;
191 uno::Any aAny = xFilterCFG->getByName( rFilterName );
193 if ( aAny >>= aProps )
195 sal_Int32 nPropertyCount = aProps.getLength();
196 for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty )
198 if( aProps[nProperty].Name == "UIComponent" )
200 OUString aServiceName;
201 aProps[nProperty].Value >>= aServiceName;
202 if( !aServiceName.isEmpty() )
204 uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog(
205 xSMGR->createInstance( aServiceName ), uno::UNO_QUERY );
206 uno::Reference< beans::XPropertyAccess > xFilterProperties(
207 xFilterDialog, uno::UNO_QUERY );
209 if( xFilterDialog.is() && xFilterProperties.is() )
211 uno::Sequence< beans::PropertyValue > aPropsForDialog(1);
212 uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY );
214 if ( rType == PDF_DOCUMENT_TYPE )
216 //add an internal property, used to tell the dialog we want to set a different
217 //string for the ok button
218 //used in filter/source/pdf/impdialog.cxx
219 uno::Sequence< beans::PropertyValue > aFilterDataValue(1);
220 aFilterDataValue[0].Name = OUString( "_OkButtonString" );
221 aFilterDataValue[0].Value = css::uno::makeAny(SfxResId(STR_PDF_EXPORT_SEND ).toString());
223 //add to the filterdata property, the only one the PDF export filter dialog will care for
224 aPropsForDialog[0].Name = OUString( "FilterData" );
225 aPropsForDialog[0].Value = css::uno::makeAny( aFilterDataValue );
227 //when executing the dialog will merge the persistent FilterData properties
228 xFilterProperties->setPropertyValues( aPropsForDialog );
231 if( xExporter.is() )
232 xExporter->setSourceDocument(
233 uno::Reference< lang::XComponent >( xModel, uno::UNO_QUERY ) );
235 if( xFilterDialog->execute() )
237 //get the filter data
238 uno::Sequence< beans::PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
240 //add them to the args
241 for ( sal_Int32 nInd = 0; nInd < aPropsFromDialog.getLength(); nInd++ )
243 if( aPropsFromDialog[ nInd ].Name == "FilterData" )
245 //found the filterdata, add to the storing argument
246 rArgs.realloc( ++rNumArgs );
247 rArgs[rNumArgs-1].Name = aPropsFromDialog[ nInd ].Name;
248 rArgs[rNumArgs-1].Value = aPropsFromDialog[ nInd ].Value;
249 break;
252 eRet = SAVE_SUCCESSFULL;
254 else
256 // cancel from dialog, then do not send
257 // If the model is not modified, it could be modified by the dispatch calls.
258 // Therefore set back to modified = false. This should not hurt if we call
259 // on a non-modified model.
260 if ( !bModified )
264 xModifiable->setModified( sal_False );
266 catch( com::sun::star::beans::PropertyVetoException& )
270 eRet = SAVE_CANCELLED;
273 break;
279 catch( css::uno::RuntimeException& )
281 throw;
283 catch( uno::Exception& )
287 return eRet;
290 sal_Bool SfxMailModel::IsEmpty() const
292 return maAttachedDocuments.empty();
295 SfxMailModel::SaveResult SfxMailModel::SaveDocumentAsFormat(
296 const OUString& aSaveFileName,
297 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
298 const OUString& rType,
299 OUString& rFileNamePath )
301 SaveResult eRet( SAVE_ERROR );
302 bool bSendAsPDF = ( rType == PDF_DOCUMENT_TYPE );
304 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::comphelper::getProcessServiceFactory();
305 css::uno::Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
306 if (!xContext.is())
307 return eRet;
309 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager( css::frame::ModuleManager::create(xContext) );
311 OUString aModule;
314 aModule = xModuleManager->identify( xFrameOrModel );
316 catch ( css::uno::RuntimeException& )
318 throw;
320 catch ( css::uno::Exception& )
324 css::uno::Reference< css::frame::XFrame > xFrame( xFrameOrModel, css::uno::UNO_QUERY );
325 css::uno::Reference< css::frame::XModel > xModel( xFrameOrModel, css::uno::UNO_QUERY );
326 if ( xFrame.is() )
328 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
329 if ( xController.is() )
330 xModel = xController->getModel();
333 // We need at least a valid module name and model reference
334 if ( !aModule.isEmpty() && xModel.is() )
336 bool bModified( false );
337 bool bHasLocation( false );
338 bool bStoreTo( false );
340 css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY );
341 css::uno::Reference< css::frame::XStorable > xStorable( xModel, css::uno::UNO_QUERY );
343 if ( xModifiable.is() )
344 bModified = xModifiable->isModified();
345 if ( xStorable.is() )
347 OUString aLocation = xStorable->getLocation();
348 INetURLObject aFileObj( aLocation );
350 bool bPrivateProtocol = ( aFileObj.GetProtocol() == INET_PROT_PRIV_SOFFICE );
352 bHasLocation = !aLocation.isEmpty() && !bPrivateProtocol;
353 OSL_ASSERT( !bPrivateProtocol );
355 if ( !rType.isEmpty() )
356 bStoreTo = true;
358 if ( xStorable.is() )
360 OUString aFilterName;
361 OUString aTypeName( rType );
362 OUString aFileName;
363 OUString aExtension;
365 css::uno::Reference< css::container::XContainerQuery > xContainerQuery(
366 xSMGR->createInstance( OUString(
367 "com.sun.star.document.FilterFactory" )),
368 css::uno::UNO_QUERY );
370 if ( bStoreTo )
372 // Retrieve filter from type
373 css::uno::Sequence< css::beans::NamedValue > aQuery( bSendAsPDF ? 3 : 2 );
374 aQuery[0].Name = OUString( "Type" );
375 aQuery[0].Value = css::uno::makeAny( aTypeName );
376 aQuery[1].Name = OUString( "DocumentService" );
377 aQuery[1].Value = css::uno::makeAny( aModule );
378 if( bSendAsPDF )
380 // #i91419#
381 // FIXME: we want just an export filter. However currently we need
382 // exact flag value as detailed in the filter configuration to get it
383 // this seems to be a bug
384 // without flags we get an import filter here, which is also unwanted
385 aQuery[2].Name = OUString( "Flags" );
386 aQuery[2].Value = css::uno::makeAny( sal_Int32(0x80042) ); // EXPORT ALIEN 3RDPARTY
389 css::uno::Reference< css::container::XEnumeration > xEnumeration =
390 xContainerQuery->createSubSetEnumerationByProperties( aQuery );
392 if ( xEnumeration->hasMoreElements() )
394 ::comphelper::SequenceAsHashMap aFilterPropsHM( xEnumeration->nextElement() );
395 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
396 OUString("Name"),
397 OUString() );
400 if ( bHasLocation )
402 // Retrieve filter from media descriptor
403 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
404 OUString aOrgFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
405 OUString( "FilterName" ),
406 OUString() );
407 if ( aOrgFilterName == aFilterName )
409 // We should save the document in the original format. Therefore this
410 // is not a storeTo operation. To support signing in this case, reset
411 // bStoreTo flag.
412 bStoreTo = false;
416 else
418 if ( bHasLocation )
420 // Retrieve filter from media descriptor
421 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
422 aFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
423 OUString( "FilterName" ),
424 OUString() );
427 if ( !bHasLocation || aFilterName.isEmpty())
429 // Retrieve the user defined default filter
432 ::comphelper::SequenceAsHashMap aFilterPropsHM( xModuleManager->getByName( aModule ) );
433 aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
434 OUString("ooSetupFactoryDefaultFilter"),
435 OUString() );
436 css::uno::Reference< css::container::XNameAccess > xNameAccess(
437 xContainerQuery, css::uno::UNO_QUERY );
438 if ( xNameAccess.is() )
440 ::comphelper::SequenceAsHashMap aFilterPropsHM2( xNameAccess->getByName( aFilterName ) );
441 aTypeName = aFilterPropsHM2.getUnpackedValueOrDefault(
442 OUString("Type"),
443 OUString() );
446 catch ( css::container::NoSuchElementException& )
449 catch ( css::beans::UnknownPropertyException& )
455 // No filter found => error
456 // No type and no location => error
457 if (( aFilterName.isEmpty() ) ||
458 ( aTypeName.isEmpty() && !bHasLocation ))
459 return eRet;
461 // Determine filen name and extension
462 if ( bHasLocation && !bStoreTo )
464 INetURLObject aFileObj( xStorable->getLocation() );
465 aExtension = (OUString)aFileObj.getExtension();
467 else
469 css::uno::Reference< container::XNameAccess > xTypeDetection(
470 xSMGR->createInstance( OUString(
471 "com.sun.star.document.TypeDetection" )),
472 css::uno::UNO_QUERY );
475 if ( xTypeDetection.is() )
479 ::comphelper::SequenceAsHashMap aTypeNamePropsHM( xTypeDetection->getByName( aTypeName ) );
480 uno::Sequence< OUString > aExtensions = aTypeNamePropsHM.getUnpackedValueOrDefault(
481 OUString("Extensions"),
482 ::uno::Sequence< OUString >() );
483 if ( aExtensions.getLength() )
484 aExtension = aExtensions[0];
486 catch ( css::container::NoSuchElementException& )
492 // Use provided save file name. If empty determine file name
493 aFileName = aSaveFileName;
494 if ( aFileName.isEmpty() )
496 if ( !bHasLocation )
498 // Create a noname file name with the correct extension
499 const OUString aNoNameFileName( "noname" );
500 aFileName = aNoNameFileName;
502 else
504 // Determine file name from model
505 INetURLObject aFileObj( xStorable->getLocation() );
506 aFileName = aFileObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::NO_DECODE );
510 // No file name => error
511 if ( aFileName.isEmpty() )
512 return eRet;
514 OSL_ASSERT( !aFilterName.isEmpty() );
515 OSL_ASSERT( !aFileName.isEmpty() );
517 // Creates a temporary directory to store a predefined file into it.
518 // This makes it possible to store the file for "send document as e-mail"
519 // with the original file name. We cannot use the original file as
520 // some mail programs need exclusive access.
521 ::utl::TempFile aTempDir( NULL, sal_True );
523 INetURLObject aFilePathObj( aTempDir.GetURL() );
524 aFilePathObj.insertName( aFileName );
525 aFilePathObj.setExtension( aExtension );
527 OUString aFileURL = aFilePathObj.GetMainURL( INetURLObject::NO_DECODE );
529 sal_Int32 nNumArgs(0);
530 const OUString aPasswordPropName( "Password" );
531 css::uno::Sequence< css::beans::PropertyValue > aArgs( ++nNumArgs );
532 aArgs[nNumArgs-1].Name = OUString( "FilterName" );
533 aArgs[nNumArgs-1].Value = css::uno::makeAny( aFilterName );
535 ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
536 OUString aPassword = aMediaDescrPropsHM.getUnpackedValueOrDefault(
537 aPasswordPropName,
538 OUString() );
539 if ( !aPassword.isEmpty() )
541 aArgs.realloc( ++nNumArgs );
542 aArgs[nNumArgs-1].Name = aPasswordPropName;
543 aArgs[nNumArgs-1].Value = css::uno::makeAny( aPassword );
546 bool bNeedsPreparation = false;
547 css::util::URL aPrepareURL;
548 css::uno::Reference< css::frame::XDispatch > xPrepareDispatch;
549 css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( xFrame, css::uno::UNO_QUERY );
550 css::uno::Reference< css::util::XURLTransformer > xURLTransformer( css::util::URLTransformer::create( xContext ) );
551 if( !bSendAsPDF )
555 // check if the document needs to be prepared for sending as mail (embedding of links, removal of invisible content)
557 aPrepareURL.Complete = OUString( ".uno:PrepareMailExport" );
558 xURLTransformer->parseStrict( aPrepareURL );
560 if ( xDispatchProvider.is() )
562 xPrepareDispatch = css::uno::Reference< css::frame::XDispatch >(
563 xDispatchProvider->queryDispatch( aPrepareURL, OUString(), 0 ));
564 if ( xPrepareDispatch.is() )
566 PrepareListener_Impl* pPrepareListener;
567 uno::Reference< css::frame::XStatusListener > xStatusListener = pPrepareListener = new PrepareListener_Impl;
568 xPrepareDispatch->addStatusListener( xStatusListener, aPrepareURL );
569 bNeedsPreparation = pPrepareListener->IsSet();
570 xPrepareDispatch->removeStatusListener( xStatusListener, aPrepareURL );
574 catch ( css::uno::RuntimeException& )
576 throw;
578 catch ( css::uno::Exception& )
583 if ( bModified || !bHasLocation || bStoreTo || bNeedsPreparation )
585 // Document is modified, is newly created or should be stored in a special format
588 if( bNeedsPreparation && xPrepareDispatch.is() )
590 if ( xPrepareDispatch.is() )
594 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
595 xPrepareDispatch->dispatch( aPrepareURL, aDispatchArgs );
597 catch ( css::uno::RuntimeException& )
599 throw;
601 catch ( css::uno::Exception& )
607 //check if this is the pdf otput filter (i#64555)
608 if( bSendAsPDF )
610 SaveResult eShowPDFFilterDialog = ShowFilterOptionsDialog(
611 xSMGR, xModel, aFilterName, rType, bModified, nNumArgs, aArgs );
613 // don't continue on dialog cancel or error
614 if ( eShowPDFFilterDialog != SAVE_SUCCESSFULL )
615 return eShowPDFFilterDialog;
618 xStorable->storeToURL( aFileURL, aArgs );
619 rFileNamePath = aFileURL;
620 eRet = SAVE_SUCCESSFULL;
622 if( !bSendAsPDF )
624 css::util::URL aURL;
625 // #i30432# notify that export is finished - the Writer may want to restore removed content
626 aURL.Complete = OUString( ".uno:MailExportFinished" );
627 xURLTransformer->parseStrict( aURL );
629 if ( xDispatchProvider.is() )
631 css::uno::Reference< css::frame::XDispatch > xDispatch = css::uno::Reference< css::frame::XDispatch >(
632 xDispatchProvider->queryDispatch( aURL, OUString(), 0 ));
633 if ( xDispatch.is() )
637 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
638 xDispatch->dispatch( aURL, aDispatchArgs );
640 catch ( css::uno::RuntimeException& )
642 throw;
644 catch ( css::uno::Exception& )
650 // If the model is not modified, it could be modified by the dispatch calls.
651 // Therefore set back to modified = false. This should not hurt if we call
652 // on a non-modified model.
653 if ( !bModified )
657 xModifiable->setModified( sal_False );
659 catch( com::sun::star::beans::PropertyVetoException& )
664 catch ( com::sun::star::io::IOException& )
666 eRet = SAVE_ERROR;
669 else
671 // We need 1:1 copy of the document to preserve an added signature.
672 aArgs.realloc( ++nNumArgs );
673 aArgs[nNumArgs-1].Name = OUString( "CopyStreamIfPossible" );
674 aArgs[nNumArgs-1].Value = css::uno::makeAny( (sal_Bool)sal_True );
678 xStorable->storeToURL( aFileURL, aArgs );
679 rFileNamePath = aFileURL;
680 eRet = SAVE_SUCCESSFULL;
682 catch ( com::sun::star::io::IOException& )
684 eRet = SAVE_ERROR;
690 return eRet;
693 SfxMailModel::SfxMailModel() :
694 mpToList ( NULL ),
695 mpCcList ( NULL ),
696 mpBccList ( NULL ),
697 mePriority ( PRIO_NORMAL ),
698 mbLoadDone ( sal_True )
702 SfxMailModel::~SfxMailModel()
704 ClearList( mpToList );
705 delete mpToList;
706 ClearList( mpCcList );
707 delete mpCcList;
708 ClearList( mpBccList );
709 delete mpBccList;
712 void SfxMailModel::AddAddress( const String& rAddress, AddressRole eRole )
714 // don't add a empty address
715 if ( rAddress.Len() > 0 )
717 AddressList_Impl* pList = NULL;
718 if ( ROLE_TO == eRole )
720 if ( !mpToList )
721 // create the list
722 mpToList = new AddressList_Impl();
723 pList = mpToList;
725 else if ( ROLE_CC == eRole )
727 if ( !mpCcList )
728 // create the list
729 mpCcList = new AddressList_Impl();
730 pList = mpCcList;
732 else if ( ROLE_BCC == eRole )
734 if ( !mpBccList )
735 // create the list
736 mpBccList = new AddressList_Impl();
737 pList = mpBccList;
739 else
741 SAL_WARN( "sfx2.dialog", "invalid address role" );
744 if ( pList )
746 // add address to list
747 AddressItemPtr_Impl pAddress = new String( rAddress );
748 pList->push_back( pAddress );
753 SfxMailModel::SendMailResult SfxMailModel::AttachDocument(
754 const OUString& sDocumentType,
755 const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
756 const OUString& sAttachmentTitle )
758 OUString sFileName;
760 SaveResult eSaveResult = SaveDocumentAsFormat( sAttachmentTitle, xFrameOrModel, sDocumentType, sFileName );
761 if ( eSaveResult == SAVE_SUCCESSFULL && !sFileName.isEmpty() )
762 maAttachedDocuments.push_back(sFileName);
763 return eSaveResult == SAVE_SUCCESSFULL ? SEND_MAIL_OK : SEND_MAIL_ERROR;
766 SfxMailModel::SendMailResult SfxMailModel::Send( const css::uno::Reference< css::frame::XFrame >& xFrame )
768 OSL_ENSURE(!maAttachedDocuments.empty(),"No document added!");
769 SendMailResult eResult = SEND_MAIL_ERROR;
770 if ( !maAttachedDocuments.empty() )
772 css::uno::Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
774 css::uno::Reference< XSimpleMailClientSupplier > xSimpleMailClientSupplier;
776 // Prefer the SimpleSystemMail service if available
777 try {
778 xSimpleMailClientSupplier = SimpleSystemMail::create( xContext );
780 catch ( const uno::Exception & )
783 if ( ! xSimpleMailClientSupplier.is() )
785 try {
786 xSimpleMailClientSupplier = SimpleCommandMail::create( xContext );
788 catch ( const uno::Exception & )
792 if ( xSimpleMailClientSupplier.is() )
794 css::uno::Reference< XSimpleMailClient > xSimpleMailClient = xSimpleMailClientSupplier->querySimpleMailClient();
796 if ( !xSimpleMailClient.is() )
798 // no mail client support => message box!
799 return SEND_MAIL_ERROR;
802 // we have a simple mail client
803 css::uno::Reference< XSimpleMailMessage > xSimpleMailMessage = xSimpleMailClient->createSimpleMailMessage();
804 if ( xSimpleMailMessage.is() )
806 sal_Int32 nSendFlags = SimpleMailClientFlags::DEFAULTS;
807 if ( maFromAddress.Len() == 0 )
809 // from address not set, try figure out users e-mail address
810 CreateFromAddress_Impl( maFromAddress );
812 xSimpleMailMessage->setOriginator( maFromAddress );
814 size_t nToCount = mpToList ? mpToList->size() : 0;
815 size_t nCcCount = mpCcList ? mpCcList->size() : 0;
816 size_t nCcSeqCount = nCcCount;
818 // set recipient (only one) for this simple mail server!!
819 if ( nToCount > 1 )
821 nCcSeqCount = nToCount - 1 + nCcCount;
822 xSimpleMailMessage->setRecipient( *mpToList->at( 0 ) );
823 nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE;
825 else if ( nToCount == 1 )
827 xSimpleMailMessage->setRecipient( *mpToList->at( 0 ) );
828 nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE;
831 // all other recipient must be handled with CC recipients!
832 if ( nCcSeqCount > 0 )
834 size_t nIndex = 0;
835 Sequence< OUString > aCcRecipientSeq;
837 aCcRecipientSeq.realloc( nCcSeqCount );
838 if ( nCcSeqCount > nCcCount )
840 for ( size_t i = 1; i < nToCount; ++i )
842 aCcRecipientSeq[nIndex++] = *mpToList->at(i);
846 for ( size_t i = 0; i < nCcCount; i++ )
848 aCcRecipientSeq[nIndex++] = *mpCcList->at(i);
850 xSimpleMailMessage->setCcRecipient( aCcRecipientSeq );
853 size_t nBccCount = mpBccList ? mpBccList->size() : 0;
854 if ( nBccCount > 0 )
856 Sequence< OUString > aBccRecipientSeq( nBccCount );
857 for ( size_t i = 0; i < nBccCount; ++i )
859 aBccRecipientSeq[i] = *mpBccList->at(i);
861 xSimpleMailMessage->setBccRecipient( aBccRecipientSeq );
864 Sequence< OUString > aAttachmentSeq(&(maAttachedDocuments[0]),maAttachedDocuments.size());
866 if ( xSimpleMailMessage->getSubject().isEmpty() ) {
867 OUString baseName( maAttachedDocuments[0].copy( maAttachedDocuments[0].lastIndexOf( '/' ) + 1 ) );
868 OUString subject( baseName );
869 if ( maAttachedDocuments.size() > 1 )
870 subject += ", ...";
871 xSimpleMailMessage->setSubject( subject );
873 xSimpleMailMessage->setAttachement( aAttachmentSeq );
875 sal_Bool bSend( sal_False );
878 xSimpleMailClient->sendSimpleMailMessage( xSimpleMailMessage, nSendFlags );
879 bSend = sal_True;
881 catch ( IllegalArgumentException& )
884 catch ( Exception& )
888 if ( bSend == sal_False )
890 css::uno::Reference< css::awt::XWindow > xParentWindow = xFrame->getContainerWindow();
892 SolarMutexGuard aGuard;
893 Window* pParentWindow = VCLUnoHelper::GetWindow( xParentWindow );
895 ErrorBox aBox( pParentWindow, SfxResId( RID_ERRBOX_MAIL_CONFIG ));
896 aBox.Execute();
897 eResult = SEND_MAIL_CANCELLED;
899 else
900 eResult = SEND_MAIL_OK;
904 else
905 eResult = SEND_MAIL_CANCELLED;
907 return eResult;
910 SfxMailModel::SendMailResult SfxMailModel::SaveAndSend( const css::uno::Reference< css::frame::XFrame >& xFrame, const OUString& rTypeName )
912 SaveResult eSaveResult;
913 SendMailResult eResult = SEND_MAIL_ERROR;
914 OUString aFileName;
916 eSaveResult = SaveDocumentAsFormat( OUString(), xFrame, rTypeName, aFileName );
918 if ( eSaveResult == SAVE_SUCCESSFULL )
920 maAttachedDocuments.push_back( aFileName );
921 return Send( xFrame );
923 else if ( eSaveResult == SAVE_CANCELLED )
924 eResult = SEND_MAIL_CANCELLED;
926 return eResult;
929 // functions -------------------------------------------------------------
931 sal_Bool CreateFromAddress_Impl( String& rFrom )
933 /* [Description]
935 This function tries to create a From-address with the help of IniManagers.
936 For this the fields 'first name', 'Name' and 'Email' are read from the
937 application-ini-data. If these fields are not set, FALSE is returned.
939 [Return value]
941 sal_True: Address could be created.
942 sal_False: Address could not be created.
946 SvtUserOptions aUserCFG;
947 String aName = aUserCFG.GetLastName ();
948 String aFirstName = aUserCFG.GetFirstName ();
949 if ( aFirstName.Len() || aName.Len() )
951 if ( aFirstName.Len() )
953 rFrom = comphelper::string::strip(aFirstName, ' ');
955 if ( aName.Len() )
956 rFrom += ' ';
958 rFrom += comphelper::string::strip(aName, ' ');
959 // remove illegal characters
960 rFrom = comphelper::string::remove(rFrom, '<');
961 rFrom = comphelper::string::remove(rFrom, '>');
962 rFrom = comphelper::string::remove(rFrom, '@');
964 String aEmailName = aUserCFG.GetEmail();
966 // remove illegal characters
967 aEmailName = comphelper::string::remove(aEmailName, '<');
968 aEmailName = comphelper::string::remove(aEmailName, '>');
970 if ( aEmailName.Len() )
972 if ( rFrom.Len() )
973 rFrom += ' ';
974 ( ( rFrom += '<' ) += comphelper::string::strip(aEmailName, ' ') ) += '>';
976 else
977 rFrom.Erase();
978 return ( rFrom.Len() > 0 );
981 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */