xref: /aoo42x/main/sfx2/source/dialog/mailmodel.cxx (revision d119d52d)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sfx2.hxx"
26 // includes --------------------------------------------------------------
27 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <com/sun/star/beans/XPropertyAccess.hpp>
29 #include <com/sun/star/frame/XFrame.hpp>
30 #include <com/sun/star/frame/XModel.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/ucb/CommandAbortedException.hpp>
33 #include <com/sun/star/uno/Reference.h>
34 #include <com/sun/star/util/XURLTransformer.hpp>
35 #include <com/sun/star/system/XSimpleMailClientSupplier.hpp>
36 #include <com/sun/star/system/SimpleMailClientFlags.hpp>
37 #include <com/sun/star/embed/XStorage.hpp>
38 #include <com/sun/star/embed/ElementModes.hpp>
39 #include <com/sun/star/embed/XTransactedObject.hpp>
40 #include <com/sun/star/container/XContainerQuery.hpp>
41 #include <com/sun/star/util/XModifiable.hpp>
42 #include <com/sun/star/frame/XModuleManager.hpp>
43 #include <com/sun/star/frame/XStorable.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/security/CertificateValidity.hpp>
46 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
47 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
48 #include <com/sun/star/frame/XDispatchProvider.hpp>
49 #include <com/sun/star/frame/XDispatch.hpp>
50 #include <com/sun/star/frame/XStatusListener.hpp>
51 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
52 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
53 #include <com/sun/star/document/XExporter.hpp>
54 #include <rtl/textenc.h>
55 #include <rtl/uri.h>
56 #include <rtl/uri.hxx>
57 #include <rtl/ustrbuf.hxx>
58 #include <vcl/msgbox.hxx>
59 
60 #include <sfx2/mailmodelapi.hxx>
61 #include "sfxtypes.hxx"
62 #include "sfx2/sfxresid.hxx"
63 #include <sfx2/sfxsids.hrc>
64 #include "dialog.hrc"
65 
66 #include <unotools/tempfile.hxx>
67 #include <unotools/configitem.hxx>
68 #include <ucbhelper/content.hxx>
69 #include <tools/urlobj.hxx>
70 #include <unotools/useroptions.hxx>
71 #include <comphelper/processfactory.hxx>
72 #include <comphelper/extract.hxx>
73 #include <comphelper/storagehelper.hxx>
74 #include <comphelper/sequenceasvector.hxx>
75 #include <comphelper/sequenceashashmap.hxx>
76 #include <comphelper/mediadescriptor.hxx>
77 #include <toolkit/helper/vclunohelper.hxx>
78 #include <vcl/svapp.hxx>
79 #include <cppuhelper/implbase1.hxx>
80 
81 // --------------------------------------------------------------
82 using namespace ::com::sun::star;
83 using namespace ::com::sun::star::beans;
84 using namespace ::com::sun::star::frame;
85 using namespace ::com::sun::star::io;
86 using namespace ::com::sun::star::lang;
87 using namespace ::com::sun::star::ucb;
88 using namespace ::com::sun::star::uno;
89 using namespace ::com::sun::star::util;
90 using namespace ::com::sun::star::system;
91 using namespace ::rtl;
92 
93 namespace css = ::com::sun::star;
94 // - class PrepareListener_Impl ------------------------------------------
95 class PrepareListener_Impl : public ::cppu::WeakImplHelper1< css::frame::XStatusListener >
96 {
97     bool m_bState;
98 public:
99         PrepareListener_Impl();
100         virtual ~PrepareListener_Impl();
101 
102         // css.frame.XStatusListener
103         virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& aEvent)
104           throw(css::uno::RuntimeException);
105 
106         // css.lang.XEventListener
107         virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent)
108           throw(css::uno::RuntimeException);
109 
110         bool IsSet() const {return m_bState;}
111 };
112 
113 /*-- 25.08.2010 14:32:49---------------------------------------------------
114 
115   -----------------------------------------------------------------------*/
116 PrepareListener_Impl::PrepareListener_Impl() :
117     m_bState( false )
118 {
119 }
120 /*-- 25.08.2010 14:32:51---------------------------------------------------
121 
122   -----------------------------------------------------------------------*/
123 PrepareListener_Impl::~PrepareListener_Impl()
124 {
125 }
126 /*-- 25.08.2010 14:32:51---------------------------------------------------
127 
128   -----------------------------------------------------------------------*/
129 void PrepareListener_Impl::statusChanged(const css::frame::FeatureStateEvent& rEvent) throw(css::uno::RuntimeException)
130 {
131     if( rEvent.IsEnabled )
132         rEvent.State >>= m_bState;
133     else
134         m_bState = sal_False;
135 }
136 /*-- 25.08.2010 14:32:52---------------------------------------------------
137 
138   -----------------------------------------------------------------------*/
139 void PrepareListener_Impl::disposing(const css::lang::EventObject& /*rEvent*/) throw(css::uno::RuntimeException)
140 {
141 }
142 
143 // class AddressList_Impl ------------------------------------------------
144 
145 typedef String* AddressItemPtr_Impl;
146 DECLARE_LIST( AddressList_Impl, AddressItemPtr_Impl )
147 
148 // class SfxMailModel -----------------------------------------------
149 
150 static const char       PDF_DOCUMENT_TYPE[]   = "pdf_Portable_Document_Format";
151 static const sal_uInt32 PDF_DOCUMENT_TYPE_LEN = 28;
152 
153 void SfxMailModel::ClearList( AddressList_Impl* pList )
154 {
155 	if ( pList )
156 	{
157 		sal_uIntPtr i, nCount = pList->Count();
158 		for ( i = 0; i < nCount; ++i )
159 			delete pList->GetObject(i);
160 		pList->Clear();
161 	}
162 }
163 
164 void SfxMailModel::MakeValueList( AddressList_Impl* pList, String& rValueList )
165 {
166 	rValueList.Erase();
167 	if ( pList )
168 	{
169 		sal_uIntPtr i, nCount = pList->Count();
170 		for ( i = 0; i < nCount; ++i )
171 		{
172 			if ( rValueList.Len() > 0 )
173 				rValueList += ',';
174 			rValueList += *pList->GetObject(i);
175 		}
176 	}
177 }
178 
179 sal_Bool HasDocumentValidSignature( const css::uno::Reference< css::frame::XModel >& xModel )
180 {
181     try
182     {
183         css::uno::Reference< css::beans::XPropertySet > xPropSet( xModel, css::uno::UNO_QUERY );
184         if ( xPropSet.is() )
185         {
186             Any a = xPropSet->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HasValidSignatures" )));
187             sal_Bool bReturn = sal_Bool();
188             if ( a >>= bReturn )
189                 return bReturn;
190         }
191     }
192     catch ( css::uno::RuntimeException& )
193     {
194         throw;
195     }
196     catch ( css::uno::Exception& )
197     {
198     }
199 
200     return sal_False;
201 }
202 
203 SfxMailModel::SaveResult SfxMailModel::ShowFilterOptionsDialog(
204     uno::Reference< lang::XMultiServiceFactory > xSMGR,
205     uno::Reference< frame::XModel > xModel,
206     const rtl::OUString& rFilterName,
207     const rtl::OUString& rType,
208     bool bModified,
209     sal_Int32& rNumArgs,
210     ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rArgs )
211 {
212     SaveResult eRet( SAVE_ERROR );
213 
214     try
215     {
216         uno::Sequence < beans::PropertyValue > aProps;
217             ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > xFilterCFG =
218                 uno::Reference< container::XNameAccess >(
219                     xSMGR->createInstance(
220                         ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ), uno::UNO_QUERY );
221         css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY );
222 
223         if ( !xFilterCFG.is() )
224             return eRet;
225 
226         uno::Any aAny = xFilterCFG->getByName( rFilterName );
227 
228         if ( aAny >>= aProps )
229         {
230             sal_Int32 nPropertyCount = aProps.getLength();
231             for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty )
232             {
233                 if( aProps[nProperty].Name.equals( ::rtl::OUString::createFromAscii( "UIComponent" )) )
234                 {
235                     ::rtl::OUString aServiceName;
236                     aProps[nProperty].Value >>= aServiceName;
237                     if( aServiceName.getLength() )
238                     {
239                         uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog(
240                             xSMGR->createInstance( aServiceName ), uno::UNO_QUERY );
241                         uno::Reference< beans::XPropertyAccess > xFilterProperties(
242                             xFilterDialog, uno::UNO_QUERY );
243 
244                         if( xFilterDialog.is() && xFilterProperties.is() )
245                         {
246                             uno::Sequence< beans::PropertyValue > aPropsForDialog(1);
247                             uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY );
248 
249                             if ( rType.equalsAsciiL( PDF_DOCUMENT_TYPE, PDF_DOCUMENT_TYPE_LEN ))
250                             {
251                                 //add an internal property, used to tell the dialog we want to set a different
252                                 //string for the ok button
253                                 //used in filter/source/pdf/impdialog.cxx
254                                 String aOkSendText( SfxResId( STR_PDF_EXPORT_SEND ));
255 
256                                 uno::Sequence< beans::PropertyValue > aFilterDataValue(1);
257                                 aFilterDataValue[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_OkButtonString" ));
258                                 aFilterDataValue[0].Value = css::uno::makeAny( ::rtl::OUString( aOkSendText ));
259 
260                                 //add to the filterdata property, the only one the PDF export filter dialog will care for
261                                 aPropsForDialog[0].Name =  ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterData" ));
262                                 aPropsForDialog[0].Value = css::uno::makeAny( aFilterDataValue );
263 
264                                 //when executing the dialog will merge the persistent FilterData properties
265                                 xFilterProperties->setPropertyValues( aPropsForDialog );
266                             }
267 
268                             if( xExporter.is() )
269                                 xExporter->setSourceDocument(
270                                     uno::Reference< lang::XComponent >( xModel, uno::UNO_QUERY ) );
271 
272                             if( xFilterDialog->execute() )
273                             {
274                                 //get the filter data
275                                 uno::Sequence< beans::PropertyValue > aPropsFromDialog = xFilterProperties->getPropertyValues();
276 
277                                 //add them to the args
278                                 for ( sal_Int32 nInd = 0; nInd < aPropsFromDialog.getLength(); nInd++ )
279                                 {
280                                     if( aPropsFromDialog[ nInd ].Name.equals( ::rtl::OUString::createFromAscii( "FilterData" ) ) )
281                                     {
282                                         //found the filterdata, add to the storing argument
283                                         rArgs.realloc( ++rNumArgs );
284                                         rArgs[rNumArgs-1].Name = aPropsFromDialog[ nInd ].Name;
285                                         rArgs[rNumArgs-1].Value = aPropsFromDialog[ nInd ].Value;
286                                         break;
287                                     }
288                                 }
289                                 eRet = SAVE_SUCCESSFULL;
290                             }
291                             else
292                             {
293                                 // cancel from dialog, then do not send
294                                 // If the model is not modified, it could be modified by the dispatch calls.
295                                 // Therefore set back to modified = false. This should not hurt if we call
296                                 // on a non-modified model.
297                                 if ( !bModified )
298                                 {
299                                     try
300                                     {
301                                         xModifiable->setModified( sal_False );
302                                     }
303                                     catch( com::sun::star::beans::PropertyVetoException& )
304                                     {
305                                     }
306                                 }
307                                 eRet = SAVE_CANCELLED;
308                             }
309                         }
310                         break;
311                     }
312                 }
313             }
314         }
315     }
316     catch( css::uno::RuntimeException& )
317     {
318         throw;
319     }
320     catch( uno::Exception& )
321     {
322     }
323 
324     return eRet;
325 }
326 
327 sal_Int32 SfxMailModel::GetCount() const
328 {
329     return maAttachedDocuments.size();
330 }
331 
332 sal_Bool SfxMailModel::IsEmpty() const
333 {
334     return maAttachedDocuments.empty();
335 }
336 
337 SfxMailModel::SaveResult SfxMailModel::SaveDocumentAsFormat(
338     const rtl::OUString& aSaveFileName,
339     const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
340     const rtl::OUString& rType,
341     rtl::OUString& rFileNamePath )
342 {
343     SaveResult  eRet( SAVE_ERROR );
344     bool        bSendAsPDF = (rType.equalsAsciiL( PDF_DOCUMENT_TYPE, PDF_DOCUMENT_TYPE_LEN ));
345 
346     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR  = ::comphelper::getProcessServiceFactory();
347     if (!xSMGR.is())
348         return eRet;
349 
350     const rtl::OUString aModuleManager( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.ModuleManager" ));
351     css::uno::Reference< css::frame::XModuleManager > xModuleManager( xSMGR->createInstance( aModuleManager ), css::uno::UNO_QUERY_THROW );
352     if ( !xModuleManager.is() )
353         return eRet;
354 
355     rtl::OUString aModule;
356     try
357     {
358          aModule = xModuleManager->identify( xFrameOrModel );
359     }
360     catch ( css::uno::RuntimeException& )
361     {
362         throw;
363     }
364     catch ( css::uno::Exception& )
365     {
366     }
367 
368     css::uno::Reference< css::frame::XFrame > xFrame( xFrameOrModel, css::uno::UNO_QUERY );
369     css::uno::Reference< css::frame::XModel > xModel( xFrameOrModel, css::uno::UNO_QUERY );
370     if ( xFrame.is() )
371     {
372         css::uno::Reference< css::frame::XController > xController = xFrame->getController();
373         if ( xController.is() )
374             xModel = xController->getModel();
375     }
376 
377     // We need at least a valid module name and model reference
378     if (( aModule.getLength() > 0 ) && xModel.is() )
379     {
380         bool bModified( false );
381         bool bHasLocation( false );
382         bool bStoreTo( false );
383 
384         css::uno::Reference< css::util::XModifiable > xModifiable( xModel, css::uno::UNO_QUERY );
385         css::uno::Reference< css::frame::XStorable > xStorable( xModel, css::uno::UNO_QUERY );
386 
387         if ( xModifiable.is() )
388             bModified = xModifiable->isModified();
389         if ( xStorable.is() )
390         {
391             rtl::OUString aLocation = xStorable->getLocation();
392             INetURLObject aFileObj( aLocation );
393 
394             bool bPrivateProtocol = ( aFileObj.GetProtocol() == INET_PROT_PRIV_SOFFICE );
395 
396             bHasLocation = ( aLocation.getLength() > 0 ) && !bPrivateProtocol;
397             OSL_ASSERT( !bPrivateProtocol );
398         }
399         if ( rType.getLength() > 0 )
400             bStoreTo = true;
401 
402         if ( xStorable.is() )
403         {
404             rtl::OUString aFilterName;
405             rtl::OUString aTypeName( rType );
406             rtl::OUString aFileName;
407             rtl::OUString aExtension;
408 
409             css::uno::Reference< css::container::XContainerQuery > xContainerQuery(
410                 xSMGR->createInstance( rtl::OUString(
411                     RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.FilterFactory" ))),
412                     css::uno::UNO_QUERY );
413 
414             if ( bStoreTo )
415             {
416                 // Retrieve filter from type
417                 css::uno::Sequence< css::beans::NamedValue > aQuery( bSendAsPDF ? 3 : 2 );
418                 aQuery[0].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Type" ));
419                 aQuery[0].Value = css::uno::makeAny( aTypeName );
420                 aQuery[1].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DocumentService" ));
421                 aQuery[1].Value = css::uno::makeAny( aModule );
422                 if( bSendAsPDF )
423                 {
424                     // #i91419#
425                     // FIXME: we want just an export filter. However currently we need
426                     // exact flag value as detailed in the filter configuration to get it
427                     // this seems to be a bug
428                     // without flags we get an import filter here, which is also unwanted
429                     aQuery[2].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Flags" ));
430                     aQuery[2].Value = css::uno::makeAny( sal_Int32(0x80042) ); // EXPORT ALIEN 3RDPARTY
431                 }
432 
433                 css::uno::Reference< css::container::XEnumeration > xEnumeration =
434                     xContainerQuery->createSubSetEnumerationByProperties( aQuery );
435 
436                 if ( xEnumeration->hasMoreElements() )
437                 {
438                     ::comphelper::SequenceAsHashMap aFilterPropsHM( xEnumeration->nextElement() );
439                     aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
440                                                 ::rtl::OUString::createFromAscii( "Name" ),
441                                                 ::rtl::OUString() );
442                 }
443 
444                 if ( bHasLocation )
445                 {
446                     // Retrieve filter from media descriptor
447                     ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
448                     rtl::OUString aOrgFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
449                                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" )),
450                                     ::rtl::OUString() );
451                     if ( aOrgFilterName == aFilterName )
452                     {
453                         // We should save the document in the original format. Therefore this
454                         // is not a storeTo operation. To support signing in this case, reset
455                         // bStoreTo flag.
456                         bStoreTo = false;
457                     }
458                 }
459             }
460             else
461             {
462                 if ( bHasLocation )
463                 {
464                     // Retrieve filter from media descriptor
465                     ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
466                     aFilterName = aMediaDescrPropsHM.getUnpackedValueOrDefault(
467                                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" )),
468                                     ::rtl::OUString() );
469                 }
470 
471                 if ( !bHasLocation || ( aFilterName.getLength() == 0 ))
472                 {
473                     // Retrieve the user defined default filter
474                     css::uno::Reference< css::container::XNameAccess > xNameAccess( xModuleManager, css::uno::UNO_QUERY );
475                     try
476                     {
477                         ::comphelper::SequenceAsHashMap aFilterPropsHM( xNameAccess->getByName( aModule ) );
478                         aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
479                                                     ::rtl::OUString::createFromAscii( "ooSetupFactoryDefaultFilter" ),
480                                                     ::rtl::OUString() );
481                         css::uno::Reference< css::container::XNameAccess > xNameAccess2(
482                             xContainerQuery, css::uno::UNO_QUERY );
483                         if ( xNameAccess2.is() )
484                         {
485                             ::comphelper::SequenceAsHashMap aFilterPropsHM2( xNameAccess2->getByName( aFilterName ) );
486                             aTypeName = aFilterPropsHM2.getUnpackedValueOrDefault(
487                                                         ::rtl::OUString::createFromAscii( "Type" ),
488                                                         ::rtl::OUString() );
489                         }
490                     }
491                     catch ( css::container::NoSuchElementException& )
492                     {
493                     }
494                     catch ( css::beans::UnknownPropertyException& )
495                     {
496                     }
497                 }
498             }
499 
500             // No filter found => error
501             // No type and no location => error
502             if (( aFilterName.getLength() == 0 ) ||
503                 (( aTypeName.getLength() == 0 ) && !bHasLocation ))
504                 return eRet;
505 
506             // Determine filen name and extension
507             if ( bHasLocation && !bStoreTo )
508             {
509                 INetURLObject aFileObj( xStorable->getLocation() );
510                 aExtension = (rtl::OUString)aFileObj.getExtension();
511             }
512             else
513             {
514                 css::uno::Reference< container::XNameAccess > xTypeDetection(
515                     xSMGR->createInstance( ::rtl::OUString(
516                         RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.TypeDetection" ))),
517                     css::uno::UNO_QUERY );
518 
519 
520                 if ( xTypeDetection.is() )
521                 {
522                     try
523                     {
524                         ::comphelper::SequenceAsHashMap aTypeNamePropsHM( xTypeDetection->getByName( aTypeName ) );
525                         uno::Sequence< ::rtl::OUString > aExtensions = aTypeNamePropsHM.getUnpackedValueOrDefault(
526                                                         ::rtl::OUString::createFromAscii( "Extensions" ),
527                                                         ::uno::Sequence< ::rtl::OUString >() );
528                         if ( aExtensions.getLength() )
529                             aExtension = aExtensions[0];
530                     }
531                     catch ( css::container::NoSuchElementException& )
532                     {
533                     }
534                 }
535             }
536 
537             // Use provided save file name. If empty determine file name
538             aFileName = aSaveFileName;
539             if ( aFileName.getLength() == 0 )
540             {
541                 if ( !bHasLocation )
542                 {
543                     // Create a noname file name with the correct extension
544                     const rtl::OUString aNoNameFileName( RTL_CONSTASCII_USTRINGPARAM( "noname" ));
545                     aFileName = aNoNameFileName;
546                 }
547                 else
548                 {
549                     // Determine file name from model
550                     INetURLObject aFileObj( xStorable->getLocation() );
551                     aFileName = aFileObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::NO_DECODE );
552                 }
553             }
554 
555             // No file name => error
556             if ( aFileName.getLength() == 0 )
557                 return eRet;
558 
559             OSL_ASSERT( aFilterName.getLength() > 0 );
560             OSL_ASSERT( aFileName.getLength() > 0 );
561 
562             // Creates a temporary directory to store a predefined file into it.
563             // This makes it possible to store the file for "send document as e-mail"
564             // with the original file name. We cannot use the original file as
565             // some mail programs need exclusive access.
566             ::utl::TempFile aTempDir( NULL, sal_True );
567 
568             INetURLObject aFilePathObj( aTempDir.GetURL() );
569             aFilePathObj.insertName( aFileName );
570             aFilePathObj.setExtension( aExtension );
571 
572             rtl::OUString aFileURL = aFilePathObj.GetMainURL( INetURLObject::NO_DECODE );
573 
574             sal_Int32 nNumArgs(0);
575             const rtl::OUString aPasswordPropName( RTL_CONSTASCII_USTRINGPARAM( "Password" ));
576             css::uno::Sequence< css::beans::PropertyValue > aArgs( ++nNumArgs );
577             aArgs[nNumArgs-1].Name  = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ));
578             aArgs[nNumArgs-1].Value = css::uno::makeAny( aFilterName );
579 
580             ::comphelper::SequenceAsHashMap aMediaDescrPropsHM( xModel->getArgs() );
581             rtl::OUString aPassword = aMediaDescrPropsHM.getUnpackedValueOrDefault(
582                                             aPasswordPropName,
583                                             ::rtl::OUString() );
584             if ( aPassword.getLength() > 0 )
585             {
586                 aArgs.realloc( ++nNumArgs );
587                 aArgs[nNumArgs-1].Name = aPasswordPropName;
588                 aArgs[nNumArgs-1].Value = css::uno::makeAny( aPassword );
589             }
590 
591             bool bNeedsPreparation = false;
592             css::util::URL aPrepareURL;
593             css::uno::Reference< css::frame::XDispatch > xPrepareDispatch;
594             css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( xFrame, css::uno::UNO_QUERY );
595             css::uno::Reference< css::util::XURLTransformer > xURLTransformer(
596                         xSMGR->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ))),
597                         css::uno::UNO_QUERY );
598             if( !bSendAsPDF )
599             {
600                 try
601                 {
602                     // check if the document needs to be prepared for sending as mail (embedding of links, removal of invisible content)
603 
604                     if ( xURLTransformer.is() )
605                     {
606                         aPrepareURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:PrepareMailExport" ));
607                         xURLTransformer->parseStrict( aPrepareURL );
608                     }
609 
610                     if ( xDispatchProvider.is() )
611                     {
612                         xPrepareDispatch = css::uno::Reference< css::frame::XDispatch >(
613                             xDispatchProvider->queryDispatch( aPrepareURL, ::rtl::OUString(), 0 ));
614                         if ( xPrepareDispatch.is() )
615                         {
616                                 PrepareListener_Impl* pPrepareListener;
617                                 uno::Reference< css::frame::XStatusListener > xStatusListener = pPrepareListener = new PrepareListener_Impl;
618                                 xPrepareDispatch->addStatusListener( xStatusListener, aPrepareURL );
619                                 bNeedsPreparation = pPrepareListener->IsSet();
620                                 xPrepareDispatch->removeStatusListener( xStatusListener, aPrepareURL );
621                         }
622                     }
623                 }
624                 catch ( css::uno::RuntimeException& )
625                 {
626                     throw;
627                 }
628                 catch ( css::uno::Exception& )
629                 {
630                 }
631             }
632 
633             if ( bModified || !bHasLocation || bStoreTo || bNeedsPreparation )
634             {
635                 // Document is modified, is newly created or should be stored in a special format
636                 try
637                 {
638                     if( bNeedsPreparation && xPrepareDispatch.is() )
639                     {
640                         if ( xPrepareDispatch.is() )
641                         {
642                             try
643                             {
644                                 css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
645                                 xPrepareDispatch->dispatch( aPrepareURL, aDispatchArgs );
646                             }
647                             catch ( css::uno::RuntimeException& )
648                             {
649                                 throw;
650                             }
651                             catch ( css::uno::Exception& )
652                             {
653                             }
654                         }
655                     }
656 
657                     //check if this is the pdf otput filter (i#64555)
658                     if( bSendAsPDF )
659                     {
660                         SaveResult eShowPDFFilterDialog = ShowFilterOptionsDialog(
661                                                             xSMGR, xModel, aFilterName, rType, bModified, nNumArgs, aArgs );
662 
663                         // don't continue on dialog cancel or error
664                         if ( eShowPDFFilterDialog != SAVE_SUCCESSFULL )
665                             return eShowPDFFilterDialog;
666                     }
667 
668                     xStorable->storeToURL( aFileURL, aArgs );
669                     rFileNamePath = aFileURL;
670                     eRet = SAVE_SUCCESSFULL;
671 
672                     if( !bSendAsPDF )
673                     {
674                         css::util::URL aURL;
675                         // #i30432# notify that export is finished - the Writer may want to restore removed content
676                         if ( xURLTransformer.is() )
677                         {
678                             aURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:MailExportFinished" ));
679                             xURLTransformer->parseStrict( aURL );
680                         }
681 
682                         if ( xDispatchProvider.is() )
683                         {
684                             css::uno::Reference< css::frame::XDispatch > xDispatch = css::uno::Reference< css::frame::XDispatch >(
685                                 xDispatchProvider->queryDispatch( aURL, ::rtl::OUString(), 0 ));
686                             if ( xDispatch.is() )
687                             {
688                                 try
689                                 {
690                                     css::uno::Sequence< css::beans::PropertyValue > aDispatchArgs;
691                                     xDispatch->dispatch( aURL, aDispatchArgs );
692                                 }
693                                 catch ( css::uno::RuntimeException& )
694                                 {
695                                     throw;
696                                 }
697                                 catch ( css::uno::Exception& )
698                                 {
699                                 }
700                             }
701                         }
702                     }
703                     // If the model is not modified, it could be modified by the dispatch calls.
704                     // Therefore set back to modified = false. This should not hurt if we call
705                     // on a non-modified model.
706                     if ( !bModified )
707                     {
708                         try
709                         {
710                             xModifiable->setModified( sal_False );
711                         }
712                         catch( com::sun::star::beans::PropertyVetoException& )
713                         {
714                         }
715                     }
716                 }
717                 catch ( com::sun::star::io::IOException& )
718                 {
719                     eRet = SAVE_ERROR;
720                 }
721             }
722             else
723             {
724                 // We need 1:1 copy of the document to preserve an added signature.
725                 aArgs.realloc( ++nNumArgs );
726                 aArgs[nNumArgs-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyStreamIfPossible" ) );
727                 aArgs[nNumArgs-1].Value = css::uno::makeAny( (sal_Bool)sal_True );
728 
729 				try
730 				{
731                     xStorable->storeToURL( aFileURL, aArgs );
732                     rFileNamePath = aFileURL;
733                     eRet = SAVE_SUCCESSFULL;
734 				}
735                 catch ( com::sun::star::io::IOException& )
736                 {
737                     eRet = SAVE_ERROR;
738                 }
739             }
740         }
741     }
742 
743     return eRet;
744 }
745 
746 SfxMailModel::SfxMailModel() :
747 	mpToList	( NULL ),
748 	mpCcList	( NULL ),
749 	mpBccList	( NULL ),
750 	mePriority	( PRIO_NORMAL ),
751 	mbLoadDone	( sal_True )
752 {
753 }
754 
755 SfxMailModel::~SfxMailModel()
756 {
757 	ClearList( mpToList );
758 	delete mpToList;
759 	ClearList( mpCcList );
760 	delete mpCcList;
761 	ClearList( mpBccList );
762 	delete mpBccList;
763 }
764 
765 void SfxMailModel::AddAddress( const String& rAddress, AddressRole eRole )
766 {
767 	// don't add a empty address
768 	if ( rAddress.Len() > 0 )
769 	{
770 		AddressList_Impl* pList = NULL;
771 		if ( ROLE_TO == eRole )
772 		{
773 			if ( !mpToList )
774 				// create the list
775 				mpToList = new AddressList_Impl;
776 			pList = mpToList;
777 		}
778 		else if ( ROLE_CC == eRole )
779 		{
780 			if ( !mpCcList )
781 				// create the list
782 				mpCcList = new AddressList_Impl;
783 			pList = mpCcList;
784 		}
785 		else if ( ROLE_BCC == eRole )
786 		{
787 			if ( !mpBccList )
788 				// create the list
789 				mpBccList = new AddressList_Impl;
790 			pList = mpBccList;
791 		}
792 		else
793 		{
794 			DBG_ERRORFILE( "invalid address role" );
795 		}
796 
797 		if ( pList )
798 		{
799 			// add address to list
800 			AddressItemPtr_Impl pAddress = new String( rAddress );
801 			pList->Insert( pAddress, LIST_APPEND );
802 		}
803 	}
804 }
805 
806 SfxMailModel::SendMailResult SfxMailModel::AttachDocument(
807     const ::rtl::OUString& sDocumentType,
808     const css::uno::Reference< css::uno::XInterface >& xFrameOrModel,
809     const ::rtl::OUString& sAttachmentTitle )
810 {
811     rtl::OUString sFileName;
812 
813     SaveResult eSaveResult = SaveDocumentAsFormat( sAttachmentTitle, xFrameOrModel, sDocumentType, sFileName );
814     if ( eSaveResult == SAVE_SUCCESSFULL && ( sFileName.getLength() > 0 ) )
815         maAttachedDocuments.push_back(sFileName);
816     return eSaveResult == SAVE_SUCCESSFULL ? SEND_MAIL_OK : SEND_MAIL_ERROR;
817 }
818 
819 SfxMailModel::SendMailResult SfxMailModel::Send( const css::uno::Reference< css::frame::XFrame >& xFrame )
820 {
821 	OSL_ENSURE(!maAttachedDocuments.empty(),"No document added!");
822 	SendMailResult	eResult = SEND_MAIL_ERROR;
823     if ( !maAttachedDocuments.empty() )
824 	{
825 	    css::uno::Reference < XMultiServiceFactory > xMgr = ::comphelper::getProcessServiceFactory();
826 	    if ( xMgr.is() )
827 	    {
828 		    css::uno::Reference< XSimpleMailClientSupplier >	xSimpleMailClientSupplier;
829 
830             // Prefer the SimpleSystemMail service if available
831             xSimpleMailClientSupplier = css::uno::Reference< XSimpleMailClientSupplier >(
832                 xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.system.SimpleSystemMail" ))),
833                 UNO_QUERY );
834 
835             if ( ! xSimpleMailClientSupplier.is() )
836             {
837                 xSimpleMailClientSupplier = css::uno::Reference< XSimpleMailClientSupplier >(
838                     xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.system.SimpleCommandMail" ))),
839                     UNO_QUERY );
840             }
841 
842 		    if ( xSimpleMailClientSupplier.is() )
843 		    {
844 			    css::uno::Reference< XSimpleMailClient > xSimpleMailClient = xSimpleMailClientSupplier->querySimpleMailClient();
845 
846 			    if ( !xSimpleMailClient.is() )
847 			    {
848 				    // no mail client support => message box!
849 				    return SEND_MAIL_ERROR;
850 			    }
851 
852 			    // we have a simple mail client
853 			    css::uno::Reference< XSimpleMailMessage > xSimpleMailMessage = xSimpleMailClient->createSimpleMailMessage();
854 			    if ( xSimpleMailMessage.is() )
855 			    {
856 				    sal_Int32 nSendFlags = SimpleMailClientFlags::DEFAULTS;
857 				    if ( maFromAddress.Len() == 0 )
858 				    {
859 					    // from address not set, try figure out users e-mail address
860 					    CreateFromAddress_Impl( maFromAddress );
861 				    }
862 				    xSimpleMailMessage->setOriginator( maFromAddress );
863 
864 				    sal_Int32 nToCount		= mpToList ? mpToList->Count() : 0;
865 				    sal_Int32 nCcCount		= mpCcList ? mpCcList->Count() : 0;
866 				    sal_Int32 nCcSeqCount	= nCcCount;
867 
868 				    // set recipient (only one) for this simple mail server!!
869 				    if ( nToCount > 1 )
870 				    {
871 					    nCcSeqCount = nToCount - 1 + nCcCount;
872 					    xSimpleMailMessage->setRecipient( *mpToList->GetObject( 0 ));
873 					    nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE;
874 				    }
875 				    else if ( nToCount == 1 )
876 				    {
877 					    xSimpleMailMessage->setRecipient( *mpToList->GetObject( 0 ));
878 					    nSendFlags = SimpleMailClientFlags::NO_USER_INTERFACE;
879 				    }
880 
881 				    // all other recipient must be handled with CC recipients!
882 				    if ( nCcSeqCount > 0 )
883 				    {
884 					    sal_Int32				nIndex = 0;
885 					    Sequence< OUString >	aCcRecipientSeq;
886 
887 					    aCcRecipientSeq.realloc( nCcSeqCount );
888 					    if ( nCcSeqCount > nCcCount )
889     				    {
890 						    for ( sal_Int32 i = 1; i < nToCount; ++i )
891 						    {
892 							    aCcRecipientSeq[nIndex++] = *mpToList->GetObject(i);
893 						    }
894 					    }
895 
896 					    for ( sal_Int32 i = 0; i < nCcCount; i++ )
897 					    {
898 						    aCcRecipientSeq[nIndex++] = *mpCcList->GetObject(i);
899 					    }
900 					    xSimpleMailMessage->setCcRecipient( aCcRecipientSeq );
901 				    }
902 
903 				    sal_Int32 nBccCount = mpBccList ? mpBccList->Count() : 0;
904 				    if ( nBccCount > 0 )
905 				    {
906 	    			    Sequence< OUString > aBccRecipientSeq( nBccCount );
907 					    for ( sal_Int32 i = 0; i < nBccCount; ++i )
908 					    {
909 						    aBccRecipientSeq[i] = *mpBccList->GetObject(i);
910 					    }
911 					    xSimpleMailMessage->setBccRecipient( aBccRecipientSeq );
912 				    }
913 
914 					Sequence< OUString > aAttachmentSeq(&(maAttachedDocuments[0]),maAttachedDocuments.size());
915 
916 				    xSimpleMailMessage->setSubject( maSubject );
917 				    xSimpleMailMessage->setAttachement( aAttachmentSeq );
918 
919 	                sal_Bool bSend( sal_False );
920                     try
921 	                {
922 		                xSimpleMailClient->sendSimpleMailMessage( xSimpleMailMessage, nSendFlags );
923 		                bSend = sal_True;
924 	                }
925 	                catch ( IllegalArgumentException& )
926 	                {
927 	                }
928 	                catch ( Exception& )
929 	                {
930 	                }
931 
932 	                if ( bSend == sal_False )
933 	                {
934                         css::uno::Reference< css::awt::XWindow > xParentWindow = xFrame->getContainerWindow();
935 
936                         ::vos::OGuard aGuard( Application::GetSolarMutex() );
937                         Window* pParentWindow = VCLUnoHelper::GetWindow( xParentWindow );
938 
939                         ErrorBox aBox( pParentWindow, SfxResId( RID_ERRBOX_MAIL_CONFIG ));
940 		                aBox.Execute();
941                         eResult = SEND_MAIL_CANCELLED;
942 	                }
943                     else
944 					    eResult = SEND_MAIL_OK;
945 			    }
946 		    }
947 	    }
948     }
949 	else
950 		eResult = SEND_MAIL_CANCELLED;
951 
952 	return eResult;
953 }
954 
955 SfxMailModel::SendMailResult SfxMailModel::SaveAndSend( const css::uno::Reference< css::frame::XFrame >& xFrame, const rtl::OUString& rTypeName )
956 {
957 	SaveResult		eSaveResult;
958 	SendMailResult	eResult = SEND_MAIL_ERROR;
959     rtl::OUString   aFileName;
960 
961     eSaveResult = SaveDocumentAsFormat( rtl::OUString(), xFrame, rTypeName, aFileName );
962 
963     if ( eSaveResult == SAVE_SUCCESSFULL )
964     {
965         maAttachedDocuments.push_back( aFileName );
966         return Send( xFrame );
967     }
968 	else if ( eSaveResult == SAVE_CANCELLED )
969 		eResult = SEND_MAIL_CANCELLED;
970 
971 	return eResult;
972 }
973 
974 // functions -------------------------------------------------------------
975 
976 sal_Bool CreateFromAddress_Impl( String& rFrom )
977 
978 /*	[Beschreibung]
979 
980 	Diese Funktion versucht mit Hilfe des IniManagers eine From-Adresse
981 	zu erzeugen. daf"ur werden die Felder 'Vorname', 'Name' und 'EMail'
982 	aus der Applikations-Ini-Datei ausgelesen. Sollten diese Felder
983 	nicht gesetzt sein, wird FALSE zur"uckgegeben.
984 
985 	[R"uckgabewert]
986 
987 	sal_True:	Adresse konnte erzeugt werden.
988 	sal_False:	Adresse konnte nicht erzeugt werden.
989 */
990 
991 {
992 	SvtUserOptions aUserCFG;
993 	String aName		= aUserCFG.GetLastName	();
994 	String aFirstName	= aUserCFG.GetFirstName	();
995 	if ( aFirstName.Len() || aName.Len() )
996 	{
997 		if ( aFirstName.Len() )
998 		{
999 			rFrom = TRIM( aFirstName );
1000 
1001 			if ( aName.Len() )
1002 				rFrom += ' ';
1003 		}
1004 		rFrom += TRIM( aName );
1005 		// unerlaubte Zeichen entfernen
1006 		rFrom.EraseAllChars( '<' );
1007 		rFrom.EraseAllChars( '>' );
1008 		rFrom.EraseAllChars( '@' );
1009 	}
1010 	String aEmailName = aUserCFG.GetEmail();
1011 
1012     // unerlaubte Zeichen entfernen
1013 	aEmailName.EraseAllChars( '<' );
1014 	aEmailName.EraseAllChars( '>' );
1015 
1016 	if ( aEmailName.Len() )
1017 	{
1018 		if ( rFrom.Len() )
1019 			rFrom += ' ';
1020 		( ( rFrom += '<' ) += TRIM( aEmailName ) ) += '>';
1021 	}
1022 	else
1023 		rFrom.Erase();
1024 	return ( rFrom.Len() > 0 );
1025 }
1026