LibreOffice Module sw (master) 1
mmoutputtypepage.cxx
Go to the documentation of this file.
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 "mmoutputtypepage.hxx"
21#include <mailmergewizard.hxx>
22#include <mmconfigitem.hxx>
23#include <strings.hrc>
24#include <bitmaps.hlst>
25#include <swtypes.hxx>
26
27#include <osl/diagnose.h>
28#include <rtl/ref.hxx>
29#include <com/sun/star/mail/XSmtpService.hpp>
30#include <vcl/idle.hxx>
31#include <vcl/svapp.hxx>
32#include <vcl/weld.hxx>
33
34#include <swunohelper.hxx>
35#include <mmresultdialogs.hxx>
36#include <maildispatcher.hxx>
37#include <imaildsplistener.hxx>
38#include <mutex>
39
40using namespace ::com::sun::star;
41
43 : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmoutputtypepage.ui", "MMOutputTypePage")
44 , m_pWizard(pWizard)
45 , m_xLetterRB(m_xBuilder->weld_radio_button("letter"))
46 , m_xMailRB(m_xBuilder->weld_radio_button("email"))
47 , m_xLetterHint(m_xBuilder->weld_label("letterft"))
48 , m_xMailHint(m_xBuilder->weld_label("emailft"))
49{
51 m_xLetterRB->connect_toggled(aLink);
52 m_xMailRB->connect_toggled(aLink);
53
55 if(rConfigItem.IsOutputToLetter())
56 m_xLetterRB->set_active(true);
57 else
58 m_xMailRB->set_active(true);
59 TypeHdl_Impl(*m_xLetterRB);
60}
61
63{
64}
65
67{
68 bool bLetter = m_xLetterRB->get_active();
69 m_xLetterHint->set_visible(bLetter);
70 m_xMailHint->set_visible(!bLetter);
71 m_pWizard->GetConfigItem().SetOutputToLetter(bLetter);
72 m_pWizard->UpdateRoadmap();
73}
74
76{
77 friend class SwSendMailDialog;
78 // The mutex is locked in SwSendMailDialog_Impl::GetNextDescriptor, which may be called
79 // both with mutex unlocked (inside SwSendMailDialog::SendMails), and with mutex locked
80 // (inside SwSendMailDialog::AddDocument).
81 std::recursive_mutex aDescriptorMutex;
82
83 std::vector< SwMailDescriptor > aDescriptors;
87 uno::Reference< mail::XMailService > xConnectedInMailService;
89
91 nCurrentDescriptor(0), aRemoveIdle("SwSendMailDialog_Impl aRemoveIdle")
92 {
93 aRemoveIdle.SetPriority(TaskPriority::LOWEST);
94 }
95
97 {
98 // Shutdown must be called when the last reference to the
99 // mail dispatcher will be released in order to force a
100 // shutdown of the mail dispatcher thread.
101 // 'join' with the mail dispatcher thread leads to a
102 // deadlock (SolarMutex).
103 if( xMailDispatcher.is() && !xMailDispatcher->isShutdownRequested() )
104 xMailDispatcher->shutdown();
105 }
107};
108
110{
111 std::scoped_lock aGuard(aDescriptorMutex);
113 {
115 return &aDescriptors[nCurrentDescriptor - 1];
116 }
117 return nullptr;
118}
119
120namespace {
121
122class SwMailDispatcherListener_Impl : public IMailDispatcherListener
123{
124 SwSendMailDialog& m_rSendMailDialog;
125
126public:
127 explicit SwMailDispatcherListener_Impl(SwSendMailDialog& rParentDlg);
128
129 virtual void idle() override;
130 virtual void mailDelivered(uno::Reference< mail::XMailMessage> xMailMessage) override;
131 virtual void mailDeliveryError(::rtl::Reference<MailDispatcher> xMailDispatcher,
132 uno::Reference< mail::XMailMessage> xMailMessage, const OUString& sErrorMessage) override;
133
134 static void DeleteAttachments( uno::Reference< mail::XMailMessage > const & xMessage );
135};
136
137}
138
139SwMailDispatcherListener_Impl::SwMailDispatcherListener_Impl(SwSendMailDialog& rParentDlg)
140 : m_rSendMailDialog(rParentDlg)
141{
142}
143
144void SwMailDispatcherListener_Impl::idle()
145{
146 SolarMutexGuard aGuard;
147 m_rSendMailDialog.AllMailsSent();
148}
149
150void SwMailDispatcherListener_Impl::mailDelivered(
151 uno::Reference< mail::XMailMessage> xMailMessage)
152{
153 SolarMutexGuard aGuard;
154 m_rSendMailDialog.DocumentSent( xMailMessage, true, nullptr );
155 DeleteAttachments( xMailMessage );
156}
157
158void SwMailDispatcherListener_Impl::mailDeliveryError(
159 ::rtl::Reference<MailDispatcher> /*xMailDispatcher*/,
160 uno::Reference< mail::XMailMessage> xMailMessage,
161 const OUString& sErrorMessage)
162{
163 SolarMutexGuard aGuard;
164 m_rSendMailDialog.DocumentSent( xMailMessage, false, &sErrorMessage );
165 DeleteAttachments( xMailMessage );
166}
167
168void SwMailDispatcherListener_Impl::DeleteAttachments( uno::Reference< mail::XMailMessage > const & xMessage )
169{
170 const uno::Sequence< mail::MailAttachment > aAttachments = xMessage->getAttachments();
171
172 for(const auto& rAttachment : aAttachments)
173 {
174 try
175 {
176 uno::Reference< beans::XPropertySet > xTransferableProperties( rAttachment.Data, uno::UNO_QUERY_THROW);
177 OUString sURL;
178 xTransferableProperties->getPropertyValue("URL") >>= sURL;
179 if(!sURL.isEmpty())
181 }
182 catch (const uno::Exception&)
183 {
184 }
185 }
186}
187
188namespace {
189
190class SwSendWarningBox_Impl : public weld::MessageDialogController
191{
192 std::unique_ptr<weld::TextView> m_xDetailED;
193public:
194 SwSendWarningBox_Impl(weld::Window* pParent, const OUString& rDetails)
195 : MessageDialogController(pParent, "modules/swriter/ui/warnemaildialog.ui", "WarnEmailDialog", "grid")
196 , m_xDetailED(m_xBuilder->weld_text_view("errors"))
197 {
198 m_xDetailED->set_size_request(80 * m_xDetailED->get_approximate_digit_width(),
199 8 * m_xDetailED->get_text_height());
200 m_xDetailED->set_text(rDetails);
201 }
202};
203
204}
205
207 : GenericDialogController(pParent, "modules/swriter/ui/mmsendmails.ui", "SendMailsDialog")
208 , m_sContinue(SwResId( ST_CONTINUE ))
209 , m_sClose(SwResId(ST_CLOSE_DIALOG))
210 , m_sSendingTo( SwResId(ST_SENDINGTO ))
211 , m_sCompleted( SwResId(ST_COMPLETED ))
212 , m_sFailed( SwResId(ST_FAILED ))
213 , m_sAddressInvalid(SwResId(ST_ADDRESS_INVALID))
214 , m_bCancel(false)
215 , m_bDestructionEnabled(false)
217 , m_pConfigItem(&rConfigItem)
218 , m_nExpectedCount(0)
219 , m_nProcessedCount(0)
220 , m_nErrorCount(0)
221 , m_xTransferStatus(m_xBuilder->weld_label("transferstatus"))
222 , m_xPaused(m_xBuilder->weld_label("paused"))
223 , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
224 , m_xErrorStatus(m_xBuilder->weld_label("errorstatus"))
225 , m_xStatus(m_xBuilder->weld_tree_view("container"))
226 , m_xStop(m_xBuilder->weld_button("stop"))
227 , m_xCancel(m_xBuilder->weld_button("cancel"))
228{
229 m_sStop = m_xStop->get_label();
231 m_sErrorStatus = m_xErrorStatus->get_label();
232
233 Size aSize(m_xStatus->get_approximate_digit_width() * 28,
234 m_xStatus->get_height_rows(20));
235 m_xStatus->set_size_request(aSize.Width(), aSize.Height());
236
237 m_xStop->connect_clicked(LINK( this, SwSendMailDialog, StopHdl_Impl));
238 m_xCancel->connect_clicked(LINK( this, SwSendMailDialog, CancelHdl_Impl));
239
240 std::vector<int> aWidths
241 {
242 o3tl::narrowing<int>(m_xStatus->get_checkbox_column_width()),
243 o3tl::narrowing<int>(aSize.Width()/3 * 2)
244 };
245 m_xStatus->set_column_fixed_widths(aWidths);
246
247 m_xPaused->set_visible(false);
249}
250
252{
253 if(!m_pImpl->xMailDispatcher.is())
254 return;
255
256 try
257 {
258 if(m_pImpl->xMailDispatcher->isStarted())
259 m_pImpl->xMailDispatcher->stop();
260 if(m_pImpl->xConnectedInMailService.is() && m_pImpl->xConnectedInMailService->isConnected())
261 m_pImpl->xConnectedInMailService->disconnect();
262
263 uno::Reference<mail::XMailMessage> xMessage =
264 m_pImpl->xMailDispatcher->dequeueMailMessage();
265 while(xMessage.is())
266 {
267 SwMailDispatcherListener_Impl::DeleteAttachments( xMessage );
268 xMessage = m_pImpl->xMailDispatcher->dequeueMailMessage();
269 }
270 }
271 catch (const uno::Exception&)
272 {
273 }
274}
275
277{
278 std::scoped_lock aGuard(m_pImpl->aDescriptorMutex);
279 m_pImpl->aDescriptors.push_back(rDesc);
280 // if the dialog is already running then continue sending of documents
281 if(m_pImpl->xMailDispatcher.is())
282 {
283 IterateMails();
284 }
285}
286
287IMPL_LINK( SwSendMailDialog, StopHdl_Impl, weld::Button&, rButton, void )
288{
289 m_bCancel = true;
290 if(!m_pImpl->xMailDispatcher.is())
291 return;
292
293 if(m_pImpl->xMailDispatcher->isStarted())
294 {
295 m_pImpl->xMailDispatcher->stop();
296 rButton.set_label(m_sContinue);
297 m_xPaused->show();
298 }
299 else
300 {
301 m_pImpl->xMailDispatcher->start();
302 rButton.set_label(m_sStop);
303 m_xPaused->hide();
304 }
305}
306
308{
309 m_xDialog->hide();
310
311 if (m_bDestructionEnabled)
312 m_xDialog->response(RET_CANCEL);
313 else
314 {
315 m_pImpl->aRemoveIdle.SetInvokeHandler( LINK( this, SwSendMailDialog, RemoveThis ) );
316 m_pImpl->aRemoveIdle.Start();
317 }
318}
319
320IMPL_STATIC_LINK( SwSendMailDialog, StartSendMails, void*, pDialog, void )
321{
322 static_cast<SwSendMailDialog*>(pDialog)->SendMails();
323}
324
325IMPL_LINK( SwSendMailDialog, RemoveThis, Timer*, pTimer, void )
326{
327 if( m_pImpl->xMailDispatcher.is() )
328 {
329 if(m_pImpl->xMailDispatcher->isStarted())
330 m_pImpl->xMailDispatcher->stop();
331 if(!m_pImpl->xMailDispatcher->isShutdownRequested())
332 m_pImpl->xMailDispatcher->shutdown();
333 }
334
335 if( m_bDestructionEnabled &&
336 (!m_pImpl->xMailDispatcher.is() ||
337 !m_pImpl->xMailDispatcher->isRunning()))
338 {
339 m_xDialog->response(RET_CANCEL);
340 }
341 else
342 {
343 pTimer->Start();
344 }
345}
346
347IMPL_STATIC_LINK( SwSendMailDialog, StopSendMails, void*, p, void )
348{
349 SwSendMailDialog* pDialog = static_cast<SwSendMailDialog*>(p);
350 if(pDialog->m_pImpl->xMailDispatcher.is() &&
351 pDialog->m_pImpl->xMailDispatcher->isStarted())
352 {
353 pDialog->m_pImpl->xMailDispatcher->stop();
354 pDialog->m_xStop->set_label(pDialog->m_sContinue);
355 pDialog->m_xPaused->show();
356 }
357}
358
360{
361 if(!m_pConfigItem)
362 {
363 OSL_FAIL("config item not set");
364 return;
365 }
366 auto xWait(std::make_unique<weld::WaitObject>(m_xDialog.get()));
367 //get a mail server connection
368 uno::Reference< mail::XSmtpService > xSmtpServer =
370 m_pImpl->xConnectedInMailService,
371 OUString(), OUString(), m_xDialog.get());
372 bool bIsLoggedIn = xSmtpServer.is() && xSmtpServer->isConnected();
373 xWait.reset();
374 if(!bIsLoggedIn)
375 {
376 OSL_FAIL("create error message");
377 return;
378 }
379 m_pImpl->xMailDispatcher.set( new MailDispatcher(xSmtpServer));
380 IterateMails();
381 m_pImpl->xMailListener = new SwMailDispatcherListener_Impl(*this);
382 m_pImpl->xMailDispatcher->addListener(m_pImpl->xMailListener);
383 if(!m_bCancel)
384 {
385 m_pImpl->xMailDispatcher->start();
386 }
387}
388
390{
391 const SwMailDescriptor* pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
392 while( pCurrentMailDescriptor )
393 {
394 if (!SwMailMergeHelper::CheckMailAddress( pCurrentMailDescriptor->sEMail))
395 {
396 OUString sMessage = m_sSendingTo;
397 m_xStatus->append();
398 m_xStatus->set_image(m_nProcessedCount, RID_BMP_FORMULA_CANCEL, 0);
399 m_xStatus->set_text(m_nProcessedCount, sMessage.replaceFirst("%1", pCurrentMailDescriptor->sEMail), 1);
404 pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
405 continue;
406 }
409 pMessage->setReplyToAddress(m_pConfigItem->GetMailReplyTo());
410 pMessage->addRecipient( pCurrentMailDescriptor->sEMail );
411 pMessage->SetSenderName( m_pConfigItem->GetMailDisplayName() );
412 pMessage->SetSenderAddress( m_pConfigItem->GetMailAddress() );
413 if(!pCurrentMailDescriptor->sAttachmentURL.isEmpty())
414 {
415 mail::MailAttachment aAttach;
416 aAttach.Data =
418 pCurrentMailDescriptor->sAttachmentURL,
419 pCurrentMailDescriptor->sAttachmentName,
420 pCurrentMailDescriptor->sMimeType );
421 aAttach.ReadableName = pCurrentMailDescriptor->sAttachmentName;
422 pMessage->addAttachment( aAttach );
423 }
424 pMessage->setSubject( pCurrentMailDescriptor->sSubject );
425 uno::Reference< datatransfer::XTransferable> xBody =
427 pCurrentMailDescriptor->sBodyContent,
428 pCurrentMailDescriptor->sBodyMimeType);
429 pMessage->setBody( xBody );
430
431 //CC and BCC are tokenized by ';'
432 if(!pCurrentMailDescriptor->sCC.isEmpty())
433 {
434 sal_Int32 nPos = 0;
435 do
436 {
437 OUString sTmp = pCurrentMailDescriptor->sCC.getToken( 0, ';', nPos );
438 if( !sTmp.isEmpty() )
439 pMessage->addCcRecipient( sTmp );
440 }
441 while (nPos >= 0);
442 }
443 if(!pCurrentMailDescriptor->sBCC.isEmpty())
444 {
445 sal_Int32 nPos = 0;
446 do
447 {
448 OUString sTmp = pCurrentMailDescriptor->sBCC.getToken( 0, ';', nPos );
449 if( !sTmp.isEmpty() )
450 pMessage->addBccRecipient( sTmp );
451 }
452 while (nPos >= 0);
453 }
454 m_pImpl->xMailDispatcher->enqueueMailMessage( pMessage );
455 pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
456 }
458}
459
460void SwSendMailDialog::StartSend(sal_Int32 nExpectedCount)
461{
463 StartSendMails ), this );
464 m_nExpectedCount = nExpectedCount > 0 ? nExpectedCount : 1;
465}
466
467void SwSendMailDialog::DocumentSent( uno::Reference< mail::XMailMessage> const & xMessage,
468 bool bResult,
469 const OUString* pError )
470{
471 //sending should stop on send errors, except after last error - it will stop in AllMailsSent
472 if (pError && m_nProcessedCount + 1 < m_nExpectedCount &&
473 m_pImpl->xMailDispatcher.is() && m_pImpl->xMailDispatcher->isStarted())
474 {
476 StopSendMails ), this );
477 }
478 OUString sInsertImg(bResult ? OUString(RID_BMP_FORMULA_APPLY) : OUString(RID_BMP_FORMULA_CANCEL));
479
480 OUString sMessage = m_sSendingTo;
481 m_xStatus->append();
482 m_xStatus->set_image(m_nProcessedCount, sInsertImg, 0);
483 m_xStatus->set_text(m_nProcessedCount, sMessage.replaceFirst("%1", xMessage->getRecipients()[0]), 1);
484 m_xStatus->set_text(m_nProcessedCount, bResult ? m_sCompleted : m_sFailed, 2);
486 if(!bResult)
488
490
491 if (pError)
492 {
493 SwSendWarningBox_Impl aDlg(m_xDialog.get(), *pError);
494 aDlg.run();
495 }
496}
497
499{
500 OUString sStatus( m_sTransferStatus );
501 sStatus = sStatus.replaceFirst("%1", OUString::number(m_nProcessedCount) );
502 sStatus = sStatus.replaceFirst("%2", OUString::number(m_nExpectedCount));
503 m_xTransferStatus->set_label(sStatus);
504
505 sStatus = m_sErrorStatus.replaceFirst("%1", OUString::number(m_nErrorCount) );
506 m_xErrorStatus->set_label(sStatus);
507
508 if (!m_pImpl->aDescriptors.empty())
509 {
510 assert(m_nExpectedCount && "div-by-zero");
511 m_xProgressBar->set_percentage(m_nProcessedCount * 100 / m_nExpectedCount);
512 }
513 else
514 m_xProgressBar->set_percentage(0);
515}
516
518{
520 {
521 m_xStop->set_sensitive(false);
522 m_xCancel->set_label(m_sClose);
523 // Leave open if some kind of error occurred
524 if (m_nErrorCount == 0)
525 {
526 m_xDialog->hide();
527 m_xDialog->response(RET_CANCEL);
528 }
529 }
530}
531
532/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
Reference< XExecutableDialog > m_xDialog
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
MailDispatcher listener interface.
A MailDispatcher should be used for sending a bunch a mail messages asynchronously.
constexpr tools::Long Height() const
constexpr tools::Long Width() const
OUString const & GetMailAddress() const
OUString const & GetMailDisplayName() const
bool IsMailReplyTo() const
OUString const & GetMailReplyTo() const
bool IsOutputToLetter() const
SwMailMergeOutputTypePage(weld::Container *pPage, SwMailMergeWizard *pWizard)
virtual ~SwMailMergeOutputTypePage() override
std::unique_ptr< weld::RadioButton > m_xLetterRB
std::unique_ptr< weld::RadioButton > m_xMailRB
SwMailMergeWizard * m_pWizard
SwMailMergeConfigItem & GetConfigItem()
void StartSend(sal_Int32 nExpectedCount)
SwMailMergeConfigItem * m_pConfigItem
std::unique_ptr< weld::Label > m_xPaused
std::unique_ptr< weld::Label > m_xTransferStatus
std::unique_ptr< SwSendMailDialog_Impl > m_pImpl
void AddDocument(SwMailDescriptor const &rDesc)
SwSendMailDialog(weld::Window *pParent, SwMailMergeConfigItem &)
std::unique_ptr< weld::TreeView > m_xStatus
std::unique_ptr< weld::ProgressBar > m_xProgressBar
sal_Int32 m_nProcessedCount
void DocumentSent(css::uno::Reference< css::mail::XMailMessage > const &xMessage, bool bResult, const OUString *pError)
std::unique_ptr< weld::Button > m_xCancel
std::unique_ptr< weld::Label > m_xErrorStatus
virtual ~SwSendMailDialog() override
std::unique_ptr< weld::Button > m_xStop
sal_Int32 m_nExpectedCount
void SetPriority(TaskPriority ePriority)
std::shared_ptr< weld::Dialog > m_xDialog
void * p
sal_uInt16 nPos
IMPL_LINK_NOARG(SwMailMergeOutputTypePage, TypeHdl_Impl, weld::Toggleable &, void)
IMPL_STATIC_LINK(SwSendMailDialog, StartSendMails, void *, pDialog, void)
IMPL_LINK(SwSendMailDialog, StopHdl_Impl, weld::Button &, rButton, void)
bool UCB_DeleteFile(const OUString &rURL)
Definition: swunohelper.cxx:59
uno::Reference< mail::XSmtpService > ConnectToSmtpServer(SwMailMergeConfigItem const &rConfigItem, uno::Reference< mail::XMailService > &rxInMailService, const OUString &rInMailServerPassword, const OUString &rOutMailServerPassword, weld::Window *pDialogParentWindow)
bool CheckMailAddress(std::u16string_view aMailAddress)
OUString sMessage
std::recursive_mutex aDescriptorMutex
uno::Reference< mail::XMailService > xConnectedInMailService
::rtl::Reference< MailDispatcher > xMailDispatcher
std::vector< SwMailDescriptor > aDescriptors
const SwMailDescriptor * GetNextDescriptor()
::rtl::Reference< IMailDispatcherListener > xMailListener
OUString SwResId(TranslateId aId)
Definition: swmodule.cxx:168
RET_CANCEL