/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2008-2014, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "notifythread.h" namespace Winix { // first thread (objects are locked) NotifyThread::NotifyThread() { patterns_changed = true; } // first thread (objects are locked) void NotifyThread::SetConfig(Config * pconfig) { config = pconfig; } // first thread (objects are locked) void NotifyThread::SetUsers(Users * pusers) { users = pusers; } // first thread (objects are locked) void NotifyThread::SetNotifyPool(NotifyPool * pool) { notify_pool = pool; } // first thread (objects are locked) void NotifyThread::SetPatterns(Patterns * pat) { pat_global = pat; } // first thread (objects are locked) void NotifyThread::PatternsChanged() { patterns_changed = true; } // first thread (objects are locked) bool NotifyThread::Init() { TemplatesNotifyFunctions::CreateFunctions(); return true; } // first thread (objects are locked) bool NotifyThread::SignalReceived() { if( patterns_changed ) { patterns = *pat_global; patterns_changed = false; } return !notify_pool->Empty(); } // second thread (objects are not locked) // return true if there is something to send from the first queue (notify_pool) bool NotifyThread::AddNextNotify() { Users::Iterator i; bool res = false; Lock(); if( !notify_pool->Empty() ) { TemplatesNotifyFunctions::notify_msg = notify_pool->GetFirst(); notify_pool->DeleteFirst(); if( TemplatesNotifyFunctions::notify_msg.code == WINIX_NOTIFY_CODE_CONFIRM_ACCOUNT || TemplatesNotifyFunctions::notify_msg.code == WINIX_NOTIFY_CODE_RESET_PASSWORD ) { msg.email = TemplatesNotifyFunctions::notify_msg.email; msg.name = TemplatesNotifyFunctions::notify_msg.name; msg.lang = TemplatesNotifyFunctions::notify_msg.lang; notify_user.push_back(msg); res = true; } else { for(i=users->Begin() ; i != users->End() ; ++i) { if( (i->notify & TemplatesNotifyFunctions::notify_msg.code) != 0 ) { msg.name = i->name; msg.email = i->email; msg.lang = config->locale_default_id; // !! IMPROVE ME bedzie osobno dla kazdego uzytkownika notify_user.push_back(msg); res = true; } } } } Unlock(); return res; } // second thread -- here we must use Lock() and Unlock() explicitly void NotifyThread::Do() { NotifyUser::iterator i; bool queue_end; while( AddNextNotify() ) { Lock(); i = notify_user.begin(); queue_end = notify_user.empty(); Unlock(); while( !queue_end ) { Lock(); TemplatesNotifyFunctions::notify_user_msg = *i; log << log3 << "NotifyThread: sending notification to: " << i->name << ", email: " << i->email << logend; Unlock(); SendMail(); Lock(); WaitForSignalSleep(2); // automatically unlock and lock again when returns bool stop = synchro->was_stop_signal; Unlock(); if( stop ) return; Lock(); notify_user.erase(i++); queue_end = (i == notify_user.end()); Unlock(); } } } // second thread void NotifyThread::SendMail() { notify_stream.Clear(); size_t lang_id = TemplatesNotifyFunctions::notify_user_msg.lang; size_t template_index = TemplatesNotifyFunctions::notify_msg.template_index; Lock(); // 'patterns' object can use logger or other stuff so we use Lock() before Ezc::Pattern * pat = patterns.Get(template_index, lang_id); if( !pat ) log << log1 << "NotifyThread: I don't have a template with index: " << template_index << " and locale id: " << lang_id << logend; Unlock(); if( pat ) { generator.RecognizeSpecialChars(true); generator.TrimWhite(true); generator.SkipNewLine(true); generator.SetFunctions(TemplatesNotifyFunctions::ezc_functions); generator.SetPattern(*pat); /* * don't use cache * 'pat' pattern is stored in 'patterns' object for all templates and by default * all functions/blocks are cached, but we are in a second thread * and cannot use such functions without locking * * IMPROVE ME * blocks are parsed to the container from the main thread * and we cannot just use it here (another thread) * so may should we have our own 'patterns' object here? * */ generator.CanUseCache(false); generator.Generate(notify_stream); SendMail(TemplatesNotifyFunctions::notify_user_msg.email, notify_stream.Str()); } } // second thread void NotifyThread::SendMail(const std::wstring & email, const std::wstring & message) { nlog << log1 << PT::Date(std::time(0)) << ' '; if( !ValidateEmail(email) ) { nlog << log1 << "NotifyThread: email adress: " << email << " is not correct" << logend; return; } sendmail_command = "sendmail "; PT::WideToUTF8(email, sendmail_command, false); FILE * sendmail = popen(sendmail_command.c_str(), "w"); if( !sendmail ) { nlog << log1 << "NotifyThread: can't run sendmail" << logend; return; } SendMail(sendmail, message); pclose(sendmail); nlog << log1 << "NotifyThread: email to: " << email << " has been sent" << logend << logsave; } // second thread void NotifyThread::SendMail(FILE * sendmail, const std::wstring & message) { char buf[10]; size_t len; for(size_t i=0 ; i