Logo Search packages:      
Sourcecode: vdr-plugin-epgsearch version File versions

mail.c

#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);
}

Generated by  Doxygen 1.6.0   Back to index