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