winix/core/notify.cpp

316 lines
5.1 KiB
C++
Executable File

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2008-2010, Tomasz Sowa
* All rights reserved.
*
*/
#include <pthread.h>
#include <unistd.h>
#include "log.h"
#include "notify.h"
#include "misc.h"
#include "request.h"
#include "utf8.h"
// the second thread uses this pointer to reference to 'this'
// (methods for the thread should be static)
Notify * Notify::obj;
void Notify::SetRequest(Request * prequest)
{
request = prequest;
}
void Notify::SetConfig(Config * pconfig)
{
config = pconfig;
}
void Notify::SetSystem(System * psystem)
{
system = psystem;
}
void Notify::SetTemplatesNotify(TemplatesNotify * ptemplates_notify)
{
templates_notify = ptemplates_notify;
}
/*
methods for the second thread
the thread can reference to 'this' by using 'obj' pointer
*/
void * Notify::ThreadRoutine(void * arg)
{
obj = (Notify*)arg;
while( true )
{
CheckQueue();
sleep(30);
}
}
void Notify::CheckQueue()
{
std::list<NotifyMsg>::iterator i = obj->notify_pool.begin();
while( i != obj->notify_pool.end() )
{
SendEmail(*i);
obj->Lock();
i = obj->notify_pool.erase(i);
obj->Unlock();
sleep(3);
}
}
void Notify::SendEmail(NotifyMsg & n)
{
TemplatesNotifyFunctions::notify_msg = &n;
obj->Lock(); // templates can be reloaded from the first thread
obj->templates_notify->Generate(n.lang);
obj->Unlock();
SendEmail(n.email, obj->templates_notify->notify_str.Str());
}
void Notify::SendEmail(const std::wstring & email, const std::wstring & message)
{
nlog.PutDate(log1);
if( !ValidateEmail(email) )
{
nlog << log1 << "Notify: email: " << email << " is not correct" << logend;
return;
}
obj->command = "sendmail ";
AssignString(email, obj->command, false);
FILE * sendmail = popen(obj->command.c_str(), "w");
if( !sendmail )
{
nlog << log1 << "Notify: can't run sendmail" << logend;
return;
}
SendMessage(sendmail, message);
pclose(sendmail);
nlog << log1 << "Notify: email to: " << email << " has been sent" << logend;
nlog << logsave;
}
void Notify::SendMessage(FILE * sendmail, const std::wstring & message)
{
char buf[10];
size_t len;
for(size_t i=0 ; i<message.length() ; ++i)
{
if( message[i] == '\n' )
{
fprintf(sendmail, "\r\n");
}
else
{
len = Ezc::IntToUTF8(int(message[i]), buf, sizeof(buf));
for(size_t a=0 ; a<len ; ++a)
fputc(buf[a], sendmail);
}
}
}
/*
methods for main thread
*/
Notify::Notify() : mutex(PTHREAD_MUTEX_INITIALIZER)
{
}
Notify::~Notify()
{
}
void Notify::ReadTemplates()
{
// we are in the first thread here
// the second thread can use our templates and we must Lock()
// (the second thread is using Lock() too)
Lock();
templates_notify->Read();
Unlock();
}
bool Notify::Init()
{
templates_notify->CreateFunctions();
// CreateFunctions() should be called before ReadTemplates()
// because the patterns will cache the functions
ReadTemplates();
int t = pthread_create(&thread, 0, ThreadRoutine, (void*)this);
if( t != 0 )
{
// log (not nlog) here
log << log1 << "Notify: can't create a thread" << logend;
return false;
}
return true;
}
bool Notify::Lock()
{
if( pthread_mutex_lock(&mutex) != 0 )
return false;
return true;
}
void Notify::Unlock()
{
pthread_mutex_unlock(&mutex);
}
void Notify::CreateItemDir(std::wstring & dir, bool clear)
{
if( clear )
dir.clear();
for(size_t a=0 ; a<request->dir_tab.size() ; ++a)
{
dir += request->dir_tab[a]->url;
dir += '/';
}
}
void Notify::CreateItemLink(std::wstring & link)
{
link = config->base_url;
CreateItemDir(link, false);
link += request->item.url;
}
void Notify::ItemChanged(int notify_code)
{
bool sending;
Users::Iterator i;
if( notify_code == 0 )
return;
if( !system || !system->mounts.pmount || !config )
{
// !! system->mounts.pmount byl czasami null
// !! kiedy dodawana byla funkcja "vim"
log << log1 << "!!! Notify: some objects are not set: "
<< system << ", "
<< system->mounts.pmount << ", "
<< config << logend;
return;
}
n.notify_code = notify_code;
n.current_mount_type = system->mounts.pmount->type;
n.doc_base_url = config->base_url;
CreateItemDir(n.item_dir);
CreateItemLink(n.item_link);
Lock();
try
{
// don't clear notify_pool here -- it is used (and will be cleared) by the second thread
for(i=system->users.Begin() ; i != system->users.End() ; ++i)
{
sending = false;
if( system->mounts.pmount->type == system->mounts.MountTypeThread() )
//system->mounts.pmount->type == system->mounts.MountTypeTicket() )
{
if( (i->thread_notify & notify_code) != 0 )
sending = true;
}
else
if( system->mounts.pmount->type == system->mounts.MountTypeCms() )
{
if( (i->cms_notify & notify_code) != 0 )
sending = true;
}
if( sending )
{
n.email = i->email;
n.lang = Locale::StrToLang(config->locale_str);// !! bedzie osobno dla kazdego uzytkownika
if( n.lang == Locale::lang_unknown )
n.lang = Locale::lang_en;
notify_pool.insert(notify_pool.end(), n);
}
}
}
catch(...)
{
Unlock();
throw;
}
Unlock();
}