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