|
|
|
/***************************************************************************
|
|
|
|
* CT Task Implementation *
|
|
|
|
* -------------------------------------------------------------------- *
|
|
|
|
* Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
|
|
|
|
* -------------------------------------------------------------------- *
|
|
|
|
* 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. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
|
|
|
|
// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
|
|
|
|
|
|
|
|
#include "cttask.h"
|
|
|
|
|
|
|
|
#include "cti18n.h"
|
|
|
|
#include <time.h> // tm, strftime()
|
|
|
|
|
|
|
|
CTTask::CTTask(string tokStr, string _comment, bool _syscron) :
|
|
|
|
syscron(_syscron)
|
|
|
|
{
|
|
|
|
if (tokStr.substr(0,2) == "#\\")
|
|
|
|
{
|
|
|
|
tokStr = tokStr.substr(2,tokStr.length() - 2);
|
|
|
|
enabled = false;
|
|
|
|
}
|
|
|
|
else if (tokStr.substr(0,1) == "#")
|
|
|
|
{
|
|
|
|
tokStr = tokStr.substr(1,tokStr.length() - 1);
|
|
|
|
enabled = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
enabled = true;
|
|
|
|
|
|
|
|
//older versions had something called silence. We should still be able to not choke on what we have been
|
|
|
|
//writing earlier. This has no use though.
|
|
|
|
if (tokStr.substr(0,1) == "-")
|
|
|
|
{
|
|
|
|
tokStr = tokStr.substr(1,tokStr.length() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tokStr.substr(0,1) == "@")
|
|
|
|
{
|
|
|
|
if (tokStr.substr(1,6) == "reboot")
|
|
|
|
{
|
|
|
|
// Dunno what to do with this...
|
|
|
|
tokStr = "0 0 1 1 *"+tokStr.substr(7,tokStr.length()-1);
|
|
|
|
}
|
|
|
|
else if (tokStr.substr(1,6) == "yearly")
|
|
|
|
{
|
|
|
|
tokStr = "0 0 1 1 *"+tokStr.substr(7,tokStr.length()-1);
|
|
|
|
}
|
|
|
|
else if (tokStr.substr(1,8) == "annually")
|
|
|
|
{
|
|
|
|
tokStr = "0 0 1 1 *"+tokStr.substr(9,tokStr.length()-1);
|
|
|
|
}
|
|
|
|
else if (tokStr.substr(1,7) == "monthly")
|
|
|
|
{
|
|
|
|
tokStr = "0 0 1 * *"+tokStr.substr(8,tokStr.length()-1);
|
|
|
|
}
|
|
|
|
else if (tokStr.substr(1,6) == "weekly")
|
|
|
|
{
|
|
|
|
tokStr = "0 0 * * 0"+tokStr.substr(7,tokStr.length()-1);
|
|
|
|
}
|
|
|
|
else if (tokStr.substr(1,5) == "daily")
|
|
|
|
{
|
|
|
|
tokStr = "0 0 * * *"+tokStr.substr(6,tokStr.length()-1);
|
|
|
|
}
|
|
|
|
else if (tokStr.substr(1,6) == "hourly")
|
|
|
|
{
|
|
|
|
tokStr = "0 * * * *"+tokStr.substr(7,tokStr.length()-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int spacepos(tokStr.find_first_of(" \t"));
|
|
|
|
minute.initialize(tokStr.substr(0,spacepos));
|
|
|
|
|
|
|
|
while(isspace(tokStr[spacepos+1])) spacepos++;
|
|
|
|
tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
|
|
|
|
spacepos = tokStr.find_first_of(" \t");
|
|
|
|
hour.initialize(tokStr.substr(0,spacepos));
|
|
|
|
|
|
|
|
while(isspace(tokStr[spacepos+1])) spacepos++;
|
|
|
|
tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
|
|
|
|
spacepos = tokStr.find_first_of(" \t");
|
|
|
|
dayOfMonth.initialize(tokStr.substr(0,spacepos));
|
|
|
|
|
|
|
|
while(isspace(tokStr[spacepos+1])) spacepos++;
|
|
|
|
tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
|
|
|
|
spacepos = tokStr.find_first_of(" \t");
|
|
|
|
month.initialize(tokStr.substr(0,spacepos));
|
|
|
|
|
|
|
|
while(isspace(tokStr[spacepos+1])) spacepos++;
|
|
|
|
tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
|
|
|
|
spacepos = tokStr.find_first_of(" \t");
|
|
|
|
dayOfWeek.initialize(tokStr.substr(0,spacepos));
|
|
|
|
|
|
|
|
if (syscron)
|
|
|
|
{
|
|
|
|
while(isspace(tokStr[spacepos+1])) spacepos++;
|
|
|
|
tokStr = tokStr.substr(spacepos+1,tokStr.length()-1);
|
|
|
|
spacepos = tokStr.find_first_of(" \t");
|
|
|
|
user = tokStr.substr(0,spacepos);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
user = string("");
|
|
|
|
|
|
|
|
command = tokStr.substr(spacepos+1,tokStr.length()-1);
|
|
|
|
// remove leading whitespace
|
|
|
|
while (command.find_first_of(" \t") == 0)
|
|
|
|
command = command.substr(1,command.length()-1);
|
|
|
|
comment = _comment;
|
|
|
|
|
|
|
|
initialUser = user;
|
|
|
|
initialCommand = command;
|
|
|
|
initialComment = comment;
|
|
|
|
initialEnabled = enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
CTTask::CTTask(const CTTask &source) :
|
|
|
|
month(source.month),
|
|
|
|
dayOfMonth(source.dayOfMonth),
|
|
|
|
dayOfWeek(source.dayOfWeek),
|
|
|
|
hour(source.hour),
|
|
|
|
minute(source.minute),
|
|
|
|
user(source.user),
|
|
|
|
command(source.command),
|
|
|
|
comment(source.comment),
|
|
|
|
enabled(source.enabled),
|
|
|
|
initialUser(""),
|
|
|
|
initialCommand(""),
|
|
|
|
initialComment(""),
|
|
|
|
initialEnabled(true)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CTTask::operator = (const CTTask& source)
|
|
|
|
{
|
|
|
|
month = source.month;
|
|
|
|
dayOfMonth = source.dayOfMonth;
|
|
|
|
dayOfWeek = source.dayOfWeek;
|
|
|
|
hour = source.hour;
|
|
|
|
minute = source.minute;
|
|
|
|
user = source.user;
|
|
|
|
command = source.command;
|
|
|
|
comment = source.comment;
|
|
|
|
enabled = source.enabled;
|
|
|
|
initialUser = "";
|
|
|
|
initialCommand = "";
|
|
|
|
initialComment = "";
|
|
|
|
initialEnabled = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ostream& operator << (ostream& outputStream, const CTTask& task)
|
|
|
|
{
|
|
|
|
// if (task.comment != string(""))
|
|
|
|
outputStream << "# " << task.comment << "\n";
|
|
|
|
|
|
|
|
if (!task.enabled)
|
|
|
|
outputStream << "#\\";
|
|
|
|
|
|
|
|
outputStream << task.minute << " ";
|
|
|
|
outputStream << task.hour << " ";
|
|
|
|
outputStream << task.dayOfMonth << " ";
|
|
|
|
outputStream << task.month << " ";
|
|
|
|
outputStream << task.dayOfWeek << "\t";
|
|
|
|
|
|
|
|
if (task.user != string(""))
|
|
|
|
outputStream << task.user << "\t";
|
|
|
|
|
|
|
|
outputStream << task.command << "\n";
|
|
|
|
|
|
|
|
return outputStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CTTask::apply()
|
|
|
|
{
|
|
|
|
month.apply();
|
|
|
|
dayOfMonth.apply();
|
|
|
|
dayOfWeek.apply();
|
|
|
|
hour.apply();
|
|
|
|
minute.apply();
|
|
|
|
initialUser = user;
|
|
|
|
initialCommand = command;
|
|
|
|
initialComment = comment;
|
|
|
|
initialEnabled = enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CTTask::cancel()
|
|
|
|
{
|
|
|
|
month.cancel();
|
|
|
|
dayOfMonth.cancel();
|
|
|
|
dayOfWeek.cancel();
|
|
|
|
hour.cancel();
|
|
|
|
minute.cancel();
|
|
|
|
user = initialUser;
|
|
|
|
command = initialCommand;
|
|
|
|
comment = initialComment;
|
|
|
|
enabled = initialEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CTTask::dirty() const
|
|
|
|
{
|
|
|
|
return (month.dirty() || dayOfMonth.dirty() || dayOfWeek.dirty() ||
|
|
|
|
hour.dirty() || minute.dirty() || (user != initialUser) ||
|
|
|
|
(command != initialCommand) || (comment != initialComment) ||
|
|
|
|
(enabled != initialEnabled) );
|
|
|
|
}
|
|
|
|
|
|
|
|
string CTTask::describe() const
|
|
|
|
{
|
|
|
|
|
|
|
|
// Of the whole program, this method is probably the trickiest.
|
|
|
|
//
|
|
|
|
// This method creates the natural language description, such as
|
|
|
|
// "At 1:00am, every Sun".
|
|
|
|
//
|
|
|
|
// First, I declare some strings for holding what can be internationalized.
|
|
|
|
// Note the tokens such as "MONTHS". Translators should reuse these
|
|
|
|
// tokens in their translations. See README.translators for more
|
|
|
|
// information.
|
|
|
|
//
|
|
|
|
// Second, I get the descriptions from the component parts such as
|
|
|
|
// days of the month.
|
|
|
|
//
|
|
|
|
// Third, I get hour/minute time combinations. Although a little bit
|
|
|
|
// awkward, I use the tm struct and strftime from <time.h>. This
|
|
|
|
// way this code is portable across all Unixes.
|
|
|
|
//
|
|
|
|
// Fourth, I know that "every day of the week" and "every day of the
|
|
|
|
// month" simply makes "every day".
|
|
|
|
//
|
|
|
|
// Fifth and finally I do tag substitution to create the natural language
|
|
|
|
// description.
|
|
|
|
|
|
|
|
string tmFormat((const char *)i18n("%H:%M").local8Bit());
|
|
|
|
string DOMFormat((const char *)i18n("Please translator, read the README.translators file in kcron's source code","DAYS_OF_MONTH of MONTHS").local8Bit());
|
|
|
|
string DOWFormat((const char *)i18n("Really, read that file","every DAYS_OF_WEEK").local8Bit());
|
|
|
|
string dateFormat((const char *)i18n("DOM_FORMAT as well as DOW_FORMAT").local8Bit());
|
|
|
|
string timeFormat((const char *)i18n("At TIME").local8Bit());
|
|
|
|
string format((const char *)i18n("TIME_FORMAT, DATE_FORMAT").local8Bit());
|
|
|
|
|
|
|
|
// Get natural language description of day of month,
|
|
|
|
// month name, and day of week.
|
|
|
|
|
|
|
|
string DOMDesc(dayOfMonth.describe());
|
|
|
|
string monthDesc(month.describe());
|
|
|
|
string DOWDesc(dayOfWeek.describe());
|
|
|
|
|
|
|
|
// Create time description.
|
|
|
|
|
|
|
|
int total(minute.count()*hour.count());
|
|
|
|
|
|
|
|
string timeDesc("");
|
|
|
|
int count(0);
|
|
|
|
|
|
|
|
for (int h = 0; h <= 23; h++)
|
|
|
|
if (hour.get(h))
|
|
|
|
for (int m = 0; m <= 59; m++)
|
|
|
|
if (minute.get(m))
|
|
|
|
{
|
|
|
|
tm time;
|
|
|
|
time.tm_sec = 0;
|
|
|
|
time.tm_min = m;
|
|
|
|
time.tm_hour = h;
|
|
|
|
time.tm_mday = 0;
|
|
|
|
time.tm_mon = 0;
|
|
|
|
time.tm_year = 0;
|
|
|
|
time.tm_wday = 0;
|
|
|
|
time.tm_yday = 0;
|
|
|
|
time.tm_isdst= 0;
|
|
|
|
|
|
|
|
char tmp[12];
|
|
|
|
strftime(tmp, 12, tmFormat.c_str(), &time);
|
|
|
|
string tmpStr = tmp;
|
|
|
|
|
|
|
|
// remove leading space
|
|
|
|
if (tmpStr.substr(0,1) == " ")
|
|
|
|
tmpStr = tmpStr.substr(1,tmpStr.length()-1);
|
|
|
|
|
|
|
|
timeDesc += tmpStr;
|
|
|
|
count++;
|
|
|
|
switch (total - count)
|
|
|
|
{
|
|
|
|
case 0: break;
|
|
|
|
case 1: if (total > 2)
|
|
|
|
timeDesc += (const char *)i18n(", and ").local8Bit();
|
|
|
|
else
|
|
|
|
timeDesc += (const char *)i18n(" and ").local8Bit();
|
|
|
|
break;
|
|
|
|
default: timeDesc += (const char*)i18n(", ").local8Bit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// "* * *" means truly every day.
|
|
|
|
// Note: Languages may use different phrases to indicate
|
|
|
|
// every day of month versus every day of week.
|
|
|
|
|
|
|
|
if ((dayOfMonth.count() == 31) &&
|
|
|
|
(dayOfWeek.count() == 7))
|
|
|
|
dateFormat = (const char *)i18n("every day ").local8Bit();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Day of month not specified, so use day of week.
|
|
|
|
if (dayOfMonth.count() == 31)
|
|
|
|
dateFormat = "DOW_FORMAT";
|
|
|
|
// Day of week not specified, so use day of month.
|
|
|
|
if (dayOfWeek.count() == 7)
|
|
|
|
dateFormat = "DOM_FORMAT";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Replace tags to build natural language description.
|
|
|
|
|
|
|
|
int pos(0);
|
|
|
|
|
|
|
|
if ((pos = DOMFormat.find("DAYS_OF_MONTH")) > -1)
|
|
|
|
DOMFormat.replace(pos,13,DOMDesc);
|
|
|
|
|
|
|
|
if ((pos = DOMFormat.find("MONTHS")) > -1)
|
|
|
|
DOMFormat.replace(pos,6,monthDesc);
|
|
|
|
|
|
|
|
if ((pos = DOWFormat.find("DAYS_OF_WEEK")) > -1)
|
|
|
|
DOWFormat.replace(pos,12,DOWDesc);
|
|
|
|
|
|
|
|
if ((pos = dateFormat.find("DOM_FORMAT")) > -1)
|
|
|
|
dateFormat.replace(pos,10,DOMFormat);
|
|
|
|
|
|
|
|
if ((pos = dateFormat.find("DOW_FORMAT")) > -1)
|
|
|
|
dateFormat.replace(pos,10,DOWFormat);
|
|
|
|
|
|
|
|
if ((pos = timeFormat.find("TIME")) > -1)
|
|
|
|
timeFormat.replace(pos,4,timeDesc);
|
|
|
|
|
|
|
|
if ((pos = format.find("DATE_FORMAT")) > -1)
|
|
|
|
format.replace(pos,11,dateFormat);
|
|
|
|
|
|
|
|
if ((pos = format.find("TIME_FORMAT")) > -1)
|
|
|
|
format.replace(pos,11,timeFormat);
|
|
|
|
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CTTask::system() const
|
|
|
|
{
|
|
|
|
return syscron;
|
|
|
|
}
|