diff options
author | Christian Wieninger <winni@debian.(none)> | 2007-11-11 15:40:28 +0100 |
---|---|---|
committer | Christian Wieninger <winni@debian.(none)> | 2007-11-11 15:40:28 +0100 |
commit | 8d4f8607dc1558ce73eb4c376bdbf78ddb65da83 (patch) | |
tree | d0c5dde81a36ab2e8a2edc7c1e6922556518b312 /mail.c | |
download | vdr-plugin-epgsearch-8d4f8607dc1558ce73eb4c376bdbf78ddb65da83.tar.gz vdr-plugin-epgsearch-8d4f8607dc1558ce73eb4c376bdbf78ddb65da83.tar.bz2 |
Initial commit
Diffstat (limited to 'mail.c')
-rw-r--r-- | mail.c | 459 |
1 files changed, 459 insertions, 0 deletions
@@ -0,0 +1,459 @@ +/* +Copyright (C) 2004-2007 Christian Wieninger + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + +The author can be reached at cwieninger@gmx.de + +The project's page is at http://winni.vdr-developer.org/epgsearch +*/ + +#include <sstream> +#include <iomanip> +#include <fstream> + +#include "mail.h" +#include "epgsearchcfg.h" +#include "log.h" +#include "epgsearchtools.h" +#include "uservars.h" + +using namespace std; + +string cMailNotifier::MailCmd = "sendEmail.pl"; + +// ---------------------- +// cMailTimerNotification +string cMailTimerNotification::Format(const string& templ) const +{ + const cEvent* pEvent = GetEvent(); + if (!pEvent) return ""; + + int TimerMatch = tmNone; + cTimer* pTimer = Timers.GetMatch(pEvent, &TimerMatch); + if (!pTimer) return ""; + + string result = templ; + cVarExpr varExprEvent(result); + result = varExprEvent.Evaluate(pEvent); + cVarExpr varExprTimer(result); + result = varExprTimer.Evaluate(pTimer); + + return result; +} + +const cEvent* cMailTimerNotification::GetEvent() const +{ + cSchedulesLock schedulesLock; + const cSchedules *schedules = cSchedules::Schedules(schedulesLock); + if (!schedules) return NULL; + const cSchedule *schedule = schedules->GetSchedule(channelID); + if (!schedule) return NULL; + return schedule->GetEvent(eventID); +} + +bool cMailTimerNotification::operator< (const cMailTimerNotification &N) const +{ + const cChannel* channel = Channels.GetByChannelID(channelID,true,true); + const cChannel* channelOther = Channels.GetByChannelID(N.channelID,true,true); + if (!channel || !channelOther) + return false; + const cEvent* event = GetEvent(); + const cEvent* eventOther = N.GetEvent(); + if (event && eventOther) // sort event by start time and channel + if (event->StartTime() == eventOther->StartTime()) + return channel->Number() < channelOther->Number(); + else + return event->StartTime() < eventOther->StartTime(); + return false; +} + +// ------------------------- +// cMailDelTimerNotification +cMailDelTimerNotification::cMailDelTimerNotification(cTimer* pTimer, const cEvent* pEvent, const string& templ) +{ + if (!pTimer || !pTimer->Channel()) return; + + channelID = pTimer->Channel()->GetChannelID(); + start = pTimer->StartTime(); + + string result = templ; + cVarExpr varExprEvent(result); + result = varExprEvent.Evaluate(pEvent); + cVarExpr varExprTimer(result); + formatted = varExprTimer.Evaluate(pTimer); +} + +bool cMailDelTimerNotification::operator< (const cMailDelTimerNotification &N) const +{ + const cChannel* channel = Channels.GetByChannelID(channelID,true,true); + const cChannel* channelOther = Channels.GetByChannelID(N.channelID,true,true); + if (!channel || !channelOther) + return false; + if (channel != channelOther) + return channel->Number() < channelOther->Number(); + else + return (start < N.start); +} + +// ------------- +// cMailNotifier +cMailNotifier::cMailNotifier(string Subject, string Body) +: subject(Subject), body(Body) +{ + SendMail(); +} + +bool cMailNotifier::SendMailViaSendmail() +{ + char mailcmd[256]; + const char* mailargs = "%s -i -FVDR -oem %s"; + const char* mailproc = "/usr/lib/sendmail"; + FILE* mail; + + string to = EPGSearchConfig.MailAddressTo; + snprintf(mailcmd, sizeof(mailcmd), mailargs, mailproc, to.c_str()); + + if (!(mail = popen(mailcmd, "w"))) { + return false; + } + + fprintf(mail, "From: VDR\n"); + fprintf(mail, "To: %s\n", to.c_str()); + fprintf(mail, "Subject: %s\n", subject.c_str()); + if (FindIgnoreCase(body, "<html>") >= 0) + fprintf(mail, "Content-Type: text/html; charset=ISO-8859-15\n"); + else + fprintf(mail, "Content-Type: text/plain; charset=ISO-8859-15\n"); + + fprintf(mail, "\n"); + + fprintf(mail, "%s", body.c_str()); + + pclose(mail); + + return true; +} + +bool cMailNotifier::SendMailViaScript() +{ + // create a temporary file for the message body + string filename = *AddDirectory(CONFIGDIR, "epgsearchmail.temp"); + std::ofstream bodyfile(filename.c_str()); + if (!bodyfile) + { + LogFile.eSysLog("error opening file %s", filename.c_str()); + return false; + } + bodyfile << body; + bodyfile.close(); + + string AuthUser = EPGSearchConfig.MailAuthUser; + string AuthPass = EPGSearchConfig.MailAuthPass; + string cmdArgs = + string(" -f \"VDR <") + EPGSearchConfig.MailAddress + ">\"" + + " -t " + EPGSearchConfig.MailAddressTo + + " -s " + EPGSearchConfig.MailServer + + " -u \"" + subject + "\""+ + (EPGSearchConfig.MailUseAuth? + (AuthUser != "" ?(" -xu " + AuthUser):"") + + (AuthPass != "" ?(" -xp " + AuthPass):"") + :"") + + " -o message-file=" + filename; + + bool success = ExecuteMailScript(cmdArgs); + + if (remove(filename.c_str()) != 0) + LogFile.eSysLog("error deleting file %s", filename.c_str()); + + return success; +} + +bool cMailNotifier::SendMail() +{ + if (!EPGSearchConfig.mailViaScript) + return SendMailViaSendmail(); + else + return SendMailViaScript(); +} + +bool cMailNotifier::ExecuteMailScript(string ScriptArgs) +{ + string mailCmd = MailCmd; + if (mailCmd == "sendEmail.pl") // beautify output for standard script + ScriptArgs += " | cut -d\" \" -f 6-"; + + cCommand cmd; + string fullcmd = "mailcmd: " + mailCmd; + if (!cmd.Parse(fullcmd.c_str())) + { + LogFile.eSysLog("error parsing cmd: %s", MailCmd.c_str()); + return false; + } + const char* res = cmd.Execute(ScriptArgs.c_str()); + scriptReply = res?res:""; + if (scriptReply != "") + LogFile.iSysLog("mail cmd result: %s", scriptReply.c_str()); + + return true; +} + +bool cMailNotifier::TestMailAccount(string MailAddressTo, string MailAddress, string MailServer, string AuthUser, string AuthPass) +{ + string cmdArgs = + string("-v -f \"VDR <") + MailAddress + ">\"" + + " -t " + MailAddressTo + + " -s " + MailServer + + " -u \"VDR-Testmail\"" + + (AuthUser != "" ?(" -xu " + AuthUser):"") + + (AuthPass != "" ?(" -xp " + AuthPass):"") + + " -m \"Success! ;-)\""; + + return ExecuteMailScript(cmdArgs); +} + +string cMailNotifier::LoadTemplate(const string& templtype) +{ + string filename = *AddDirectory(CONFIGDIR, templtype.c_str()); + string templ = ""; + if (filename != "" && access(filename.c_str(), F_OK) == 0) + { + LogFile.iSysLog("loading %s", filename.c_str()); + FILE *f = fopen(filename.c_str(), "r"); + if (f) + { + templ = ""; + char *s; + cReadLine ReadLine; + while ((s = ReadLine.Read(f)) != NULL) + { + if (strlen(s) > 0 && s[0] == '#') + continue; + templ += string(s) + "\n"; + } + fclose(f); + } + } + return templ; +} + +string cMailNotifier::GetTemplValue(const string& templ, const string& entry) +{ + if (templ == "" || entry == "") return ""; + + string start = "<" + entry + ">"; + string end = "</" + entry + ">"; + + int eBegin = FindIgnoreCase(templ, start); + int eEnd = FindIgnoreCase(templ, end); + if (eBegin < 0 || eEnd < 0) return ""; + string value(templ.begin() + eBegin + start.length(), templ.begin() + eEnd); + return value; +} + +// ------------------- +// cMailUpdateNotifier +cMailUpdateNotifier::cMailUpdateNotifier() +{ + mailTemplate = LoadTemplate("epgsearchupdmail.templ"); +} + +void cMailUpdateNotifier::AddNewTimerNotification(tEventID EventID, tChannelID ChannelID) +{ + cMailTimerNotification N(EventID, ChannelID); + newTimers.insert(N); +} + +void cMailUpdateNotifier::AddModTimerNotification(tEventID EventID, tChannelID ChannelID) +{ + cMailTimerNotification N(EventID, ChannelID); + modTimers.insert(N); +} + +void cMailUpdateNotifier::AddRemoveTimerNotification(cTimer* t, const cEvent* e) +{ + string templTimer = GetTemplValue(mailTemplate, "timer"); + cMailDelTimerNotification N(t, e, templTimer); + delTimers.insert(N); +} + +void cMailUpdateNotifier::SendUpdateNotifications() +{ + if (newTimers.size() == 0 && + modTimers.size() == 0 && + delTimers.size() == 0) + return; + + // extract single templates + if (mailTemplate == "") + { + LogFile.eSysLog("error loading %s", *AddDirectory(CONFIGDIR, "epgsearchupdmail.templ")); + return; + } + string templSubject = GetTemplValue(mailTemplate, "subject"); + string templBody = GetTemplValue(mailTemplate, "mailbody"); + string templTimer = GetTemplValue(mailTemplate, "timer"); + + // create the timer list for new timers + string newtimers; + if (newTimers.size() == 0) + newtimers = tr("No new timers were added."); + std::set<cMailTimerNotification>::iterator itnt; + for (itnt = newTimers.begin(); itnt != newTimers.end(); itnt++) + { + string message = (*itnt).Format(templTimer); + if (message != "") newtimers += message; + } + + // create the timer list for modified timers + string modtimers; + if (modTimers.size() == 0) + modtimers = tr("No timers were modified."); + std::set<cMailTimerNotification>::iterator itmt; + for (itmt = modTimers.begin(); itmt != modTimers.end(); itmt++) + { + string message = (*itmt).Format(templTimer); + if (message != "") modtimers += message; + } + + // create the timer list for removed timers + string deltimers; + if (delTimers.size() == 0) + deltimers = tr("No timers were deleted."); + std::set<cMailDelTimerNotification>::iterator itdt; + for (itdt = delTimers.begin(); itdt != delTimers.end(); itdt++) + { + string message = (*itdt).formatted; + if (message != "") deltimers += message; + } + + // evaluate variables + cVarExpr varExprSubj(templSubject); + subject = varExprSubj.Evaluate(); + subject = ReplaceAll(subject, "%update.countnewtimers%", NumToString((long)newTimers.size())); + subject = ReplaceAll(subject, "%update.countmodtimers%", NumToString((long)modTimers.size())); + subject = ReplaceAll(subject, "%update.countdeltimers%", NumToString((long)delTimers.size())); + + newtimers = ReplaceAll(newtimers, "%update.countnewtimers%", NumToString((long)newTimers.size())); + modtimers = ReplaceAll(modtimers, "%update.countmodtimers%", NumToString((long)modTimers.size())); + deltimers = ReplaceAll(deltimers, "%update.countdeltimers%", NumToString((long)delTimers.size())); + + cVarExpr varExprBody(templBody); + body = varExprBody.Evaluate(); + body = ReplaceAll(body, "%update.countnewtimers%", NumToString((long)newTimers.size())); + body = ReplaceAll(body, "%update.countmodtimers%", NumToString((long)modTimers.size())); + body = ReplaceAll(body, "%update.countdeltimers%", NumToString((long)delTimers.size())); + body = ReplaceAll(body, "%update.newtimers%", newtimers); + body = ReplaceAll(body, "%update.modtimers%", modtimers); + body = ReplaceAll(body, "%update.deltimers%", deltimers); + + SendMail(); + + newTimers.clear(); + modTimers.clear(); + delTimers.clear(); +} + +// --------------------- +// cMailConflictNotifier +void cMailConflictNotifier::SendConflictNotifications(cConflictCheck& conflictCheck) +{ + if (conflictCheck.relevantConflicts == 0) + return; + + // check if anything has changed since last mail + ostringstream newMailConflicts; + cList<cConflictCheckTime>* failedList = conflictCheck.GetFailed(); + if (!failedList) return; + + for(cConflictCheckTime* ct = failedList->First(); ct; ct = failedList->Next(ct)) + { + if (!ct || ct->ignore) continue; + std::set<cConflictCheckTimerObj*,TimerObjSort>::iterator it; + for (it = ct->failedTimers.begin(); it != ct->failedTimers.end(); it++) + if ((*it) && !(*it)->ignore && (*it)->Event()) + newMailConflicts << (*it)->Event()->EventID() << "|" << (*it)->Event()->ChannelID().ToString(); + } + string newMailConflictsMD5 = MD5(newMailConflicts.str()); + if (newMailConflictsMD5 == EPGSearchConfig.LastMailConflicts) + { + LogFile.Log(3, "conflicts unchanged - no new notification needed."); + return; + } + + + // open the template + string templ = LoadTemplate("epgsearchconflmail.templ"); + if (templ == "") + { + LogFile.eSysLog("error loading %s", *AddDirectory(CONFIGDIR, "epgsearchconflmail.templ")); + return; + } + + // extract single templates + LogFile.Log(3, "extracting templates"); + string templSubject = GetTemplValue(templ, "subject"); + string templBody = GetTemplValue(templ, "mailbody"); + string templConflictsAt = GetTemplValue(templ, "conflictsat"); + string templConflictTimer = GetTemplValue(templ, "conflicttimer"); + LogFile.Log(3, "extracting templates - done"); + + // create the conflict list + string conflicts; + for(cConflictCheckTime* ct = failedList->First(); ct; ct = failedList->Next(ct)) + { + if (ct->ignore) continue; + // format conflict time + string conflictsAt = templConflictsAt; + conflictsAt = ReplaceAll(conflictsAt, "%conflict.time%", TIMESTRING(ct->evaltime)); + conflictsAt = ReplaceAll(conflictsAt, "%conflict.date%", DATESTRING(ct->evaltime)); + + string conflicttimers; + std::set<cConflictCheckTimerObj*,TimerObjSort>::iterator it; + for (it = ct->failedTimers.begin(); it != ct->failedTimers.end(); it++) + if (!(*it)->ignore && (*it)->Event()) + { + cMailTimerNotification M((*it)->Event()->EventID(), (*it)->Event()->ChannelID()); + string message = M.Format(templConflictTimer); + if (message != "") + { + message = ReplaceAll(message, "%device%", NumToString((*it)->device)); + conflicttimers += message; + } + } + conflictsAt = ReplaceAll(conflictsAt, "%conflict.confltimers%", conflicttimers); + + conflicts += conflictsAt; + } + + // evaluate variables + cVarExpr varExprSubj(templSubject); + subject = varExprSubj.Evaluate(); + subject = ReplaceAll(subject, "%conflict.count%", NumToString(conflictCheck.relevantConflicts)); + + conflicts = ReplaceAll(conflicts, "%conflict.count%", NumToString(conflictCheck.relevantConflicts)); + + cVarExpr varExprBody(templBody); + body = varExprBody.Evaluate(); + body = ReplaceAll(body, "%conflict.count%", NumToString(conflictCheck.relevantConflicts)); + body = ReplaceAll(body, "%conflict.conflicts%", conflicts); + + SendMail(); + + // store conflicts + strcpy(EPGSearchConfig.LastMailConflicts, newMailConflictsMD5.c_str()); + cPluginManager::GetPlugin("epgsearch")->SetupStore("LastMailConflicts", EPGSearchConfig.LastMailConflicts); +} |