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