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