xref: /trunk/main/sw/source/ui/uno/unomailmerge.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <vcl/svapp.hxx>
33 #include <vos/mutex.hxx>
34 #include <osl/mutex.hxx>
35 #include <svl/itemprop.hxx>
36 #include <svl/urihelper.hxx>
37 #include <svx/dataaccessdescriptor.hxx>
38 #include <tools/shl.hxx>    // GetAppData
39 #include <tools/tempfile.hxx>
40 #include <sfx2/app.hxx>
41 #include <sfx2/docfile.hxx>
42 #include <sfx2/docfilt.hxx>
43 #include <comphelper/processfactory.hxx>
44 #include <vcl/timer.hxx>
45 #include <com/sun/star/sdb/CommandType.hpp>
46 #include <com/sun/star/text/MailMergeType.hpp>
47 #include <com/sun/star/text/MailMergeEvent.hpp>
48 #include <com/sun/star/text/XMailMergeListener.hpp>
49 #include <com/sun/star/text/XMailMergeBroadcaster.hpp>
50 #include <com/sun/star/beans/PropertyAttribute.hpp>
51 #include <com/sun/star/lang/XUnoTunnel.hpp>
52 #include <com/sun/star/sdbc/XResultSet.hpp>
53 #include <com/sun/star/sdbc/XConnection.hpp>
54 #include <com/sun/star/sdbc/XRowSet.hpp>
55 #include <com/sun/star/frame/XComponentLoader.hpp>
56 #include <com/sun/star/util/XCloseable.hpp>
57 #ifndef _COM_SUN_STAR_UTIL_CloseVetoException_HPP_
58 #include <com/sun/star/util/CloseVetoException.hpp>
59 #endif
60 #include <com/sun/star/sdbcx/XRowLocate.hpp>
61 #include <com/sun/star/frame/XStorable.hpp>
62 #include "com/sun/star/mail/XSmtpService.hpp"
63 #include <sfx2/viewfrm.hxx>
64 #include <sfx2/event.hxx>
65 #include <swevent.hxx>
66 #include <unomailmerge.hxx>
67 #include <swdll.hxx>
68 #include <swmodule.hxx>
69 #include <unoprnms.hxx>
70 #include <unomap.hxx>
71 #include <swunohelper.hxx>
72 #include <docsh.hxx>
73 #ifndef IDOCUMENTDEVICEACCESS_HXX_INCLUDED
74 #include <IDocumentDeviceAccess.hxx>
75 #endif
76 #include <view.hxx>
77 #include <dbmgr.hxx>
78 #include <unotxdoc.hxx>
79 #include <prtopt.hxx>
80 #include <wrtsh.hxx>
81 #include <shellio.hxx>
82 #include <mmconfigitem.hxx>
83 #include <mailmergehelper.hxx>
84 #include <memory>
85 
86 #include <unomid.h>
87 
88 
89 #define SN_MAIL_MERGE               "com.sun.star.text.MailMerge"
90 #define SN_DATA_ACCESS_DESCRIPTOR   "com.sun.star.sdb.DataAccessDescriptor"
91 
92 using namespace ::com::sun::star;
93 using namespace ::com::sun::star::frame;
94 using namespace ::com::sun::star::uno;
95 using namespace ::com::sun::star::lang;
96 using namespace ::com::sun::star::beans;
97 using namespace ::com::sun::star::text;
98 using ::rtl::OUString;
99 using namespace SWUnoHelper;
100 
101 ////////////////////////////////////////////////////////////
102 
103 typedef ::utl::SharedUNOComponent< XInterface > SharedComponent;
104 
105 ////////////////////////////////////////////////////////////
106 
107 osl::Mutex &    GetMailMergeMutex()
108 {
109     static osl::Mutex   aMutex;
110     return aMutex;
111 }
112 
113 ////////////////////////////////////////////////////////////
114 
115 enum CloseResult
116 {
117 	eSuccess,		// successfully closed
118 	eVetoed,		// vetoed, ownership transfered to the vetoing instance
119 	eFailed			// failed for some unknown reason
120 };
121 static CloseResult CloseModelAndDocSh(
122        Reference< frame::XModel > &rxModel,
123        SfxObjectShellRef &rxDocSh )
124 {
125 	CloseResult eResult = eSuccess;
126 
127     rxDocSh = 0;
128 
129     //! models/documents should never be disposed (they may still be
130     //! used for printing which is called asynchronously for example)
131     //! instead call close
132     Reference< util::XCloseable > xClose( rxModel, UNO_QUERY );
133     if (xClose.is())
134     {
135         try
136         {
137             //! 'sal_True' -> transfer ownership to vetoing object if vetoed!
138             //! I.e. now that object is responsible for closing the model and doc shell.
139             xClose->close( sal_True );
140         }
141         catch (util::CloseVetoException &)
142         {
143             //! here we have the problem that the temporary file that is
144 			//! currently being printed will never be deleted. :-(
145 			eResult = eVetoed;
146         }
147 		catch ( const uno::RuntimeException& )
148 		{
149 			eResult = eFailed;
150 		}
151     }
152 	return eResult;
153 }
154 
155 ////////////////////////////////////////////////////////////
156 
157 static sal_Bool LoadFromURL_impl(
158         Reference< frame::XModel > &rxModel,
159         SfxObjectShellRef &rxDocSh,
160         const String &rURL,
161         sal_Bool bClose )
162     throw (RuntimeException)
163 {
164     // try to open the document readonly and hidden
165     Reference< frame::XModel > xTmpModel;
166     Sequence < PropertyValue > aArgs( 1 );
167     aArgs[0].Name = C2U("Hidden");
168     sal_Bool bVal = sal_True;
169     aArgs[0].Value <<= bVal;
170     try
171     {
172         Reference < XComponentLoader > xDesktop( ::comphelper::getProcessServiceFactory()->
173                 createInstance( C2U("com.sun.star.frame.Desktop") ), UNO_QUERY );
174         xTmpModel = Reference < XModel >( xDesktop->loadComponentFromURL(
175                 rURL, C2U("_blank"), 0, aArgs ), UNO_QUERY );
176     }
177     catch( Exception & )
178     {
179         return sal_False;
180     }
181 
182     // try to get the DocShell
183     SwDocShell *pTmpDocShell = 0;
184     Reference < XUnoTunnel > xTunnel( xTmpModel, UNO_QUERY );
185     if (xTunnel.is())
186     {
187         SwXTextDocument* pTextDoc = reinterpret_cast<SwXTextDocument *>(
188                 xTunnel->getSomething( SwXTextDocument::getUnoTunnelId() ));
189         pTmpDocShell = pTextDoc ? pTextDoc->GetDocShell() : 0;
190     }
191 
192     sal_Bool bRes = sal_False;
193     if (xTmpModel.is() && pTmpDocShell)    // everything available?
194     {
195         if (bClose)
196             CloseModelAndDocSh( rxModel, rxDocSh );
197         // set new stuff
198         rxModel = xTmpModel;
199         rxDocSh = pTmpDocShell;
200         bRes = sal_True;
201     }
202     else
203     {
204         // SfxObjectShellRef is ok here, since the document will be explicitly closed
205         SfxObjectShellRef xTmpDocSh = pTmpDocShell;
206         CloseModelAndDocSh( xTmpModel, xTmpDocSh );
207     }
208 
209     return bRes;
210 }
211 
212 //==========================================================
213 namespace
214 {
215     class DelayedFileDeletion : public ::cppu::WeakImplHelper1< util::XCloseListener >
216 	{
217 	protected:
218 		::osl::Mutex					m_aMutex;
219 		Reference< util::XCloseable >	m_xDocument;
220 		Timer							m_aDeleteTimer;
221 		String							m_sTemporaryFile;
222 		sal_Int32						m_nPendingDeleteAttempts;
223 
224 	public:
225 		DelayedFileDeletion( const Reference< XModel >& _rxModel,
226 							 const String& _rTemporaryFile );
227 
228 	protected:
229 		~DelayedFileDeletion( );
230 
231 		// XCloseListener
232 		virtual void SAL_CALL queryClosing( const EventObject& _rSource, sal_Bool _bGetsOwnership ) throw (util::CloseVetoException, RuntimeException);
233 		virtual void SAL_CALL notifyClosing( const EventObject& _rSource ) throw (RuntimeException);
234 
235 		// XEventListener
236 		virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException);
237 
238 	private:
239 		void implTakeOwnership( );
240 		DECL_LINK( OnTryDeleteFile, void* );
241 
242 	private:
243 		DelayedFileDeletion( const DelayedFileDeletion& );					// never implemented
244 		DelayedFileDeletion& operator=( const DelayedFileDeletion& );		// never implemented
245 	};
246 
247 	DBG_NAME( DelayedFileDeletion )
248 	//------------------------------------------------------
249 	DelayedFileDeletion::DelayedFileDeletion( const Reference< XModel >& _rxModel, const String& _rTemporaryFile )
250         :
251         m_xDocument( _rxModel, UNO_QUERY )
252         ,m_sTemporaryFile( _rTemporaryFile )
253 		,m_nPendingDeleteAttempts( 0 )
254 	{
255 		DBG_CTOR( DelayedFileDeletion, NULL );
256 
257 		osl_incrementInterlockedCount( &m_refCount );
258 		try
259 		{
260 			if ( m_xDocument.is() )
261 			{
262 				m_xDocument->addCloseListener( this );
263 				// successfully added -> keep ourself alive
264 				acquire();
265 			}
266 			else {
267 				DBG_ERROR( "DelayedFileDeletion::DelayedFileDeletion: model is no component!" );
268             }
269 		}
270 		catch( const Exception& )
271 		{
272 			DBG_ERROR( "DelayedFileDeletion::DelayedFileDeletion: could not register as event listener at the model!" );
273 		}
274 		osl_decrementInterlockedCount( &m_refCount );
275 	}
276 
277 	//--------------------------------------------------------------------
278     IMPL_LINK( DelayedFileDeletion, OnTryDeleteFile, void*, EMPTYARG )
279 	{
280 		::osl::ClearableMutexGuard aGuard( m_aMutex );
281 
282 		sal_Bool bSuccess = sal_False;
283 		try
284 		{
285 			sal_Bool bDeliverOwnership = ( 0 == m_nPendingDeleteAttempts );
286 				// if this is our last attemt, then anybody which vetoes this has to take the consequences
287 				// (means take the ownership)
288 			m_xDocument->close( bDeliverOwnership );
289 			bSuccess = sal_True;
290 		}
291 		catch( const util::CloseVetoException& )
292 		{
293 			// somebody vetoed -> next try
294 			if ( m_nPendingDeleteAttempts )
295 			{
296 				// next attempt
297 				--m_nPendingDeleteAttempts;
298 				m_aDeleteTimer.Start();
299 			}
300 			else
301 				bSuccess = sal_True;	// can't do anything here ...
302 		}
303 		catch( const Exception& )
304 		{
305 			DBG_ERROR( "DelayedFileDeletion::OnTryDeleteFile: caught a strange exception!" );
306 			bSuccess = sal_True;
307 				// can't do anything here ...
308 		}
309 
310 		if ( bSuccess )
311 		{
312 			SWUnoHelper::UCB_DeleteFile( m_sTemporaryFile );
313 			aGuard.clear();
314 			release();	// this should be our last reference, we should be dead after this
315 		}
316 		return 0L;
317 	}
318 
319 	//--------------------------------------------------------------------
320 	void DelayedFileDeletion::implTakeOwnership( )
321 	{
322 		// revoke ourself as listener
323 		try
324 		{
325 			m_xDocument->removeCloseListener( this );
326 		}
327 		catch( const Exception & )
328 		{
329 			DBG_ERROR( "DelayedFileDeletion::implTakeOwnership: could not revoke the listener!" );
330 		}
331 
332 		m_aDeleteTimer.SetTimeout( 3000 );	// 3 seconds
333 		m_aDeleteTimer.SetTimeoutHdl( LINK( this, DelayedFileDeletion, OnTryDeleteFile ) );
334 		m_nPendingDeleteAttempts = 3;	// try 3 times at most
335 		m_aDeleteTimer.Start( );
336 	}
337 
338 	//--------------------------------------------------------------------
339     void SAL_CALL DelayedFileDeletion::queryClosing( const EventObject& , sal_Bool _bGetsOwnership ) throw (util::CloseVetoException, RuntimeException)
340 	{
341 		::osl::MutexGuard aGuard( m_aMutex );
342 		if ( _bGetsOwnership )
343 			implTakeOwnership( );
344 
345 		// always veto: We want to take the ownership ourself, as this is the only chance to delete
346 		// the temporary file which the model is based on
347 		throw util::CloseVetoException( );
348 	}
349 
350 	//--------------------------------------------------------------------
351     void SAL_CALL DelayedFileDeletion::notifyClosing( const EventObject&  ) throw (RuntimeException)
352 	{
353 		DBG_ERROR( "DelayedFileDeletion::notifyClosing: how this?" );
354 		// this should not happen:
355 		// Either, a foreign instance closes the document, then we should veto this, and take the ownership
356 		// Or, we ourself close the document, then we should not be a listener anymore
357 	}
358 
359 	//------------------------------------------------------
360     void SAL_CALL DelayedFileDeletion::disposing( const EventObject&  ) throw (RuntimeException)
361 	{
362 		DBG_ERROR( "DelayedFileDeletion::disposing: how this?" );
363 		// this should not happen:
364 		// Either, a foreign instance closes the document, then we should veto this, and take the ownership
365 		// Or, we ourself close the document, then we should not be a listener anymore
366 	}
367 
368 	//------------------------------------------------------
369 	DelayedFileDeletion::~DelayedFileDeletion( )
370 	{
371 		DBG_DTOR( DelayedFileDeletion, NULL );
372 	}
373 }
374 
375 ////////////////////////////////////////////////////////////
376 
377 static sal_Bool DeleteTmpFile_Impl(
378         Reference< frame::XModel > &rxModel,
379         SfxObjectShellRef &rxDocSh,
380         const String &rTmpFileURL )
381 {
382     sal_Bool bRes = sal_False;
383     if (rTmpFileURL.Len())
384     {
385 		sal_Bool bDelete = sal_True;
386 		if ( eVetoed == CloseModelAndDocSh( rxModel, rxDocSh ) )
387 		{
388 			// somebody vetoed the closing, and took the ownership of the document
389 			// -> ensure that the temporary file is deleted later on
390 			Reference< XEventListener > xEnsureDelete( new DelayedFileDeletion( rxModel, rTmpFileURL ) );
391 				// note: as soon as #106931# is fixed, the whole DelayedFileDeletion is to be superseeded by
392 				// a better solution
393 			bDelete = sal_False;
394 		}
395 
396         rxModel = 0;
397         rxDocSh = 0; // destroy doc shell
398 
399 		if ( bDelete )
400 		{
401 			if ( !SWUnoHelper::UCB_DeleteFile( rTmpFileURL ) )
402 			{
403 				Reference< XEventListener > xEnsureDelete( new DelayedFileDeletion( rxModel, rTmpFileURL ) );
404 					// same not as above: as soon as #106931#, ...
405 			}
406 		}
407 		else
408 			bRes = sal_True;	// file will be deleted delayed
409     }
410     return bRes;
411 }
412 
413 ////////////////////////////////////////////////////////////
414 
415 SwXMailMerge::SwXMailMerge() :
416     aEvtListeners   ( GetMailMergeMutex() ),
417     aMergeListeners ( GetMailMergeMutex() ),
418     aPropListeners  ( GetMailMergeMutex() ),
419     pPropSet( aSwMapProvider.GetPropertySet( PROPERTY_MAP_MAILMERGE ) ),
420     bSendAsHTML(sal_False),
421     bSendAsAttachment(sal_False),
422     bSaveAsSingleFile(sal_False)
423 
424 {
425     // create empty document
426     // like in: SwModule::InsertEnv (appenv.cxx)
427     SwDocShell *pDocShell = new SwDocShell( SFX_CREATE_MODE_STANDARD );
428     xDocSh = pDocShell;
429     xDocSh->DoInitNew( 0 );
430     SfxViewFrame *pFrame = SfxViewFrame::LoadHiddenDocument( *xDocSh, 0 );
431     SwView *pView = (SwView*) pFrame->GetViewShell();
432     pView->AttrChangedNotify( &pView->GetWrtShell() );//Damit SelectShell gerufen wird.
433 
434     xModel = pDocShell->GetModel();
435 
436     nDataCommandType    = sdb::CommandType::TABLE;
437     nOutputType         = MailMergeType::PRINTER;
438     bEscapeProcessing   = sal_True;     //!! allow to process properties like "Filter", "Order", ...
439     bSinglePrintJobs    = sal_False;
440     bFileNameFromColumn = sal_False;
441 
442     bDisposing = sal_False;
443 }
444 
445 SwXMailMerge::~SwXMailMerge()
446 {
447 	if (aTmpFileName.Len())
448 		DeleteTmpFile_Impl( xModel, xDocSh, aTmpFileName );
449 	else	// there was no temporary file in use
450 	{
451 		//! we still need to close the model and doc shell manually
452 		//! because there is no automatism that will do that later.
453 		//! #120086#
454 		if ( eVetoed == CloseModelAndDocSh( xModel, xDocSh ) )
455 			DBG_WARNING( "owner ship transfered to vetoing object!" );
456 
457         xModel = 0;
458         xDocSh = 0; // destroy doc shell
459 	}
460 }
461 
462 uno::Any SAL_CALL SwXMailMerge::execute(
463         const uno::Sequence< beans::NamedValue >& rArguments )
464     throw (IllegalArgumentException, Exception, RuntimeException)
465 {
466     vos::OGuard aGuard( Application::GetSolarMutex() );
467 
468     //
469     // get property values to be used
470     // (use values from the service as default and override them with
471     // the values that are provided as arguments)
472     //
473     uno::Sequence< uno::Any >           aCurSelection   = aSelection;
474     uno::Reference< sdbc::XResultSet >  xCurResultSet   = xResultSet;
475     uno::Reference< sdbc::XConnection > xCurConnection  = xConnection;
476     uno::Reference< frame::XModel >     xCurModel       = xModel;
477     OUString   aCurDataSourceName       = aDataSourceName;
478     OUString   aCurDataCommand          = aDataCommand;
479     OUString   aCurFilter               = aFilter;
480     OUString   aCurDocumentURL          = aDocumentURL;
481     OUString   aCurOutputURL            = aOutputURL;
482     OUString   aCurFileNamePrefix       = aFileNamePrefix;
483     sal_Int32  nCurDataCommandType      = nDataCommandType;
484     sal_Int16  nCurOutputType           = nOutputType;
485     sal_Bool   bCurEscapeProcessing     = bEscapeProcessing;
486     sal_Bool   bCurSinglePrintJobs      = bSinglePrintJobs;
487     sal_Bool   bCurFileNameFromColumn   = bFileNameFromColumn;
488     //
489     SfxObjectShellRef xCurDocSh = xDocSh;   // the document
490     //
491     const beans::NamedValue *pArguments = rArguments.getConstArray();
492     sal_Int32 nArgs = rArguments.getLength();
493     for (sal_Int32 i = 0;  i < nArgs;  ++i)
494     {
495         const OUString &rName   = pArguments[i].Name;
496         const Any &rValue       = pArguments[i].Value;
497 
498         sal_Bool bOK = sal_True;
499         if (rName.equalsAscii( GetPropName( UNO_NAME_SELECTION ) ))
500             bOK = rValue >>= aCurSelection;
501         else if (rName.equalsAscii( GetPropName( UNO_NAME_RESULT_SET ) ))
502             bOK = rValue >>= xCurResultSet;
503         else if (rName.equalsAscii( GetPropName( UNO_NAME_CONNECTION ) ))
504             bOK = rValue >>= xCurConnection;
505         else if (rName.equalsAscii( GetPropName( UNO_NAME_MODEL ) ))
506             throw PropertyVetoException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property is read-only: " ) ) + rName, static_cast < cppu::OWeakObject * > ( this ) );
507         else if (rName.equalsAscii( GetPropName( UNO_NAME_DATA_SOURCE_NAME ) ))
508             bOK = rValue >>= aCurDataSourceName;
509         else if (rName.equalsAscii( GetPropName( UNO_NAME_DAD_COMMAND ) ))
510             bOK = rValue >>= aCurDataCommand;
511         else if (rName.equalsAscii( GetPropName( UNO_NAME_FILTER ) ))
512             bOK = rValue >>= aCurFilter;
513         else if (rName.equalsAscii( GetPropName( UNO_NAME_DOCUMENT_URL ) ))
514         {
515             bOK = rValue >>= aCurDocumentURL;
516             if (aCurDocumentURL.getLength()
517                 && !LoadFromURL_impl( xCurModel, xCurDocSh, aCurDocumentURL, sal_False ))
518                 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Failed to create document from URL: " ) ) + aCurDocumentURL, static_cast < cppu::OWeakObject * > ( this ) );
519         }
520         else if (rName.equalsAscii( GetPropName( UNO_NAME_OUTPUT_URL ) ))
521         {
522             bOK = rValue >>= aCurOutputURL;
523             if (aCurOutputURL.getLength())
524             {
525                 if (!UCB_IsDirectory(aCurOutputURL))
526                     throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "URL does not point to a directory: " ) ) + aCurOutputURL, static_cast < cppu::OWeakObject * > ( this ), 0 );
527                 if (UCB_IsReadOnlyFileName(aCurOutputURL))
528                     throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "URL is read-only: " ) ) + aCurOutputURL, static_cast < cppu::OWeakObject * > ( this ), 0 );
529             }
530         }
531         else if (rName.equalsAscii( GetPropName( UNO_NAME_FILE_NAME_PREFIX ) ))
532             bOK = rValue >>= aCurFileNamePrefix;
533         else if (rName.equalsAscii( GetPropName( UNO_NAME_DAD_COMMAND_TYPE ) ))
534             bOK = rValue >>= nCurDataCommandType;
535         else if (rName.equalsAscii( GetPropName( UNO_NAME_OUTPUT_TYPE ) ))
536             bOK = rValue >>= nCurOutputType;
537         else if (rName.equalsAscii( GetPropName( UNO_NAME_ESCAPE_PROCESSING ) ))
538             bOK = rValue >>= bCurEscapeProcessing;
539         else if (rName.equalsAscii( GetPropName( UNO_NAME_SINGLE_PRINT_JOBS ) ))
540             bOK = rValue >>= bCurSinglePrintJobs;
541         else if (rName.equalsAscii( GetPropName( UNO_NAME_FILE_NAME_FROM_COLUMN ) ))
542             bOK = rValue >>= bCurFileNameFromColumn;
543         else if (rName.equalsAscii( GetPropName( UNO_NAME_SUBJECT ) ))
544             bOK = rValue >>= sSubject;
545         else if (rName.equalsAscii( GetPropName( UNO_NAME_ADDRESS_FROM_COLUMN ) ))
546             bOK = rValue >>= sAddressFromColumn;
547         else if (rName.equalsAscii( GetPropName( UNO_NAME_SEND_AS_HTML ) ))
548             bOK = rValue >>= bSendAsHTML;
549         else if (rName.equalsAscii( GetPropName( UNO_NAME_MAIL_BODY ) ))
550             bOK = rValue >>= sMailBody;
551         else if (rName.equalsAscii( GetPropName( UNO_NAME_ATTACHMENT_NAME ) ))
552             bOK = rValue >>= sAttachmentName;
553         else if (rName.equalsAscii( GetPropName( UNO_NAME_ATTACHMENT_FILTER ) ))
554             bOK = rValue >>= sAttachmentFilter;
555         else if (rName.equalsAscii( GetPropName( UNO_NAME_COPIES_TO ) ))
556             bOK = rValue >>= aCopiesTo;
557         else if (rName.equalsAscii( GetPropName( UNO_NAME_BLIND_COPIES_TO ) ))
558             bOK = rValue >>= aBlindCopiesTo;
559         else if (rName.equalsAscii( GetPropName( UNO_NAME_SEND_AS_ATTACHMENT ) ))
560             bOK = rValue >>= bSendAsAttachment;
561         else if (rName.equalsAscii( GetPropName( UNO_NAME_PRINT_OPTIONS ) ))
562             bOK = rValue >>= aPrintSettings;
563         else if (rName.equalsAscii( GetPropName( UNO_NAME_SAVE_AS_SINGLE_FILE ) ))
564             bOK = rValue >>= bSaveAsSingleFile;
565         else if (rName.equalsAscii( GetPropName( UNO_NAME_SAVE_FILTER ) ))
566             bOK = rValue >>= sSaveFilter;
567         else if (rName.equalsAscii( GetPropName( UNO_NAME_SAVE_FILTER_OPTIONS ) ))
568             bOK = rValue >>= sSaveFilterOptions;
569         else if (rName.equalsAscii( GetPropName( UNO_NAME_SAVE_FILTER_DATA ) ))
570             bOK = rValue >>= aSaveFilterData;
571         else if (rName.equalsAscii( GetPropName( UNO_NAME_IN_SERVER_PASSWORD ) ))
572             bOK = rValue >>= sInServerPassword;
573         else if (rName.equalsAscii( GetPropName( UNO_NAME_OUT_SERVER_PASSWORD ) ))
574             bOK = rValue >>= sOutServerPassword;
575         else
576             throw UnknownPropertyException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property is unknown: " ) ) + rName, static_cast < cppu::OWeakObject * > ( this ) );
577 
578         if (!bOK)
579             throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property type mismatch or property not set: " ) ) + rName, static_cast < cppu::OWeakObject * > ( this ), 0 );
580     }
581 
582 	// need to translate the selection: the API here requires a sequence of bookmarks, but the MergeNew
583 	// method we will call below requires a sequence of indicies.
584 	if ( aCurSelection.getLength() )
585 	{
586 		Sequence< Any > aTranslated( aCurSelection.getLength() );
587 
588 		sal_Bool bValid = sal_False;
589 		Reference< sdbcx::XRowLocate > xRowLocate( xCurResultSet, UNO_QUERY );
590 		if ( xRowLocate.is() )
591 		{
592 
593 			const Any* pBookmarks = aCurSelection.getConstArray();
594 			const Any* pBookmarksEnd = pBookmarks + aCurSelection.getLength();
595 			Any* pTranslated = aTranslated.getArray();
596 
597 			try
598 			{
599 				sal_Bool bEverythingsFine = sal_True;
600 				for ( ; ( pBookmarks != pBookmarksEnd ) && bEverythingsFine; ++pBookmarks )
601 				{
602 					if ( xRowLocate->moveToBookmark( *pBookmarks ) )
603 						*pTranslated <<= xCurResultSet->getRow();
604 					else
605 						bEverythingsFine = sal_False;
606 				}
607 				if ( bEverythingsFine )
608 					bValid = sal_True;
609 			}
610 			catch( const Exception& )
611 			{
612 				bValid = sal_False;
613 			}
614 		}
615 
616 		if ( !bValid )
617 		{
618             throw IllegalArgumentException(
619 				OUString ( RTL_CONSTASCII_USTRINGPARAM ( "The current 'Selection' does not describe a valid array of bookmarks, relative to the current 'ResultSet'." ) ),
620 				static_cast < cppu::OWeakObject * > ( this ),
621 				0
622 			);
623 		}
624 
625 		aCurSelection = aTranslated;
626 	}
627 
628     SfxViewFrame*   pFrame = SfxViewFrame::GetFirst( xCurDocSh, sal_False);
629     SwView *pView = PTR_CAST( SwView, pFrame->GetViewShell() );
630     if (!pView)
631         throw RuntimeException();
632     SwWrtShell &rSh = *pView->GetWrtShellPtr();
633 
634     // avoid assertion in 'Update' from Sfx by supplying a shell
635     // and thus avoiding the SelectShell call in Writers GetState function
636     // while still in Update of Sfx.
637     // (GetSelection in Update is not allowed)
638     if (pView && aCurDocumentURL.getLength())
639         pView->AttrChangedNotify( &pView->GetWrtShell() );//Damit SelectShell gerufen wird.
640 
641     SharedComponent aRowSetDisposeHelper;
642     if (!xCurResultSet.is())
643     {
644         if (!aCurDataSourceName.getLength() || !aCurDataCommand.getLength() )
645         {
646             DBG_ERROR("PropertyValues missing or unset");
647             throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Either the ResultSet or DataSourceName and DataCommand must be set." ) ), static_cast < cppu::OWeakObject * > ( this ), 0 );
648         }
649 
650         //
651         // build ResultSet from DataSourceName, DataCommand and DataCommandType
652         //
653         Reference< XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() );
654         if (xMgr.is())
655         {
656             Reference< XInterface > xInstance = xMgr->createInstance(
657                     C2U( "com.sun.star.sdb.RowSet" ));
658             aRowSetDisposeHelper.reset( xInstance, SharedComponent::TakeOwnership );
659             Reference< XPropertySet > xRowSetPropSet( xInstance, UNO_QUERY );
660             DBG_ASSERT( xRowSetPropSet.is(), "failed to get XPropertySet interface from RowSet" );
661             if (xRowSetPropSet.is())
662             {
663                 if (xCurConnection.is())
664                     xRowSetPropSet->setPropertyValue( C2U("ActiveConnection"),  makeAny( xCurConnection ) );
665                 xRowSetPropSet->setPropertyValue( C2U("DataSourceName"),    makeAny( aCurDataSourceName ) );
666                 xRowSetPropSet->setPropertyValue( C2U("Command"),           makeAny( aCurDataCommand ) );
667                 xRowSetPropSet->setPropertyValue( C2U("CommandType"),       makeAny( nCurDataCommandType ) );
668                 xRowSetPropSet->setPropertyValue( C2U("EscapeProcessing"),  makeAny( bCurEscapeProcessing ) );
669                 xRowSetPropSet->setPropertyValue( C2U("ApplyFilter"),       makeAny( sal_True ) );
670                 xRowSetPropSet->setPropertyValue( C2U("Filter"),            makeAny( aCurFilter ) );
671 
672                 Reference< sdbc::XRowSet > xRowSet( xInstance, UNO_QUERY );
673                 if (xRowSet.is())
674                     xRowSet->execute(); // build ResultSet from properties
675                 if( !xCurConnection.is() )
676                     xCurConnection.set( xRowSetPropSet->getPropertyValue( C2U( "ActiveConnection" )), UNO_QUERY );
677                 xCurResultSet = Reference< sdbc::XResultSet >( xRowSet, UNO_QUERY );
678                 DBG_ASSERT( xCurResultSet.is(), "failed to build ResultSet" );
679             }
680         }
681     }
682 
683     svx::ODataAccessDescriptor aDescriptor;
684     aDescriptor.setDataSource(aCurDataSourceName);
685     aDescriptor[ svx::daConnection ]         <<= xCurConnection;
686     aDescriptor[ svx::daCommand ]            <<= aCurDataCommand;
687     aDescriptor[ svx::daCommandType ]        <<= nCurDataCommandType;
688     aDescriptor[ svx::daEscapeProcessing ]   <<= bCurEscapeProcessing;
689     aDescriptor[ svx::daCursor ]             <<= xCurResultSet;
690     // aDescriptor[ svx::daColumnName ]      not used
691     // aDescriptor[ svx::daColumnObject ]    not used
692     aDescriptor[ svx::daSelection ]          <<= aCurSelection;
693 
694     sal_uInt16 nMergeType;
695     switch (nCurOutputType)
696     {
697         case MailMergeType::PRINTER : nMergeType = DBMGR_MERGE_MAILMERGE; break;
698         case MailMergeType::FILE    : nMergeType = DBMGR_MERGE_MAILFILES; break;
699         case MailMergeType::MAIL    : nMergeType = DBMGR_MERGE_MAILING; break;
700         default:
701             throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Invalid value of property:" ) ) + C2U("OutputType"), static_cast < cppu::OWeakObject * > ( this ), 0 );
702     }
703 
704     SwNewDBMgr* pMgr = rSh.GetNewDBMgr();
705     //force layout creation
706     rSh.CalcLayout();
707     DBG_ASSERT( pMgr, "database manager missing" );
708 
709     SwMergeDescriptor aMergeDesc( nMergeType, rSh, aDescriptor );
710 
711     std::auto_ptr< SwMailMergeConfigItem > pMMConfigItem;
712     uno::Reference< mail::XMailService > xInService;
713     if (MailMergeType::PRINTER == nCurOutputType)
714     {
715         IDocumentDeviceAccess* pIDDA = rSh.getIDocumentDeviceAccess();
716         SwPrintData aPrtData( pIDDA->getPrintData() );
717         aPrtData.SetPrintSingleJobs( bCurSinglePrintJobs );
718         pIDDA->setPrintData( aPrtData );
719         // #i25686# printing should not be done asynchronously to prevent dangling offices
720         // when mail merge is called as command line macro
721         aMergeDesc.bPrintAsync = sal_False;
722         aMergeDesc.aPrintOptions = aPrintSettings;
723         aMergeDesc.bCreateSingleFile = true;
724     }
725     else /* FILE and MAIL*/
726     {
727 		INetURLObject aURLObj;
728         aURLObj.SetSmartProtocol( INET_PROT_FILE );
729 
730 		if (aCurDocumentURL.getLength())
731 		{
732 			// if OutputURL or FileNamePrefix are missing get
733 			// them from DocumentURL
734             aURLObj.SetSmartURL( aCurDocumentURL );
735 			if (!aCurFileNamePrefix.getLength())
736                 aCurFileNamePrefix = aURLObj.GetBase(); // filename without extension
737             if (!aCurOutputURL.getLength())
738             {
739                 //aCurOutputURL = aURLObj.GetURLPath();
740                 aURLObj.removeSegment();
741                 aCurOutputURL = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
742             }
743 		}
744 		else	// default empty document without URL
745 		{
746 			if (!aCurOutputURL.getLength())
747 				throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "OutputURL is not set and can not be obtained." ) ), static_cast < cppu::OWeakObject * > ( this ) );
748 		}
749 
750 		aURLObj.SetSmartURL( aCurOutputURL );
751         String aPath = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
752 
753         String aDelim( INET_PATH_TOKEN );
754         if (aPath.Len() >= aDelim.Len() &&
755             aPath.Copy( aPath.Len()-aDelim.Len() ).CompareTo( aDelim ) != COMPARE_EQUAL)
756             aPath += aDelim;
757         if (bCurFileNameFromColumn)
758             pMgr->SetEMailColumn( aCurFileNamePrefix );
759         else
760         {
761             aPath += String( aCurFileNamePrefix );
762             pMgr->SetEMailColumn( String() );
763         }
764         pMgr->SetSubject( aPath );
765         if(MailMergeType::FILE == nCurOutputType)
766         {
767             aMergeDesc.sSaveToFilter = sSaveFilter;
768             aMergeDesc.sSaveToFilterOptions = sSaveFilterOptions;
769             aMergeDesc.aSaveToFilterData = aSaveFilterData;
770             aMergeDesc.bCreateSingleFile = bSaveAsSingleFile;
771         }
772         else /*if(MailMergeType::MAIL == nCurOutputType)*/
773         {
774             pMgr->SetEMailColumn( sAddressFromColumn );
775             if(!sAddressFromColumn.getLength())
776                 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Mail address column not set." ) ), static_cast < cppu::OWeakObject * > ( this ) );
777             aMergeDesc.sSaveToFilter     = sAttachmentFilter;
778             aMergeDesc.sSubject          = sSubject;
779             aMergeDesc.sMailBody         = sMailBody;
780             aMergeDesc.sAttachmentName   = sAttachmentName;
781             aMergeDesc.aCopiesTo         = aCopiesTo;
782             aMergeDesc.aBlindCopiesTo    = aBlindCopiesTo;
783             aMergeDesc.bSendAsHTML       = bSendAsHTML;
784             aMergeDesc.bSendAsAttachment = bSendAsAttachment;
785 
786             aMergeDesc.bCreateSingleFile = sal_False;
787             pMMConfigItem = std::auto_ptr< SwMailMergeConfigItem >(new SwMailMergeConfigItem);
788             aMergeDesc.pMailMergeConfigItem = pMMConfigItem.get();
789             aMergeDesc.xSmtpServer = SwMailMergeHelper::ConnectToSmtpServer(
790                     *pMMConfigItem,
791                     xInService,
792                     sInServerPassword, sOutServerPassword );
793             if( !aMergeDesc.xSmtpServer.is() || !aMergeDesc.xSmtpServer->isConnected())
794                 throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Failed to connect to mail server." ) ), static_cast < cppu::OWeakObject * > ( this ) );
795         }
796     }
797 
798 
799     // save document with temporary filename
800     const SfxFilter *pSfxFlt = SwIoSystem::GetFilterOfFormat(
801             String::CreateFromAscii( FILTER_XML ),
802             SwDocShell::Factory().GetFilterContainer() );
803     String aExtension( pSfxFlt->GetDefaultExtension() );
804     aExtension.EraseLeadingChars( '*' );
805     TempFile aTempFile( C2U("SwMM"), &aExtension );
806     aTmpFileName = aTempFile.GetName();
807 
808 	Reference< XStorable > xStorable( xCurModel, UNO_QUERY );
809 	sal_Bool bStoredAsTemporary = sal_False;
810 	if ( xStorable.is() )
811 	{
812 		try
813 		{
814 			xStorable->storeAsURL( aTmpFileName, Sequence< PropertyValue >() );
815 			bStoredAsTemporary = sal_True;
816 		}
817 		catch( const Exception& )
818 		{
819 		}
820 	}
821 	if ( !bStoredAsTemporary )
822         throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Failed to save temporary file." ) ), static_cast < cppu::OWeakObject * > ( this ) );
823 
824     pMgr->SetMergeSilent( sal_True );       // suppress dialogs, message boxes, etc.
825     const SwXMailMerge *pOldSrc = pMgr->GetMailMergeEvtSrc();
826     DBG_ASSERT( !pOldSrc || pOldSrc == this, "Ooops... different event source already set." );
827     pMgr->SetMailMergeEvtSrc( this );   // launch events for listeners
828 
829     SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_MAIL_MERGE, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE), xCurDocSh));
830     sal_Bool bSucc = pMgr->MergeNew( aMergeDesc );
831     SFX_APP()->NotifyEvent(SfxEventHint(SW_EVENT_MAIL_MERGE_END, SwDocShell::GetEventName(STR_SW_EVENT_MAIL_MERGE_END), xCurDocSh));
832 
833     pMgr->SetMailMergeEvtSrc( pOldSrc );
834 
835 	if ( xCurModel.get() != xModel.get() )
836 	{	// in case it was a temporary model -> close it, and delete the file
837 	    DeleteTmpFile_Impl( xCurModel, xCurDocSh, aTmpFileName );
838 		aTmpFileName.Erase();
839 	}
840 	// (in case it wasn't a temporary model, it will be closed in the dtor, at the latest)
841 
842     if (!bSucc)
843         throw Exception( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Mail merge failed. Sorry, no further information available." ) ), static_cast < cppu::OWeakObject * > ( this ) );
844 
845     //de-initialize services
846     if(xInService.is() && xInService->isConnected())
847         xInService->disconnect();
848     if(aMergeDesc.xSmtpServer.is() && aMergeDesc.xSmtpServer->isConnected())
849         aMergeDesc.xSmtpServer->disconnect();
850 
851     return makeAny( sal_True );
852 }
853 
854 void SwXMailMerge::LaunchMailMergeEvent( const MailMergeEvent &rEvt ) const
855 {
856     cppu::OInterfaceIteratorHelper aIt( ((SwXMailMerge *) this)->aMergeListeners );
857     while (aIt.hasMoreElements())
858     {
859         Reference< XMailMergeListener > xRef( aIt.next(), UNO_QUERY );
860         if (xRef.is())
861             xRef->notifyMailMergeEvent( rEvt );
862     }
863 }
864 
865 void SwXMailMerge::launchEvent( const PropertyChangeEvent &rEvt ) const
866 {
867     cppu::OInterfaceContainerHelper *pContainer =
868             aPropListeners.getContainer( rEvt.PropertyHandle );
869     if (pContainer)
870     {
871         cppu::OInterfaceIteratorHelper aIt( *pContainer );
872         while (aIt.hasMoreElements())
873         {
874             Reference< XPropertyChangeListener > xRef( aIt.next(), UNO_QUERY );
875             if (xRef.is())
876                 xRef->propertyChange( rEvt );
877         }
878     }
879 }
880 
881 
882 uno::Reference< beans::XPropertySetInfo > SAL_CALL SwXMailMerge::getPropertySetInfo(  )
883     throw (RuntimeException)
884 {
885     vos::OGuard aGuard( Application::GetSolarMutex() );
886     static Reference< XPropertySetInfo > aRef = pPropSet->getPropertySetInfo();
887     return aRef;
888 }
889 
890 void SAL_CALL SwXMailMerge::setPropertyValue(
891         const OUString& rPropertyName, const uno::Any& rValue )
892     throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
893 {
894     vos::OGuard aGuard( Application::GetSolarMutex() );
895 
896     const SfxItemPropertySimpleEntry* pCur = pPropSet->getPropertyMap()->getByName( rPropertyName );
897     if (!pCur)
898         throw UnknownPropertyException();
899     else if (pCur->nFlags & PropertyAttribute::READONLY)
900         throw PropertyVetoException();
901     else
902     {
903         void *pData = NULL;
904         const uno::Type* pType = pCur->pType;
905         switch (pCur->nWID)
906         {
907             case WID_SELECTION :                pData = &aSelection;  break;
908             case WID_RESULT_SET :               pData = &xResultSet;  break;
909             case WID_CONNECTION :               pData = &xConnection;  break;
910             case WID_MODEL :                    pData = &xModel;  break;
911             case WID_DATA_SOURCE_NAME :         pData = &aDataSourceName;  break;
912             case WID_DATA_COMMAND :             pData = &aDataCommand;  break;
913             case WID_FILTER :                   pData = &aFilter;  break;
914             case WID_DOCUMENT_URL :             pData = &aDocumentURL;  break;
915             case WID_OUTPUT_URL :               pData = &aOutputURL;  break;
916             case WID_DATA_COMMAND_TYPE :        pData = &nDataCommandType;  break;
917             case WID_OUTPUT_TYPE :              pData = &nOutputType;  break;
918             case WID_ESCAPE_PROCESSING :        pData = &bEscapeProcessing;  break;
919             case WID_SINGLE_PRINT_JOBS :        pData = &bSinglePrintJobs;  break;
920             case WID_FILE_NAME_FROM_COLUMN :    pData = &bFileNameFromColumn;  break;
921             case WID_FILE_NAME_PREFIX :         pData = &aFileNamePrefix;  break;
922             case WID_MAIL_SUBJECT:              pData = &sSubject; break;
923             case WID_ADDRESS_FROM_COLUMN:       pData = &sAddressFromColumn; break;
924             case WID_SEND_AS_HTML:              pData = &bSendAsHTML; break;
925             case WID_SEND_AS_ATTACHMENT:        pData = &bSendAsAttachment; break;
926             case WID_MAIL_BODY:                 pData = &sMailBody; break;
927             case WID_ATTACHMENT_NAME:           pData = &sAttachmentName; break;
928             case WID_ATTACHMENT_FILTER:         pData = &sAttachmentFilter;break;
929             case WID_PRINT_OPTIONS:             pData = &aPrintSettings; break;
930             case WID_SAVE_AS_SINGLE_FILE:       pData = &bSaveAsSingleFile; break;
931             case WID_SAVE_FILTER:               pData = &sSaveFilter; break;
932             case WID_SAVE_FILTER_OPTIONS:       pData = &sSaveFilterOptions; break;
933             case WID_SAVE_FILTER_DATA:          pData = &aSaveFilterData; break;
934             case WID_COPIES_TO:                 pData = &aCopiesTo; break;
935             case WID_BLIND_COPIES_TO:           pData = &aBlindCopiesTo;break;
936             case WID_IN_SERVER_PASSWORD:        pData = &sInServerPassword; break;
937             case WID_OUT_SERVER_PASSWORD:       pData = &sOutServerPassword; break;
938             default :
939                 DBG_ERROR("unknown WID");
940         }
941         Any aOld( pData, *pType );
942 
943         sal_Bool bChanged = sal_False;
944         sal_Bool bOK = sal_True;
945         if (aOld != rValue)
946         {
947             if (pData == &aSelection)
948                 bOK = rValue >>= aSelection;
949             else if (pData == &xResultSet)
950                 bOK = rValue >>= xResultSet;
951             else if (pData == &xConnection)
952                 bOK = rValue >>= xConnection;
953             else if (pData == &xModel)
954                 bOK = rValue >>= xModel;
955             else if (pData == &aDataSourceName)
956                 bOK = rValue >>= aDataSourceName;
957             else if (pData == &aDataCommand)
958                 bOK = rValue >>= aDataCommand;
959             else if (pData == &aFilter)
960                 bOK = rValue >>= aFilter;
961             else if (pData == &aDocumentURL)
962             {
963                 OUString aText;
964                 bOK = rValue >>= aText;
965                 if (aText.getLength()
966                     && !LoadFromURL_impl( xModel, xDocSh, aText, sal_True ))
967                     throw RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Failed to create document from URL: " ) ) + aText, static_cast < cppu::OWeakObject * > ( this ) );
968                 aDocumentURL = aText;
969             }
970             else if (pData == &aOutputURL)
971             {
972                 OUString aText;
973                 bOK = rValue >>= aText;
974                 if (aText.getLength())
975                 {
976                     if (!UCB_IsDirectory(aText))
977                         throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "URL does not point to a directory: " ) ) + aText, static_cast < cppu::OWeakObject * > ( this ), 0 );
978                     if (UCB_IsReadOnlyFileName(aText))
979                         throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "URL is read-only: " ) ) + aText, static_cast < cppu::OWeakObject * > ( this ), 0 );
980                 }
981                 aOutputURL = aText;
982             }
983             else if (pData == &nDataCommandType)
984                 bOK = rValue >>= nDataCommandType;
985             else if (pData == &nOutputType)
986                 bOK = rValue >>= nOutputType;
987             else if (pData == &bEscapeProcessing)
988                 bOK = rValue >>= bEscapeProcessing;
989             else if (pData == &bSinglePrintJobs)
990                 bOK = rValue >>= bSinglePrintJobs;
991             else if (pData == &bFileNameFromColumn)
992                 bOK = rValue >>= bFileNameFromColumn;
993             else if (pData == &aFileNamePrefix)
994                 bOK = rValue >>= aFileNamePrefix;
995             else if (pData == &sSubject)
996                 bOK = rValue >>= sSubject;
997             else if (pData == &sAddressFromColumn)
998                 bOK = rValue >>= sAddressFromColumn;
999             else if (pData == &bSendAsHTML)
1000                 bOK = rValue >>= bSendAsHTML;
1001             else if (pData == &bSendAsAttachment)
1002                 bOK = rValue >>= bSendAsAttachment;
1003             else if (pData == &sMailBody)
1004                 bOK = rValue >>= sMailBody;
1005             else if (pData == &sAttachmentName)
1006                 bOK = rValue >>= sAttachmentName;
1007             else if (pData == &sAttachmentFilter)
1008                 bOK = rValue >>= sAttachmentFilter;
1009             else if (pData == &aPrintSettings)
1010                 bOK = rValue >>= aPrintSettings;
1011             else if (pData == &bSaveAsSingleFile)
1012                 bOK = rValue >>= bSaveAsSingleFile;
1013             else if (pData == &sSaveFilter)
1014                 bOK = rValue >>= sSaveFilter;
1015             else if (pData == &sSaveFilterOptions)
1016                 bOK = rValue >>= sSaveFilterOptions;
1017             else if (pData == &aSaveFilterData)
1018                 bOK = rValue >>= aSaveFilterData;
1019             else if (pData == &aCopiesTo)
1020                 bOK = rValue >>= aCopiesTo;
1021             else if (pData == &aBlindCopiesTo)
1022                 bOK = rValue >>= aBlindCopiesTo;
1023             else if(pData == &sInServerPassword)
1024                 bOK = rValue >>= sInServerPassword;
1025             else if(pData == &sOutServerPassword)
1026                 bOK = rValue >>= sInServerPassword;
1027             else {
1028                 DBG_ERROR( "invalid pointer" );
1029             }
1030             DBG_ASSERT( bOK, "set value failed" );
1031             bChanged = sal_True;
1032         }
1033         if (!bOK)
1034             throw IllegalArgumentException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property type mismatch or property not set: " ) ) + rPropertyName, static_cast < cppu::OWeakObject * > ( this ), 0 );
1035 
1036         if (bChanged)
1037         {
1038             PropertyChangeEvent aChgEvt( (XPropertySet *) this, rPropertyName,
1039                     sal_False, pCur->nWID, aOld, rValue );
1040             launchEvent( aChgEvt );
1041         }
1042     }
1043 }
1044 
1045 uno::Any SAL_CALL SwXMailMerge::getPropertyValue(
1046         const OUString& rPropertyName )
1047     throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
1048 {
1049     vos::OGuard aGuard( Application::GetSolarMutex() );
1050 
1051     Any aRet;
1052 
1053     const SfxItemPropertySimpleEntry* pCur = pPropSet->getPropertyMap()->getByName( rPropertyName );
1054     if (!pCur)
1055         throw UnknownPropertyException();
1056     else
1057     {
1058         switch (pCur->nWID)
1059         {
1060             case WID_SELECTION :                aRet <<= aSelection;  break;
1061             case WID_RESULT_SET :               aRet <<= xResultSet;  break;
1062             case WID_CONNECTION :               aRet <<= xConnection;  break;
1063             case WID_MODEL :                    aRet <<= xModel;  break;
1064             case WID_DATA_SOURCE_NAME :         aRet <<= aDataSourceName;  break;
1065             case WID_DATA_COMMAND :             aRet <<= aDataCommand;  break;
1066             case WID_FILTER :                   aRet <<= aFilter;  break;
1067             case WID_DOCUMENT_URL :             aRet <<= aDocumentURL;  break;
1068             case WID_OUTPUT_URL :               aRet <<= aOutputURL;  break;
1069             case WID_DATA_COMMAND_TYPE :        aRet <<= nDataCommandType;  break;
1070             case WID_OUTPUT_TYPE :              aRet <<= nOutputType;  break;
1071             case WID_ESCAPE_PROCESSING :        aRet <<= bEscapeProcessing;  break;
1072             case WID_SINGLE_PRINT_JOBS :        aRet <<= bSinglePrintJobs;  break;
1073             case WID_FILE_NAME_FROM_COLUMN :    aRet <<= bFileNameFromColumn;  break;
1074             case WID_FILE_NAME_PREFIX :         aRet <<= aFileNamePrefix;  break;
1075             case WID_MAIL_SUBJECT:              aRet <<= sSubject; break;
1076             case WID_ADDRESS_FROM_COLUMN:       aRet <<= sAddressFromColumn; break;
1077             case WID_SEND_AS_HTML:              aRet <<= bSendAsHTML; break;
1078             case WID_SEND_AS_ATTACHMENT:        aRet <<= bSendAsAttachment; break;
1079             case WID_MAIL_BODY:                 aRet <<= sMailBody; break;
1080             case WID_ATTACHMENT_NAME:           aRet <<= sAttachmentName; break;
1081             case WID_ATTACHMENT_FILTER:         aRet <<= sAttachmentFilter;break;
1082             case WID_PRINT_OPTIONS:             aRet <<= aPrintSettings; break;
1083             case WID_SAVE_AS_SINGLE_FILE:       aRet <<= bSaveAsSingleFile; break;
1084             case WID_SAVE_FILTER:               aRet <<= sSaveFilter; break;
1085             case WID_SAVE_FILTER_OPTIONS:       aRet <<= sSaveFilterOptions; break;
1086             case WID_SAVE_FILTER_DATA:          aRet <<= aSaveFilterData; break;
1087             case WID_COPIES_TO:                 aRet <<= aCopiesTo; break;
1088             case WID_BLIND_COPIES_TO:           aRet <<= aBlindCopiesTo;break;
1089             case WID_IN_SERVER_PASSWORD:        aRet <<= sInServerPassword; break;
1090             case WID_OUT_SERVER_PASSWORD:       aRet <<= sOutServerPassword; break;
1091             default :
1092                 DBG_ERROR("unknown WID");
1093         }
1094     }
1095 
1096     return aRet;
1097 }
1098 
1099 void SAL_CALL SwXMailMerge::addPropertyChangeListener(
1100         const OUString& rPropertyName,
1101         const uno::Reference< beans::XPropertyChangeListener >& rListener )
1102     throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
1103 {
1104     vos::OGuard aGuard( Application::GetSolarMutex() );
1105     if (!bDisposing && rListener.is())
1106     {
1107         const SfxItemPropertySimpleEntry* pCur = pPropSet->getPropertyMap()->getByName( rPropertyName );
1108         if (pCur)
1109             aPropListeners.addInterface( pCur->nWID, rListener );
1110         else
1111             throw UnknownPropertyException();
1112     }
1113 }
1114 
1115 void SAL_CALL SwXMailMerge::removePropertyChangeListener(
1116         const OUString& rPropertyName,
1117         const uno::Reference< beans::XPropertyChangeListener >& rListener )
1118     throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
1119 {
1120     vos::OGuard aGuard( Application::GetSolarMutex() );
1121     if (!bDisposing && rListener.is())
1122     {
1123         const SfxItemPropertySimpleEntry* pCur = pPropSet->getPropertyMap()->getByName( rPropertyName );
1124         if (pCur)
1125             aPropListeners.removeInterface( pCur->nWID, rListener );
1126         else
1127             throw UnknownPropertyException();
1128     }
1129 }
1130 
1131 void SAL_CALL SwXMailMerge::addVetoableChangeListener(
1132         const OUString& /*rPropertyName*/,
1133         const uno::Reference< beans::XVetoableChangeListener >& /*rListener*/ )
1134     throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
1135 {
1136     // no vetoable property, thus no support for vetoable change listeners
1137     DBG_WARNING( "not implemented");
1138 }
1139 
1140 void SAL_CALL SwXMailMerge::removeVetoableChangeListener(
1141         const OUString& /*rPropertyName*/,
1142         const uno::Reference< beans::XVetoableChangeListener >& /*rListener*/ )
1143     throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
1144 {
1145     // no vetoable property, thus no support for vetoable change listeners
1146     DBG_WARNING( "not implemented");
1147 }
1148 
1149 
1150 void SAL_CALL SwXMailMerge::dispose()
1151     throw(RuntimeException)
1152 {
1153     vos::OGuard aGuard( Application::GetSolarMutex() );
1154 
1155     if (!bDisposing)
1156     {
1157         bDisposing = sal_True;
1158 
1159         EventObject aEvtObj( (XPropertySet *) this );
1160         aEvtListeners.disposeAndClear( aEvtObj );
1161         aMergeListeners.disposeAndClear( aEvtObj );
1162         aPropListeners.disposeAndClear( aEvtObj );
1163     }
1164 }
1165 
1166 void SAL_CALL SwXMailMerge::addEventListener(
1167         const Reference< XEventListener >& rxListener )
1168     throw(RuntimeException)
1169 {
1170     vos::OGuard aGuard( Application::GetSolarMutex() );
1171     if (!bDisposing && rxListener.is())
1172         aEvtListeners.addInterface( rxListener );
1173 }
1174 
1175 void SAL_CALL SwXMailMerge::removeEventListener(
1176         const Reference< XEventListener >& rxListener )
1177     throw(RuntimeException)
1178 {
1179     vos::OGuard aGuard( Application::GetSolarMutex() );
1180     if (!bDisposing && rxListener.is())
1181         aEvtListeners.removeInterface( rxListener );
1182 }
1183 
1184 void SAL_CALL SwXMailMerge::addMailMergeEventListener(
1185         const uno::Reference< XMailMergeListener >& rxListener )
1186     throw (RuntimeException)
1187 {
1188     vos::OGuard aGuard( Application::GetSolarMutex() );
1189     if (!bDisposing && rxListener.is())
1190         aMergeListeners.addInterface( rxListener );
1191 }
1192 
1193 void SAL_CALL SwXMailMerge::removeMailMergeEventListener(
1194         const uno::Reference< XMailMergeListener >& rxListener )
1195     throw (RuntimeException)
1196 {
1197     vos::OGuard aGuard( Application::GetSolarMutex() );
1198     if (!bDisposing && rxListener.is())
1199         aMergeListeners.removeInterface( rxListener );
1200 }
1201 
1202 OUString SAL_CALL SwXMailMerge::getImplementationName()
1203     throw(RuntimeException)
1204 {
1205     vos::OGuard aGuard( Application::GetSolarMutex() );
1206     return SwXMailMerge_getImplementationName();
1207 }
1208 
1209 sal_Bool SAL_CALL SwXMailMerge::supportsService( const OUString& rServiceName )
1210     throw(RuntimeException)
1211 {
1212     vos::OGuard aGuard( Application::GetSolarMutex() );
1213     return C2U( SN_MAIL_MERGE ) == rServiceName ||
1214            C2U( SN_DATA_ACCESS_DESCRIPTOR ) == rServiceName;
1215 }
1216 
1217 uno::Sequence< OUString > SAL_CALL SwXMailMerge::getSupportedServiceNames()
1218     throw(RuntimeException)
1219 {
1220     vos::OGuard aGuard( Application::GetSolarMutex() );
1221     return SwXMailMerge_getSupportedServiceNames();
1222 }
1223 
1224 ////////////////////////////////////////////////////////////
1225 
1226 uno::Sequence< OUString > SAL_CALL SwXMailMerge_getSupportedServiceNames()
1227     throw()
1228 {
1229     uno::Sequence< OUString > aNames(2);
1230     OUString *pName = aNames.getArray();
1231     pName[0] = C2U( SN_MAIL_MERGE );
1232     pName[1] = C2U( SN_DATA_ACCESS_DESCRIPTOR );
1233     return aNames;
1234 }
1235 
1236 OUString SAL_CALL SwXMailMerge_getImplementationName()
1237     throw()
1238 {
1239     return OUString( C2U( "SwXMailMerge" ) );
1240 }
1241 
1242 uno::Reference< uno::XInterface > SAL_CALL SwXMailMerge_createInstance(
1243         const uno::Reference< XMultiServiceFactory > & /*rSMgr*/)
1244     throw( uno::Exception )
1245 {
1246     vos::OGuard aGuard( Application::GetSolarMutex() );
1247 
1248     //the module may not be loaded
1249 	SwDLL::Init();
1250     uno::Reference< uno::XInterface > xRef = (cppu::OWeakObject *) new SwXMailMerge();
1251     return xRef;
1252 }
1253 
1254