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