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 #include "maildispatcher.hxx" 31 #include "imaildsplistener.hxx" 32 33 #include <algorithm> 34 35 using namespace ::com::sun::star; 36 using ::rtl::OUString; 37 38 typedef std::list< uno::Reference<mail::XMailMessage> > MailMessageContainer_t; 39 typedef std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcherListenerContainer_t; 40 41 namespace /* private */ 42 { 43 /* Generic event notifier for started, 44 stopped, and idle events which are 45 very similary */ 46 class GenericEventNotifier 47 { 48 public: 49 // pointer to virtual function typedef 50 typedef void (IMailDispatcherListener::*GenericNotificationFunc_t)(::rtl::Reference<MailDispatcher>); 51 52 GenericEventNotifier( 53 GenericNotificationFunc_t notification_function, 54 ::rtl::Reference<MailDispatcher> mail_dispatcher) : 55 notification_function_(notification_function), 56 mail_dispatcher_(mail_dispatcher) 57 {} 58 59 void operator() (::rtl::Reference<IMailDispatcherListener> listener) const 60 { (listener.get()->*notification_function_)(mail_dispatcher_); } 61 62 private: 63 GenericNotificationFunc_t notification_function_; 64 ::rtl::Reference<MailDispatcher> mail_dispatcher_; 65 }; 66 67 class MailDeliveryNotifier 68 { 69 public: 70 MailDeliveryNotifier(::rtl::Reference<MailDispatcher> xMailDispatcher, uno::Reference<mail::XMailMessage> message) : 71 mail_dispatcher_(xMailDispatcher), 72 message_(message) 73 {} 74 75 void operator() (::rtl::Reference<IMailDispatcherListener> listener) const 76 { listener->mailDelivered(mail_dispatcher_, message_); } 77 78 private: 79 ::rtl::Reference<MailDispatcher> mail_dispatcher_; 80 uno::Reference<mail::XMailMessage> message_; 81 }; 82 83 class MailDeliveryErrorNotifier 84 { 85 public: 86 MailDeliveryErrorNotifier( 87 ::rtl::Reference<MailDispatcher> xMailDispatcher, 88 uno::Reference<mail::XMailMessage> message, 89 const ::rtl::OUString& error_message) : 90 mail_dispatcher_(xMailDispatcher), 91 message_(message), 92 error_message_(error_message) 93 {} 94 95 void operator() (::rtl::Reference<IMailDispatcherListener> listener) const 96 { listener->mailDeliveryError(mail_dispatcher_, message_, error_message_); } 97 98 private: 99 ::rtl::Reference<MailDispatcher> mail_dispatcher_; 100 uno::Reference<mail::XMailMessage> message_; 101 ::rtl::OUString error_message_; 102 }; 103 104 } // namespace private 105 106 107 MailDispatcher::MailDispatcher(uno::Reference<mail::XSmtpService> mailserver) : 108 mailserver_ (mailserver), 109 run_(false), 110 shutdown_requested_(false) 111 { 112 wakening_call_.reset(); 113 mail_dispatcher_active_.reset(); 114 115 if (!create()) 116 throw uno::RuntimeException(); 117 118 // wait until the mail dispatcher thread is really alive 119 // and has aquired a reference to this instance of the 120 // class 121 mail_dispatcher_active_.wait(); 122 } 123 124 MailDispatcher::~MailDispatcher() 125 { 126 } 127 128 void MailDispatcher::enqueueMailMessage(uno::Reference<mail::XMailMessage> message) 129 { 130 ::osl::MutexGuard thread_status_guard(thread_status_mutex_); 131 ::osl::MutexGuard message_container_guard(message_container_mutex_); 132 133 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); 134 135 messages_.push_back(message); 136 if (run_) 137 wakening_call_.set(); 138 } 139 140 uno::Reference<mail::XMailMessage> MailDispatcher::dequeueMailMessage() 141 { 142 ::osl::MutexGuard guard(message_container_mutex_); 143 uno::Reference<mail::XMailMessage> message; 144 if(!messages_.empty()) 145 { 146 message = messages_.front(); 147 messages_.pop_front(); 148 } 149 return message; 150 } 151 152 void MailDispatcher::start() 153 { 154 OSL_PRECOND(!isStarted(), "MailDispatcher is already started!"); 155 156 ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_); 157 158 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); 159 160 if (!shutdown_requested_) 161 { 162 run_ = true; 163 wakening_call_.set(); 164 thread_status_guard.clear(); 165 166 MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); 167 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::started, this)); 168 } 169 } 170 171 void MailDispatcher::stop() 172 { 173 OSL_PRECOND(isStarted(), "MailDispatcher not started!"); 174 175 ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_); 176 177 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); 178 179 if (!shutdown_requested_) 180 { 181 run_ = false; 182 wakening_call_.reset(); 183 thread_status_guard.clear(); 184 185 MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); 186 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::stopped, this)); 187 } 188 } 189 190 void MailDispatcher::shutdown() 191 { 192 ::osl::MutexGuard thread_status_guard(thread_status_mutex_); 193 194 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); 195 196 shutdown_requested_ = true; 197 wakening_call_.set(); 198 } 199 200 bool MailDispatcher::isStarted() const 201 { 202 return run_; 203 } 204 205 void MailDispatcher::addListener(::rtl::Reference<IMailDispatcherListener> listener) 206 { 207 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); 208 209 ::osl::MutexGuard guard(listener_container_mutex_); 210 listeners_.push_back(listener); 211 } 212 213 void MailDispatcher::removeListener(::rtl::Reference<IMailDispatcherListener> listener) 214 { 215 OSL_PRECOND(!shutdown_requested_, "MailDispatcher thread is shuting down already"); 216 217 ::osl::MutexGuard guard(listener_container_mutex_); 218 listeners_.remove(listener); 219 } 220 221 std::list< ::rtl::Reference<IMailDispatcherListener> > MailDispatcher::cloneListener() 222 { 223 ::osl::MutexGuard guard(listener_container_mutex_); 224 return listeners_; 225 } 226 227 void MailDispatcher::sendMailMessageNotifyListener(uno::Reference<mail::XMailMessage> message) 228 { 229 try 230 { 231 mailserver_->sendMailMessage(message); 232 MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); 233 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryNotifier(this, message)); 234 } 235 catch (mail::MailException& ex) 236 { 237 MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); 238 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message)); 239 } 240 catch (uno::RuntimeException& ex) 241 { 242 MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); 243 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), MailDeliveryErrorNotifier(this, message, ex.Message)); 244 } 245 } 246 247 void MailDispatcher::run() 248 { 249 // aquire a self reference in order to avoid race 250 // conditions. The last client of this class must 251 // call shutdown before releasing his last reference 252 // to this class in order to shutdown this thread 253 // which will release his (the very last reference 254 // to the class and so force their destruction 255 m_xSelfReference = this; 256 257 // signal that the mail dispatcher thread is now alive 258 mail_dispatcher_active_.set(); 259 260 for(;;) 261 { 262 wakening_call_.wait(); 263 264 ::osl::ClearableMutexGuard thread_status_guard(thread_status_mutex_); 265 if (shutdown_requested_) 266 break; 267 268 ::osl::ClearableMutexGuard message_container_guard(message_container_mutex_); 269 270 if (messages_.size()) 271 { 272 thread_status_guard.clear(); 273 uno::Reference<mail::XMailMessage> message = messages_.front(); 274 messages_.pop_front(); 275 message_container_guard.clear(); 276 sendMailMessageNotifyListener(message); 277 } 278 else // idle - put ourself to sleep 279 { 280 wakening_call_.reset(); 281 message_container_guard.clear(); 282 thread_status_guard.clear(); 283 MailDispatcherListenerContainer_t listeners_cloned(cloneListener()); 284 std::for_each(listeners_cloned.begin(), listeners_cloned.end(), GenericEventNotifier(&IMailDispatcherListener::idle, this)); 285 } 286 } // end for SSH ALI 287 } 288 /*-- 27.08.2004 12:04:46--------------------------------------------------- 289 290 -----------------------------------------------------------------------*/ 291 void MailDispatcher::onTerminated() 292 { 293 //keep the reference until the end of onTerminated() because of the call order in the 294 //_threadFunc() from osl/thread.hxx 295 m_xSelfReference = 0; 296 } 297