SVN_SILENT made messages (.desktop file)
[kdeadmin.git] / kcron / ctcron.cpp
blob09977657fb8cb6def33e7b37eed24f1594787e58
1 /***************************************************************************
2 * CT Cron Implementation *
3 * -------------------------------------------------------------------- *
4 * Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
5 * -------------------------------------------------------------------- *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 ***************************************************************************/
12 // Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
13 // I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
15 #include "ctcron.h"
17 #include "cti18n.h"
18 #include "cttask.h"
19 #include "ctvariable.h"
20 #include <unistd.h> // getuid(), unlink()
21 #include <pwd.h> // pwd, getpwnam(), getpwuid()
22 #include <stdio.h>
23 #include <assert.h>
25 #include <QFile>
27 #include <kshell.h>
28 #include <klocale.h>
29 #include <ktemporaryfile.h>
31 #include <iostream>
33 using namespace std;
35 CTCron::CTCron(const QString& crontabBinary, bool _syscron, string _login) :
36 syscron(_syscron)
38 int uid(getuid());
40 this->crontab = crontabBinary;
42 KTemporaryFile tmp;
43 tmp.open();
44 tmpFileName = tmp.fileName();
46 QString readCommand;
48 if (uid == 0)
49 // root, so provide requested crontab
51 if (syscron)
53 readCommand = "cat /etc/crontab > " + KShell::quoteArg(tmpFileName);
54 writeCommand = "cat " + KShell::quoteArg(tmpFileName) + " > /etc/crontab";
55 login = (const char *)i18n("(System Crontab)").toLocal8Bit();
56 name = "";
58 else
60 readCommand = crontab + " -u " + _login.c_str() + " -l > " + KShell::quoteArg(tmpFileName);
61 writeCommand = crontab + " -u " + _login.c_str() + " " + KShell::quoteArg(tmpFileName);
62 if (!initFromPasswd(getpwnam(_login.c_str())))
64 error = i18n("No password entry found for user '%1'", _login.c_str());
68 else
69 // regular user, so provide user's own crontab
71 readCommand = crontab + " -l > " + KShell::quoteArg(tmpFileName);
72 writeCommand = crontab + " " + KShell::quoteArg(tmpFileName);
73 if (!initFromPasswd(getpwuid(uid)))
75 error = i18n("No password entry found for uid '%1'", uid);
79 if (name.empty())
80 name = login;
82 initialTaskCount = 0;
83 initialVariableCount = 0;
85 if (isError())
86 return;
88 // Don't set error if it can't be read, it means the user
89 // doesn't have a crontab.
90 if (system(QFile::encodeName(readCommand)) == 0)
92 ifstream cronfile(QFile::encodeName(tmpFileName));
93 cronfile >> *this;
96 initialTaskCount = task.size();
97 initialVariableCount = variable.size();
100 CTCron::CTCron(const QString& crontabBinary, const struct passwd *pwd) :
101 syscron(false)
103 Q_ASSERT(pwd != 0L);
105 crontab = crontabBinary;
107 KTemporaryFile tmp;
108 tmp.open();
109 tmpFileName = tmp.fileName();
111 QString readCommand = crontab + " -u " + QString(pwd->pw_name) + " -l > " + KShell::quoteArg(tmpFileName);
112 writeCommand = crontab + " -u " + QString(pwd->pw_name) + " " + KShell::quoteArg(tmpFileName);
114 initFromPasswd(pwd);
116 initialTaskCount = 0;
117 initialVariableCount = 0;
119 if (isError())
120 return;
122 // Don't set error if it can't be read, it means the user
123 // doesn't have a crontab.
124 if (system(QFile::encodeName(readCommand)) == 0)
126 ifstream cronfile(QFile::encodeName(tmpFileName));
127 cronfile >> *this;
130 initialTaskCount = task.size();
131 initialVariableCount = variable.size();
134 bool CTCron::initFromPasswd(const struct passwd *pwd)
136 if (pwd == 0)
138 return false;
140 else
142 login = pwd->pw_name;
143 name = pwd->pw_gecos;
144 return true;
148 void CTCron::operator = (const CTCron& source)
150 assert(!source.syscron);
152 for (CTVariableIterator i = const_cast<CTCron&>(source).variable.begin();
153 i != source.variable.end(); ++i)
155 CTVariable* tmp = new CTVariable(**i);
156 variable.push_back(tmp);
159 for (CTTaskIterator i = const_cast<CTCron&>(source).task.begin();
160 i != source.task.end(); ++i)
162 CTTask* tmp = new CTTask(**i);
163 task.push_back(tmp);
167 istream& operator >> (istream& inputStream, CTCron& cron)
169 const int MAX = 1024;
170 char buffer[MAX];
171 string line("");
172 string comment("");
174 while (inputStream)
176 inputStream.getline(buffer, MAX);
177 line = buffer;
179 // search for comments "#" but not disabled tasks "#\"
180 if ((line.find("#") == 0) && (line.find("\\") != 1))
182 // If the first 10 characters don't contain a character, it's probably a disabled entry.
183 int first_text = line.find_first_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
184 if (first_text < 0)
185 continue;
187 if (first_text < 10)
189 // remove leading pound sign
190 line = line.substr(1,line.length()-1);
191 // remove leading whitespace
192 while (line.find_first_of(" \t") == 0)
193 line = line.substr(1,line.length()-1);
194 comment = line;
195 continue;
199 // else
201 // either a task or a variable
202 int firstWhiteSpace(line.find_first_of(" \t"));
203 int firstEquals(line.find("="));
205 // if there is an equals sign and either there is no
206 // whitespace or the first whitespace is after the equals
207 // sign, it must be a variable
208 if ((firstEquals > 0) && ((firstWhiteSpace == -1) ||
209 firstWhiteSpace > firstEquals))
211 // create variable
212 CTVariable *tmp = new CTVariable(line, comment);
213 cron.variable.push_back(tmp);
214 comment = "";
216 else
217 // must be a task, either enabled or disabled
219 if (firstWhiteSpace > 0)
221 CTTask *tmp = new CTTask(line, comment, cron.syscron);
222 cron.task.push_back(tmp);
223 comment = "";
228 return inputStream;
231 ostream& operator << (ostream& outputStream, const CTCron& cron)
233 int itemCount(0);
235 for (CTVariableIterator i = const_cast<CTCron&>(cron).variable.begin();
236 i != cron.variable.end(); ++i)
238 outputStream << **i;
239 itemCount++;
242 for (CTTaskIterator i = const_cast<CTCron&>(cron).task.begin();
243 i != cron.task.end(); ++i)
245 outputStream << **i;
246 itemCount++;
249 if (itemCount > 0)
251 outputStream << "# This file was written by KCron. Copyright (c) 1999, Gary Meyer\n";
252 outputStream << "# Although KCron supports most crontab formats, use care when editing.\n";
253 outputStream << "# Note: Lines beginning with \"#\\\" indicates a disabled task.\n";
256 return outputStream;
259 CTCron::~CTCron()
261 for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
262 delete *i;
263 for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
264 delete *i;
267 void CTCron::apply()
269 // write to temp file
270 ofstream cronfile(QFile::encodeName(tmpFileName));
271 cronfile << *this << flush;
273 // install temp file into crontab
274 if (system(QFile::encodeName(writeCommand)) != 0)
276 error = i18n("An error occurred while updating crontab.");
279 // remove the temp file
280 (void) unlink(QFile::encodeName(tmpFileName));
282 if (isError())
283 return;
285 // mark as applied
286 for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
287 (*i)->apply();
289 for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
290 (*i)->apply();
292 initialTaskCount = task.size();
293 initialVariableCount = variable.size();
296 void CTCron::cancel()
298 for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
299 (*i)->cancel();
301 for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
302 (*i)->cancel();
305 bool CTCron::dirty()
307 bool isDirty(false);
309 if (initialTaskCount != task.size()) isDirty = true;
311 if (initialVariableCount != variable.size()) isDirty = true;
313 for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
314 if ((*i)->dirty()) isDirty = true;
316 for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
317 if ((*i)->dirty()) isDirty = true;
319 return isDirty;
322 string CTCron::path() const
324 string path;
326 for (CTVariableIterator var = const_cast<CTCron*>(this)->variable.begin();
327 var != variable.end(); var++)
329 if ((*var)->variable == "PATH")
331 path = (*var)->value;
334 return path;