summaryrefslogtreecommitdiff
path: root/mail.c
diff options
context:
space:
mode:
authorChristian Wieninger <winni@debian.(none)>2007-11-11 15:40:28 +0100
committerChristian Wieninger <winni@debian.(none)>2007-11-11 15:40:28 +0100
commit8d4f8607dc1558ce73eb4c376bdbf78ddb65da83 (patch)
treed0c5dde81a36ab2e8a2edc7c1e6922556518b312 /mail.c
downloadvdr-plugin-epgsearch-8d4f8607dc1558ce73eb4c376bdbf78ddb65da83.tar.gz
vdr-plugin-epgsearch-8d4f8607dc1558ce73eb4c376bdbf78ddb65da83.tar.bz2
Initial commit
Diffstat (limited to 'mail.c')
-rw-r--r--mail.c459
1 files changed, 459 insertions, 0 deletions
diff --git a/mail.c b/mail.c
new file mode 100644
index 0000000..4f3bd3f
--- /dev/null
+++ b/mail.c
@@ -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);
+}