- handle events that move around from year to year, i.e.,
``the last Monday in April' - handle easter new options -f calendarfile -A days -B days Calendar HOME directory ~/.calendar don't sent mail if ~/.calendar/nomail exist
This commit is contained in:
parent
4ad1bd1e33
commit
c9c822e632
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=13840
@ -1,6 +1,7 @@
|
|||||||
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||||
|
|
||||||
PROG= calendar
|
PROG= calendar
|
||||||
|
SRCS= calendar.c io.c day.c ostern.c
|
||||||
INTER= de_DE.ISO_8859-1
|
INTER= de_DE.ISO_8859-1
|
||||||
SHAREDIR= /usr/share/calendar
|
SHAREDIR= /usr/share/calendar
|
||||||
TEXTMODE?= 444
|
TEXTMODE?= 444
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.\" Copyright (c) 1989, 1990, 1993
|
.\" Copyright (c) 1989, 1990, 1993
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
.\"
|
.\"
|
||||||
.\" Redistribution and use in source and binary forms, with or without
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
.\" modification, are permitted provided that the following conditions
|
.\" modification, are permitted provided that the following conditions
|
||||||
@ -11,8 +11,8 @@
|
|||||||
.\" documentation and/or other materials provided with the distribution.
|
.\" documentation and/or other materials provided with the distribution.
|
||||||
.\" 3. All advertising materials mentioning features or use of this software
|
.\" 3. All advertising materials mentioning features or use of this software
|
||||||
.\" must display the following acknowledgement:
|
.\" must display the following acknowledgement:
|
||||||
.\" This product includes software developed by the University of
|
.\" This product includes software developed by the University of
|
||||||
.\" California, Berkeley and its contributors.
|
.\" California, Berkeley and its contributors.
|
||||||
.\" 4. Neither the name of the University nor the names of its contributors
|
.\" 4. Neither the name of the University nor the names of its contributors
|
||||||
.\" may be used to endorse or promote products derived from this software
|
.\" may be used to endorse or promote products derived from this software
|
||||||
.\" without specific prior written permission.
|
.\" without specific prior written permission.
|
||||||
@ -29,7 +29,7 @@
|
|||||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" @(#)calendar.1 8.1 (Berkeley) 6/29/93
|
.\" @(#)calendar.1 8.1 (Berkeley) 6/29/93
|
||||||
.\"
|
.\"
|
||||||
.Dd June 29, 1993
|
.Dd June 29, 1993
|
||||||
.Dt CALENDAR 1
|
.Dt CALENDAR 1
|
||||||
@ -40,6 +40,9 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm calendar
|
.Nm calendar
|
||||||
.Op Fl a
|
.Op Fl a
|
||||||
|
.Op Fl A Ar num
|
||||||
|
.Op Fl B Ar num
|
||||||
|
.Op Fl f Ar calendarfile
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm Calendar
|
.Nm Calendar
|
||||||
checks the current directory for a file named
|
checks the current directory for a file named
|
||||||
@ -54,6 +57,20 @@ The following options are available:
|
|||||||
Process the ``calendar'' files of all users and mail the results
|
Process the ``calendar'' files of all users and mail the results
|
||||||
to them.
|
to them.
|
||||||
This requires super-user privileges.
|
This requires super-user privileges.
|
||||||
|
.It Fl A Ar num
|
||||||
|
print lines from today and next
|
||||||
|
.Ar num
|
||||||
|
days (forward, future)
|
||||||
|
|
||||||
|
.It Fl B Ar num
|
||||||
|
print lines from today and previous
|
||||||
|
.Ar num
|
||||||
|
days (backward, past)
|
||||||
|
.It Fl f Pa calendarfile
|
||||||
|
use
|
||||||
|
.Pa calendarfile
|
||||||
|
as default calendar file.
|
||||||
|
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Lines should begin with a month and day.
|
Lines should begin with a month and day.
|
||||||
@ -65,6 +82,11 @@ A month without a day matches the first of that month.
|
|||||||
Two numbers default to the month followed by the day.
|
Two numbers default to the month followed by the day.
|
||||||
Lines with leading tabs default to the last entered date, allowing
|
Lines with leading tabs default to the last entered date, allowing
|
||||||
multiple line specifications for a single date.
|
multiple line specifications for a single date.
|
||||||
|
``Easter'', may be followed by an positive or negative integer, is
|
||||||
|
Easter for this year. Weekdays may be followed by ``-4'' ... ``+5'' (aliases
|
||||||
|
last, first, second, third, fourth) for moving events like
|
||||||
|
``the last Monday in April''
|
||||||
|
|
||||||
By convention, dates followed by an asterisk are not fixed, i.e., change
|
By convention, dates followed by an asterisk are not fixed, i.e., change
|
||||||
from year to year.
|
from year to year.
|
||||||
.Pp
|
.Pp
|
||||||
@ -83,17 +105,46 @@ are ignored.
|
|||||||
.Pp
|
.Pp
|
||||||
Some possible calendar entries:
|
Some possible calendar entries:
|
||||||
.Bd -unfilled -offset indent
|
.Bd -unfilled -offset indent
|
||||||
#include <calendar.usholiday>
|
#include <calendar.usholiday>
|
||||||
#include <calendar.birthday>
|
#include <calendar.birthday>
|
||||||
|
|
||||||
|
6/15 ... June 15 (if ambiguous, will default to month/day).
|
||||||
|
Jun. 15 ... June 15.
|
||||||
|
15 June ... June 15.
|
||||||
|
Thursday ... Every Thursday.
|
||||||
|
June ... Every June 1st.
|
||||||
|
15 * ... 15th of every month.
|
||||||
|
|
||||||
|
May Sun+2 ... second Sunday in May (Muttertag)
|
||||||
|
04/SunLast ... last Sunday in April, summer time in Europe
|
||||||
|
Easter ... Easter
|
||||||
|
Easter-2 ... Good Friday (2 days before Easter)
|
||||||
|
|
||||||
6/15 ... June 15 (if ambiguous, will default to month/day).
|
|
||||||
Jun. 15 ... June 15.
|
|
||||||
15 June ... June 15.
|
|
||||||
Thursday ... Every Thursday.
|
|
||||||
June ... Every June 1st.
|
|
||||||
15 * ... 15th of every month.
|
|
||||||
.Ed
|
.Ed
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
|
|
||||||
|
.Pp
|
||||||
|
.Bl -tag -width calendar.christian -compact
|
||||||
|
.It Pa calendar
|
||||||
|
file in current directory
|
||||||
|
|
||||||
|
.It Pa ~/.calendar
|
||||||
|
.Pa calendar
|
||||||
|
HOME directory.
|
||||||
|
.Nm calendar
|
||||||
|
did a chdir into this directory if exist.
|
||||||
|
|
||||||
|
|
||||||
|
.It Pa ~/.calendar/calendar
|
||||||
|
file in calendar HOME directory, used if no calendar file
|
||||||
|
in current directory.
|
||||||
|
|
||||||
|
.It Pa ~/.calendar/nomail
|
||||||
|
don't send mail if
|
||||||
|
.Pa ~/.calendar/nomail
|
||||||
|
exist.
|
||||||
|
.El
|
||||||
|
|
||||||
The following default calendar files are provided:
|
The following default calendar files are provided:
|
||||||
.Pp
|
.Pp
|
||||||
.Bl -tag -width calendar.christian -compact
|
.Bl -tag -width calendar.christian -compact
|
||||||
@ -122,6 +173,10 @@ Strongly oriented toward rock 'n' roll.
|
|||||||
U.S. holidays.
|
U.S. holidays.
|
||||||
This calendar should be updated yearly by the local system administrator
|
This calendar should be updated yearly by the local system administrator
|
||||||
so that roving holidays are set correctly for the current year.
|
so that roving holidays are set correctly for the current year.
|
||||||
|
|
||||||
|
.It Pa calendar.german
|
||||||
|
German calendar.
|
||||||
|
|
||||||
.El
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr at 1 ,
|
.Xr at 1 ,
|
||||||
@ -139,7 +194,7 @@ first on the line.
|
|||||||
A
|
A
|
||||||
.Nm
|
.Nm
|
||||||
command appeared in Version 7 AT&T UNIX.
|
command appeared in Version 7 AT&T UNIX.
|
||||||
|
|
||||||
.Sh BUGS
|
.Sh BUGS
|
||||||
.Nm Calendar
|
.Nm Calendar
|
||||||
doesn't handle events that move around from year to year, i.e.,
|
doesn't handle Jewish holidays and moon phases.
|
||||||
``the last Monday in April''.
|
|
||||||
|
@ -41,37 +41,23 @@ static char copyright[] =
|
|||||||
static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
|
static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
|
||||||
#endif /* not lint */
|
#endif /* not lint */
|
||||||
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <err.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "pathnames.h"
|
#include "pathnames.h"
|
||||||
|
#include "calendar.h"
|
||||||
|
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
int doall;
|
int doall = 0;
|
||||||
|
time_t f_time = 0;
|
||||||
|
|
||||||
void cal __P((void));
|
int f_dayAfter = 0; /* days after current date */
|
||||||
void closecal __P((FILE *));
|
int f_dayBefore = 0; /* days before current date */
|
||||||
int getday __P((char *));
|
|
||||||
int getfield __P((char *, char **, int *));
|
|
||||||
int getmonth __P((char *));
|
|
||||||
int isnow __P((char *));
|
|
||||||
FILE *opencal __P((void));
|
|
||||||
void settime __P((void));
|
|
||||||
void usage __P((void));
|
|
||||||
#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(argc, argv)
|
main(argc, argv)
|
||||||
@ -81,7 +67,7 @@ main(argc, argv)
|
|||||||
extern int optind;
|
extern int optind;
|
||||||
int ch;
|
int ch;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "-a")) != EOF)
|
while ((ch = getopt(argc, argv, "?-af:t:A:B:")) != EOF)
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '-': /* backward contemptible */
|
case '-': /* backward contemptible */
|
||||||
case 'a':
|
case 'a':
|
||||||
@ -91,6 +77,24 @@ main(argc, argv)
|
|||||||
}
|
}
|
||||||
doall = 1;
|
doall = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'f': /* other calendar file */
|
||||||
|
calendarFile = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't': /* other date, undocumented, for tests */
|
||||||
|
f_time = Mktime (optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'A': /* days after current date */
|
||||||
|
f_dayAfter = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'B': /* days before current date */
|
||||||
|
f_dayBefore = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
@ -101,7 +105,12 @@ main(argc, argv)
|
|||||||
if (argc)
|
if (argc)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
settime();
|
/* use current time */
|
||||||
|
if (f_time <= 0)
|
||||||
|
(void)time(&f_time);
|
||||||
|
|
||||||
|
settime(f_time);
|
||||||
|
|
||||||
if (doall)
|
if (doall)
|
||||||
while ((pw = getpwent()) != NULL) {
|
while ((pw = getpwent()) != NULL) {
|
||||||
(void)setegid(pw->pw_gid);
|
(void)setegid(pw->pw_gid);
|
||||||
@ -115,297 +124,13 @@ main(argc, argv)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
cal()
|
|
||||||
{
|
|
||||||
register int printing;
|
|
||||||
register char *p;
|
|
||||||
FILE *fp;
|
|
||||||
int ch;
|
|
||||||
char buf[2048 + 1];
|
|
||||||
|
|
||||||
if ((fp = opencal()) == NULL)
|
|
||||||
return;
|
|
||||||
for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
|
|
||||||
if ((p = strchr(buf, '\n')) != NULL)
|
|
||||||
*p = '\0';
|
|
||||||
else
|
|
||||||
while ((ch = getchar()) != '\n' && ch != EOF);
|
|
||||||
if (buf[0] == '\0')
|
|
||||||
continue;
|
|
||||||
if (buf[0] != '\t')
|
|
||||||
printing = isnow(buf) ? 1 : 0;
|
|
||||||
if (printing)
|
|
||||||
(void)fprintf(fp, "%s\n", buf);
|
|
||||||
}
|
|
||||||
closecal(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iovec header[] = {
|
|
||||||
"From: ", 6,
|
|
||||||
NULL, 0,
|
|
||||||
" (Reminder Service)\nTo: ", 24,
|
|
||||||
NULL, 0,
|
|
||||||
"\nSubject: ", 10,
|
|
||||||
NULL, 0,
|
|
||||||
"'s Calendar\nPrecedence: bulk\n\n", 30,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 1-based month, 0-based days, cumulative */
|
|
||||||
int daytab[][14] = {
|
|
||||||
0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364,
|
|
||||||
0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365,
|
|
||||||
};
|
|
||||||
struct tm *tp;
|
|
||||||
int *cumdays, offset, yrdays;
|
|
||||||
char dayname[10];
|
|
||||||
|
|
||||||
void
|
|
||||||
settime()
|
|
||||||
{
|
|
||||||
time_t now;
|
|
||||||
|
|
||||||
(void)time(&now);
|
|
||||||
tp = localtime(&now);
|
|
||||||
if (isleap(tp->tm_year + 1900)) {
|
|
||||||
yrdays = 366;
|
|
||||||
cumdays = daytab[1];
|
|
||||||
} else {
|
|
||||||
yrdays = 365;
|
|
||||||
cumdays = daytab[0];
|
|
||||||
}
|
|
||||||
/* Friday displays Monday's events */
|
|
||||||
offset = tp->tm_wday == 5 ? 3 : 1;
|
|
||||||
header[5].iov_base = dayname;
|
|
||||||
header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Possible date formats include any combination of:
|
|
||||||
* 3-charmonth (January, Jan, Jan)
|
|
||||||
* 3-charweekday (Friday, Monday, mon.)
|
|
||||||
* numeric month or day (1, 2, 04)
|
|
||||||
*
|
|
||||||
* Any character may separate them, or they may not be separated. Any line,
|
|
||||||
* following a line that is matched, that starts with "whitespace", is shown
|
|
||||||
* along with the matched line.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
isnow(endp)
|
|
||||||
char *endp;
|
|
||||||
{
|
|
||||||
int day, flags, month, v1, v2;
|
|
||||||
|
|
||||||
#define F_ISMONTH 0x01
|
|
||||||
#define F_ISDAY 0x02
|
|
||||||
flags = 0;
|
|
||||||
/* didn't recognize anything, skip it */
|
|
||||||
if (!(v1 = getfield(endp, &endp, &flags)))
|
|
||||||
return (0);
|
|
||||||
if (flags & F_ISDAY || v1 > 12) {
|
|
||||||
/* found a day */
|
|
||||||
day = v1;
|
|
||||||
/* if no recognizable month, assume just a day alone */
|
|
||||||
if (!(month = getfield(endp, &endp, &flags)))
|
|
||||||
month = tp->tm_mon + 1;
|
|
||||||
} else if (flags & F_ISMONTH) {
|
|
||||||
month = v1;
|
|
||||||
/* if no recognizable day, assume the first */
|
|
||||||
if (!(day = getfield(endp, &endp, &flags)))
|
|
||||||
day = 1;
|
|
||||||
} else {
|
|
||||||
v2 = getfield(endp, &endp, &flags);
|
|
||||||
if (flags & F_ISMONTH) {
|
|
||||||
day = v1;
|
|
||||||
month = v2;
|
|
||||||
} else {
|
|
||||||
/* F_ISDAY set, v2 > 12, or no way to tell */
|
|
||||||
month = v1;
|
|
||||||
/* if no recognizable day, assume the first */
|
|
||||||
day = v2 ? v2 : 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flags & F_ISDAY)
|
|
||||||
day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
|
|
||||||
day = cumdays[month] + day;
|
|
||||||
|
|
||||||
/* if today or today + offset days */
|
|
||||||
if (day >= tp->tm_yday && day <= tp->tm_yday + offset)
|
|
||||||
return (1);
|
|
||||||
/* if number of days left in this year + days to event in next year */
|
|
||||||
if (yrdays - tp->tm_yday + day <= offset)
|
|
||||||
return (1);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
getfield(p, endp, flags)
|
|
||||||
char *p, **endp;
|
|
||||||
int *flags;
|
|
||||||
{
|
|
||||||
int val;
|
|
||||||
char *start, savech;
|
|
||||||
|
|
||||||
for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
|
|
||||||
if (*p == '*') { /* `*' is current month */
|
|
||||||
*flags |= F_ISMONTH;
|
|
||||||
*endp = p+1;
|
|
||||||
return (tp->tm_mon + 1);
|
|
||||||
}
|
|
||||||
if (isdigit(*p)) {
|
|
||||||
val = strtol(p, &p, 10); /* if 0, it's failure */
|
|
||||||
for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
|
|
||||||
*endp = p;
|
|
||||||
return (val);
|
|
||||||
}
|
|
||||||
for (start = p; isalpha(*++p););
|
|
||||||
savech = *p;
|
|
||||||
*p = '\0';
|
|
||||||
if ((val = getmonth(start)) != 0)
|
|
||||||
*flags |= F_ISMONTH;
|
|
||||||
else if ((val = getday(start)) != 0)
|
|
||||||
*flags |= F_ISDAY;
|
|
||||||
else {
|
|
||||||
*p = savech;
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
|
|
||||||
*endp = p;
|
|
||||||
return (val);
|
|
||||||
}
|
|
||||||
|
|
||||||
char path[MAXPATHLEN + 1];
|
|
||||||
|
|
||||||
FILE *
|
|
||||||
opencal()
|
|
||||||
{
|
|
||||||
int fd, pdes[2];
|
|
||||||
|
|
||||||
/* open up calendar file as stdin */
|
|
||||||
if (!freopen("calendar", "r", stdin)) {
|
|
||||||
if (doall)
|
|
||||||
return (NULL);
|
|
||||||
errx(1, "no calendar file in current directory.");
|
|
||||||
}
|
|
||||||
if (pipe(pdes) < 0)
|
|
||||||
return (NULL);
|
|
||||||
switch (vfork()) {
|
|
||||||
case -1: /* error */
|
|
||||||
(void)close(pdes[0]);
|
|
||||||
(void)close(pdes[1]);
|
|
||||||
return (NULL);
|
|
||||||
case 0:
|
|
||||||
/* child -- stdin already setup, set stdout to pipe input */
|
|
||||||
if (pdes[1] != STDOUT_FILENO) {
|
|
||||||
(void)dup2(pdes[1], STDOUT_FILENO);
|
|
||||||
(void)close(pdes[1]);
|
|
||||||
}
|
|
||||||
(void)close(pdes[0]);
|
|
||||||
execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
|
|
||||||
(void)fprintf(stderr,
|
|
||||||
"calendar: execl: %s: %s.\n", _PATH_CPP, strerror(errno));
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
/* parent -- set stdin to pipe output */
|
|
||||||
(void)dup2(pdes[0], STDIN_FILENO);
|
|
||||||
(void)close(pdes[0]);
|
|
||||||
(void)close(pdes[1]);
|
|
||||||
|
|
||||||
/* not reading all calendar files, just set output to stdout */
|
|
||||||
if (!doall)
|
|
||||||
return (stdout);
|
|
||||||
|
|
||||||
/* set output to a temporary file, so if no output don't send mail */
|
|
||||||
(void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
|
|
||||||
if ((fd = mkstemp(path)) < 0)
|
|
||||||
return (NULL);
|
|
||||||
return (fdopen(fd, "w+"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
closecal(fp)
|
|
||||||
FILE *fp;
|
|
||||||
{
|
|
||||||
struct stat sbuf;
|
|
||||||
int nread, pdes[2], status;
|
|
||||||
char buf[1024];
|
|
||||||
|
|
||||||
if (!doall)
|
|
||||||
return;
|
|
||||||
|
|
||||||
(void)rewind(fp);
|
|
||||||
if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
|
|
||||||
goto done;
|
|
||||||
if (pipe(pdes) < 0)
|
|
||||||
goto done;
|
|
||||||
switch (vfork()) {
|
|
||||||
case -1: /* error */
|
|
||||||
(void)close(pdes[0]);
|
|
||||||
(void)close(pdes[1]);
|
|
||||||
goto done;
|
|
||||||
case 0:
|
|
||||||
/* child -- set stdin to pipe output */
|
|
||||||
if (pdes[0] != STDIN_FILENO) {
|
|
||||||
(void)dup2(pdes[0], STDIN_FILENO);
|
|
||||||
(void)close(pdes[0]);
|
|
||||||
}
|
|
||||||
(void)close(pdes[1]);
|
|
||||||
execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
|
|
||||||
"\"Reminder Service\"", "-f", "root", NULL);
|
|
||||||
(void)fprintf(stderr,
|
|
||||||
"calendar: %s: %s.\n", _PATH_SENDMAIL, strerror(errno));
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
/* parent -- write to pipe input */
|
|
||||||
(void)close(pdes[0]);
|
|
||||||
|
|
||||||
header[1].iov_base = header[3].iov_base = pw->pw_name;
|
|
||||||
header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
|
|
||||||
writev(pdes[1], header, 7);
|
|
||||||
while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
|
|
||||||
(void)write(pdes[1], buf, nread);
|
|
||||||
(void)close(pdes[1]);
|
|
||||||
done: (void)fclose(fp);
|
|
||||||
(void)unlink(path);
|
|
||||||
while (wait(&status) >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *months[] = {
|
|
||||||
"jan", "feb", "mar", "apr", "may", "jun",
|
|
||||||
"jul", "aug", "sep", "oct", "nov", "dec", NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
getmonth(s)
|
|
||||||
register char *s;
|
|
||||||
{
|
|
||||||
register char **p;
|
|
||||||
|
|
||||||
for (p = months; *p; ++p)
|
|
||||||
if (!strncasecmp(s, *p, 3))
|
|
||||||
return ((p - months) + 1);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *days[] = {
|
|
||||||
"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
getday(s)
|
|
||||||
register char *s;
|
|
||||||
{
|
|
||||||
register char **p;
|
|
||||||
|
|
||||||
for (p = days; *p; ++p)
|
|
||||||
if (!strncasecmp(s, *p, 3))
|
|
||||||
return ((p - days) + 1);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
(void)fprintf(stderr, "usage: calendar [-a]\n");
|
(void)fprintf(stderr,
|
||||||
|
"usage: calendar [-a] [-A days] [-B days] [-f calendarfile]\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
370
usr.bin/calendar/day.c
Normal file
370
usr.bin/calendar/day.c
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1989, 1993, 1994
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "pathnames.h"
|
||||||
|
#include "calendar.h"
|
||||||
|
|
||||||
|
struct tm *tp;
|
||||||
|
int *cumdays, offset, yrdays;
|
||||||
|
char dayname[10];
|
||||||
|
|
||||||
|
|
||||||
|
/* 1-based month, 0-based days, cumulative */
|
||||||
|
int daytab[][14] = {
|
||||||
|
{ 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
|
||||||
|
{ 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *days[] = {
|
||||||
|
"sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *months[] = {
|
||||||
|
"jan", "feb", "mar", "apr", "may", "jun",
|
||||||
|
"jul", "aug", "sep", "oct", "nov", "dec", NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
settime(now)
|
||||||
|
time_t now;
|
||||||
|
{
|
||||||
|
|
||||||
|
tp = localtime(&now);
|
||||||
|
if ( isleap(tp->tm_year + 1900) ) {
|
||||||
|
yrdays = 366;
|
||||||
|
cumdays = daytab[1];
|
||||||
|
} else {
|
||||||
|
yrdays = 365;
|
||||||
|
cumdays = daytab[0];
|
||||||
|
}
|
||||||
|
/* Friday displays Monday's events */
|
||||||
|
offset = tp->tm_wday == 5 ? 3 : 1;
|
||||||
|
header[5].iov_base = dayname;
|
||||||
|
header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert Day[/Month][/Year] into unix time (since 1970)
|
||||||
|
* Day: tow digits, Month: two digits, Year: digits
|
||||||
|
*/
|
||||||
|
time_t Mktime (date)
|
||||||
|
char *date;
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
int len;
|
||||||
|
struct tm tm;
|
||||||
|
|
||||||
|
(void)time(&t);
|
||||||
|
tp = localtime(&t);
|
||||||
|
|
||||||
|
len = strlen(date);
|
||||||
|
tm.tm_sec = 0;
|
||||||
|
tm.tm_min = 0;
|
||||||
|
tm.tm_hour = 0;
|
||||||
|
tm.tm_mday = tp->tm_mday;
|
||||||
|
tm.tm_mon = tp->tm_mon;
|
||||||
|
tm.tm_year = tp->tm_year;
|
||||||
|
|
||||||
|
|
||||||
|
/* day */
|
||||||
|
*(date+2) = NULL;
|
||||||
|
tm.tm_mday = atoi(date);
|
||||||
|
|
||||||
|
/* month */
|
||||||
|
if (len >= 4) {
|
||||||
|
*(date+5) = NULL;
|
||||||
|
tm.tm_mon = atoi(date+3) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Year */
|
||||||
|
if (len >= 7) {
|
||||||
|
tm.tm_year = atoi(date+6);
|
||||||
|
|
||||||
|
/* tm_year up 1900 ... */
|
||||||
|
if (tm.tm_year > 1900)
|
||||||
|
tm.tm_year -= 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
printf("Mktime: %d %d %d %s\n", (int)mktime(&tm), (int)t, len,
|
||||||
|
asctime(&tm));
|
||||||
|
#endif
|
||||||
|
return(mktime(&tm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Possible date formats include any combination of:
|
||||||
|
* 3-charmonth (January, Jan, Jan)
|
||||||
|
* 3-charweekday (Friday, Monday, mon.)
|
||||||
|
* numeric month or day (1, 2, 04)
|
||||||
|
*
|
||||||
|
* Any character may separate them, or they may not be separated. Any line,
|
||||||
|
* following a line that is matched, that starts with "whitespace", is shown
|
||||||
|
* along with the matched line.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
isnow(endp)
|
||||||
|
char *endp;
|
||||||
|
{
|
||||||
|
int day, flags, month, v1, v2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CONVENTION
|
||||||
|
*
|
||||||
|
* Month: 1-12
|
||||||
|
* Monthname: Jan .. Dec
|
||||||
|
* Day: 1-31
|
||||||
|
* Weekday: Mon-Sun
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
|
||||||
|
/* read first field */
|
||||||
|
/* didn't recognize anything, skip it */
|
||||||
|
if (!(v1 = getfield(endp, &endp, &flags)))
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
/* Easter or Easter depending days */
|
||||||
|
if (flags & F_EASTER)
|
||||||
|
day = v1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1. {Weekday,Day} XYZ ...
|
||||||
|
*
|
||||||
|
* where Day is > 12
|
||||||
|
*/
|
||||||
|
else if (flags & F_ISDAY || v1 > 12) {
|
||||||
|
|
||||||
|
/* found a day; day: 1-31 or weekday: 1-7 */
|
||||||
|
day = v1;
|
||||||
|
|
||||||
|
/* {Day,Weekday} {Month,Monthname} ... */
|
||||||
|
/* if no recognizable month, assume just a day alone
|
||||||
|
* in other words, find month or use current month */
|
||||||
|
if (!(month = getfield(endp, &endp, &flags)))
|
||||||
|
month = tp->tm_mon + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. {Monthname} XYZ ... */
|
||||||
|
else if (flags & F_ISMONTH) {
|
||||||
|
month = v1;
|
||||||
|
|
||||||
|
/* Monthname {day,weekday} */
|
||||||
|
/* if no recognizable day, assume the first day in month */
|
||||||
|
if (!(day = getfield(endp, &endp, &flags)))
|
||||||
|
day = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hm ... */
|
||||||
|
else {
|
||||||
|
v2 = getfield(endp, &endp, &flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* {Day} {Monthname} ...
|
||||||
|
* where Day <= 12
|
||||||
|
*/
|
||||||
|
if (flags & F_ISMONTH) {
|
||||||
|
day = v1;
|
||||||
|
month = v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* {Month} {Weekday,Day} ... */
|
||||||
|
else {
|
||||||
|
/* F_ISDAY set, v2 > 12, or no way to tell */
|
||||||
|
month = v1;
|
||||||
|
/* if no recognizable day, assume the first */
|
||||||
|
day = v2 ? v2 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert Weekday into *next* Day,
|
||||||
|
* e.g.: 'Sunday' -> 22
|
||||||
|
* 'SunayLast' -> ??
|
||||||
|
*/
|
||||||
|
if (flags & F_ISDAY) {
|
||||||
|
#if DEBUG
|
||||||
|
fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* variable weekday, SundayLast, MondayFirst ... */
|
||||||
|
if (day < 0 || day >= 10) {
|
||||||
|
|
||||||
|
/* negative offset; last, -4 .. -1 */
|
||||||
|
if (day < 0) {
|
||||||
|
v1 = day/10 - 1; /* offset -4 ... -1 */
|
||||||
|
day = 10 + (day % 10); /* day 1 ... 7 */
|
||||||
|
|
||||||
|
/* day, eg '22th' */
|
||||||
|
v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
|
||||||
|
|
||||||
|
/* (month length - day) / 7 + 1 */
|
||||||
|
if (((int)((cumdays[month+1] -
|
||||||
|
cumdays[month] - v2) / 7) + 1) == -v1)
|
||||||
|
/* bingo ! */
|
||||||
|
day = v2;
|
||||||
|
|
||||||
|
/* set to yesterday */
|
||||||
|
else
|
||||||
|
day = tp->tm_mday - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first, second ... +1 ... +5 */
|
||||||
|
else {
|
||||||
|
v1 = day/10; /* offset: +1 (first Sunday) ... */
|
||||||
|
day = day % 10;
|
||||||
|
|
||||||
|
/* day, eg '22th' */
|
||||||
|
v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
|
||||||
|
|
||||||
|
/* Hurrah! matched */
|
||||||
|
if ( ((v2 - 1 + 7) / 7) == v1 )
|
||||||
|
day = v2;
|
||||||
|
|
||||||
|
/* set to yesterday */
|
||||||
|
else
|
||||||
|
day = tp->tm_mday - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wired */
|
||||||
|
else {
|
||||||
|
day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
fprintf(stderr, "day2: yday %d %d\n", day, tp->tm_yday);
|
||||||
|
#endif
|
||||||
|
if (!(flags & F_EASTER))
|
||||||
|
day = cumdays[month] + day;
|
||||||
|
|
||||||
|
/* if today or today + offset days */
|
||||||
|
if (day >= tp->tm_yday - f_dayBefore &&
|
||||||
|
day <= tp->tm_yday + offset + f_dayAfter)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
/* if number of days left in this year + days to event in next year */
|
||||||
|
if (yrdays - tp->tm_yday + day <= offset + f_dayAfter ||
|
||||||
|
/* a year backward, eg. 6 Jan and 10 days before -> 27. Dec */
|
||||||
|
tp->tm_yday + day - f_dayBefore < 0
|
||||||
|
)
|
||||||
|
return (1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getmonth(s)
|
||||||
|
register char *s;
|
||||||
|
{
|
||||||
|
register char **p;
|
||||||
|
|
||||||
|
for (p = months; *p; ++p)
|
||||||
|
if (!strncasecmp(s, *p, 3))
|
||||||
|
return ((p - months) + 1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getday(s)
|
||||||
|
register char *s;
|
||||||
|
{
|
||||||
|
register char **p;
|
||||||
|
|
||||||
|
for (p = days; *p; ++p)
|
||||||
|
if (!strncasecmp(s, *p, 3))
|
||||||
|
return ((p - days) + 1);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return offset for variable weekdays
|
||||||
|
* -1 -> last weekday in month
|
||||||
|
* +1 -> first weekday in month
|
||||||
|
* ... etc ...
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
getdayvar(s)
|
||||||
|
register char *s;
|
||||||
|
{
|
||||||
|
register int offset;
|
||||||
|
|
||||||
|
|
||||||
|
offset = strlen(s);
|
||||||
|
|
||||||
|
|
||||||
|
/* Sun+1 or Wednesday-2
|
||||||
|
* ^ ^ */
|
||||||
|
|
||||||
|
/* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */
|
||||||
|
switch(*(s + offset - 2)) {
|
||||||
|
case '-':
|
||||||
|
return(-(atoi(s + offset - 1)));
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
return(atoi(s + offset - 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* some aliases: last, first, second, third, fourth
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* last */
|
||||||
|
if (offset > 4 && !strcasecmp(s + offset - 4, "last"))
|
||||||
|
return(-1);
|
||||||
|
else if (offset > 5 && !strcasecmp(s + offset - 5, "first"))
|
||||||
|
return(+1);
|
||||||
|
else if (offset > 6 && !strcasecmp(s + offset - 6, "second"))
|
||||||
|
return(+2);
|
||||||
|
else if (offset > 5 && !strcasecmp(s + offset - 5, "third"))
|
||||||
|
return(+3);
|
||||||
|
else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth"))
|
||||||
|
return(+4);
|
||||||
|
|
||||||
|
|
||||||
|
/* no offset detected */
|
||||||
|
return(0);
|
||||||
|
}
|
271
usr.bin/calendar/io.c
Normal file
271
usr.bin/calendar/io.c
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1989, 1993, 1994
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef lint
|
||||||
|
static char copyright[] =
|
||||||
|
"@(#) Copyright (c) 1989, 1993\n\
|
||||||
|
The Regents of the University of California. All rights reserved.\n";
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#ifndef lint
|
||||||
|
static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
|
||||||
|
#endif /* not lint */
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "pathnames.h"
|
||||||
|
#include "calendar.h"
|
||||||
|
|
||||||
|
|
||||||
|
char *calendarFile = "calendar"; /* default calendar file */
|
||||||
|
char *calendarHome = ".calendar"; /* HOME */
|
||||||
|
char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */
|
||||||
|
|
||||||
|
struct iovec header[] = {
|
||||||
|
"From: ", 6,
|
||||||
|
NULL, 0,
|
||||||
|
" (Reminder Service)\nTo: ", 24,
|
||||||
|
NULL, 0,
|
||||||
|
"\nSubject: ", 10,
|
||||||
|
NULL, 0,
|
||||||
|
"'s Calendar\nPrecedence: bulk\n\n", 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
cal()
|
||||||
|
{
|
||||||
|
register int printing;
|
||||||
|
register char *p;
|
||||||
|
FILE *fp;
|
||||||
|
int ch;
|
||||||
|
char buf[2048 + 1];
|
||||||
|
|
||||||
|
if ((fp = opencal()) == NULL)
|
||||||
|
return;
|
||||||
|
for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
|
||||||
|
if ((p = strchr(buf, '\n')) != NULL)
|
||||||
|
*p = '\0';
|
||||||
|
else
|
||||||
|
while ((ch = getchar()) != '\n' && ch != EOF);
|
||||||
|
if (buf[0] == '\0')
|
||||||
|
continue;
|
||||||
|
if (buf[0] != '\t')
|
||||||
|
printing = isnow(buf) ? 1 : 0;
|
||||||
|
if (printing)
|
||||||
|
(void)fprintf(fp, "%s\n", buf);
|
||||||
|
}
|
||||||
|
closecal(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
getfield(p, endp, flags)
|
||||||
|
char *p, **endp;
|
||||||
|
int *flags;
|
||||||
|
{
|
||||||
|
int val, var;
|
||||||
|
char *start, savech;
|
||||||
|
|
||||||
|
for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
|
||||||
|
if (*p == '*') { /* `*' is current month */
|
||||||
|
*flags |= F_ISMONTH;
|
||||||
|
*endp = p+1;
|
||||||
|
return (tp->tm_mon + 1);
|
||||||
|
}
|
||||||
|
if (isdigit(*p)) {
|
||||||
|
val = strtol(p, &p, 10); /* if 0, it's failure */
|
||||||
|
for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
|
||||||
|
*endp = p;
|
||||||
|
return (val);
|
||||||
|
}
|
||||||
|
for (start = p; isalpha(*++p););
|
||||||
|
|
||||||
|
/* Sunday-1 */
|
||||||
|
if (*p == '+' || *p == '-')
|
||||||
|
for(; isdigit(*++p););
|
||||||
|
|
||||||
|
savech = *p;
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
/* Month */
|
||||||
|
if ((val = getmonth(start)) != 0)
|
||||||
|
*flags |= F_ISMONTH;
|
||||||
|
|
||||||
|
/* Day */
|
||||||
|
else if ((val = getday(start)) != 0) {
|
||||||
|
*flags |= F_ISDAY;
|
||||||
|
|
||||||
|
/* variable weekday */
|
||||||
|
if ((var = getdayvar(start)) != 0) {
|
||||||
|
if (var <=5 && var >= -4)
|
||||||
|
val += var * 10;
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("var: %d\n", var);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Easter */
|
||||||
|
else if ((val = geteaster(start, tp->tm_year + 1900)) != 0)
|
||||||
|
*flags |= F_EASTER;
|
||||||
|
|
||||||
|
/* undefined rest */
|
||||||
|
else {
|
||||||
|
*p = savech;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p);
|
||||||
|
*endp = p;
|
||||||
|
return (val);
|
||||||
|
}
|
||||||
|
|
||||||
|
char path[MAXPATHLEN + 1];
|
||||||
|
|
||||||
|
FILE *
|
||||||
|
opencal()
|
||||||
|
{
|
||||||
|
int fd, pdes[2];
|
||||||
|
struct stat sbuf;
|
||||||
|
|
||||||
|
/* open up calendar file as stdin */
|
||||||
|
if (!freopen(calendarFile, "r", stdin)) {
|
||||||
|
if (doall) {
|
||||||
|
if (chdir(calendarHome) != 0)
|
||||||
|
return (NULL);
|
||||||
|
if (stat(calendarNoMail, &sbuf) == 0)
|
||||||
|
return (NULL);
|
||||||
|
if (!freopen(calendarFile, "r", stdin))
|
||||||
|
return (NULL);
|
||||||
|
} else {
|
||||||
|
chdir(getenv("HOME"));
|
||||||
|
if (!(chdir(calendarHome) == 0 &&
|
||||||
|
freopen(calendarFile, "r", stdin)))
|
||||||
|
errx(1, "no calendar file: ``%s'' or ``~/%s/%s\n", calendarFile, calendarHome, calendarFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pipe(pdes) < 0)
|
||||||
|
return (NULL);
|
||||||
|
switch (vfork()) {
|
||||||
|
case -1: /* error */
|
||||||
|
(void)close(pdes[0]);
|
||||||
|
(void)close(pdes[1]);
|
||||||
|
return (NULL);
|
||||||
|
case 0:
|
||||||
|
/* child -- stdin already setup, set stdout to pipe input */
|
||||||
|
if (pdes[1] != STDOUT_FILENO) {
|
||||||
|
(void)dup2(pdes[1], STDOUT_FILENO);
|
||||||
|
(void)close(pdes[1]);
|
||||||
|
}
|
||||||
|
(void)close(pdes[0]);
|
||||||
|
execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
|
||||||
|
(void)fprintf(stderr,
|
||||||
|
"calendar: execl: %s: %s.\n", _PATH_CPP, strerror(errno));
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
/* parent -- set stdin to pipe output */
|
||||||
|
(void)dup2(pdes[0], STDIN_FILENO);
|
||||||
|
(void)close(pdes[0]);
|
||||||
|
(void)close(pdes[1]);
|
||||||
|
|
||||||
|
/* not reading all calendar files, just set output to stdout */
|
||||||
|
if (!doall)
|
||||||
|
return (stdout);
|
||||||
|
|
||||||
|
/* set output to a temporary file, so if no output don't send mail */
|
||||||
|
(void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
|
||||||
|
if ((fd = mkstemp(path)) < 0)
|
||||||
|
return (NULL);
|
||||||
|
return (fdopen(fd, "w+"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
closecal(fp)
|
||||||
|
FILE *fp;
|
||||||
|
{
|
||||||
|
struct stat sbuf;
|
||||||
|
int nread, pdes[2], status;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
if (!doall)
|
||||||
|
return;
|
||||||
|
|
||||||
|
(void)rewind(fp);
|
||||||
|
if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
|
||||||
|
goto done;
|
||||||
|
if (pipe(pdes) < 0)
|
||||||
|
goto done;
|
||||||
|
switch (vfork()) {
|
||||||
|
case -1: /* error */
|
||||||
|
(void)close(pdes[0]);
|
||||||
|
(void)close(pdes[1]);
|
||||||
|
goto done;
|
||||||
|
case 0:
|
||||||
|
/* child -- set stdin to pipe output */
|
||||||
|
if (pdes[0] != STDIN_FILENO) {
|
||||||
|
(void)dup2(pdes[0], STDIN_FILENO);
|
||||||
|
(void)close(pdes[0]);
|
||||||
|
}
|
||||||
|
(void)close(pdes[1]);
|
||||||
|
execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
|
||||||
|
"\"Reminder Service\"", "-f", "root", NULL);
|
||||||
|
(void)fprintf(stderr,
|
||||||
|
"calendar: %s: %s.\n", _PATH_SENDMAIL, strerror(errno));
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
/* parent -- write to pipe input */
|
||||||
|
(void)close(pdes[0]);
|
||||||
|
|
||||||
|
header[1].iov_base = header[3].iov_base = pw->pw_name;
|
||||||
|
header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
|
||||||
|
writev(pdes[1], header, 7);
|
||||||
|
while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
|
||||||
|
(void)write(pdes[1], buf, nread);
|
||||||
|
(void)close(pdes[1]);
|
||||||
|
done: (void)fclose(fp);
|
||||||
|
(void)unlink(path);
|
||||||
|
while (wait(&status) >= 0);
|
||||||
|
}
|
||||||
|
|
94
usr.bin/calendar/ostern.c
Normal file
94
usr.bin/calendar/ostern.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1995 Wolfram Schneider. Public domain.
|
||||||
|
*
|
||||||
|
* $Id: ostern.c,v 1.2 1996/02/01 13:05:12 wosch Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* return year day for Easter */
|
||||||
|
|
||||||
|
int easter (year)
|
||||||
|
int year; /* 0 ... abcd, NOT since 1900 */
|
||||||
|
{
|
||||||
|
|
||||||
|
int e_a, e_b, e_c, e_d, e_e,e_f, e_g, e_h, e_i, e_k,
|
||||||
|
e_l, e_m, e_n, e_p, e_q;
|
||||||
|
|
||||||
|
/* silly, but it works */
|
||||||
|
e_a = year % 19;
|
||||||
|
e_b = year / 100;
|
||||||
|
e_c = year % 100;
|
||||||
|
|
||||||
|
e_d = e_b / 4;
|
||||||
|
e_e = e_b % 4;
|
||||||
|
e_f = (e_b + 8) / 25;
|
||||||
|
e_g = (e_b + 1 - e_f) / 3;
|
||||||
|
e_h = ((19 * e_a) + 15 + e_b - (e_d + e_g)) % 30;
|
||||||
|
e_i = e_c / 4;
|
||||||
|
e_k = e_c % 4;
|
||||||
|
e_l = (32 + 2 * e_e + 2 * e_i - (e_h + e_k)) % 7;
|
||||||
|
e_m = (e_a + 11 * e_h + 22 * e_l) / 451;
|
||||||
|
e_n = (e_h + e_l + 114 - (7 * e_m)) / 31;
|
||||||
|
e_p = (e_h + e_l + 114 - (7 * e_m)) % 31;
|
||||||
|
e_p = e_p + 1;
|
||||||
|
|
||||||
|
e_q = 31 + 28;
|
||||||
|
|
||||||
|
if (e_k == 0 && e_c != 0)
|
||||||
|
e_q += 1;
|
||||||
|
|
||||||
|
if (e_n == 4)
|
||||||
|
e_q += 31;
|
||||||
|
|
||||||
|
e_q += e_p;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", e_a , e_b , e_c , e_d , e_e , e_f , e_g , e_h , e_i , e_k , e_l , e_m , e_n , e_p , e_q);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (e_q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return year day for Easter or easter depending days
|
||||||
|
* Match: Easter([+-][0-9]+)?
|
||||||
|
* e.g: Easter-2 is Good Friday (2 days before Easter)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
geteaster(s, year)
|
||||||
|
char *s;
|
||||||
|
int year;
|
||||||
|
{
|
||||||
|
register int offset = 0;
|
||||||
|
|
||||||
|
#define EASTER "easter"
|
||||||
|
#define EASTERNAMELEN (sizeof(EASTER) - 1)
|
||||||
|
|
||||||
|
/* no easter */
|
||||||
|
if (strncasecmp(s, EASTER, EASTERNAMELEN))
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
printf("%s %d %d\n", s, year, EASTERNAMELEN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Easter+1 or Easter-2
|
||||||
|
* ^ ^ */
|
||||||
|
|
||||||
|
switch(*(s + EASTERNAMELEN)) {
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
offset = -(atoi(s + EASTERNAMELEN + 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
offset = atoi(s + EASTERNAMELEN + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (easter(year) + offset);
|
||||||
|
}
|
@ -36,5 +36,6 @@
|
|||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
|
|
||||||
#define _PATH_CPP "/usr/bin/cpp"
|
#define _PATH_CPP "/usr/bin/cpp"
|
||||||
|
|
||||||
/* XXX -- fix when cpp parses arguments rationally */
|
/* XXX -- fix when cpp parses arguments rationally */
|
||||||
#define _PATH_INCLUDE "-I/usr/share/calendar"
|
#define _PATH_INCLUDE "-I/usr/share/calendar"
|
||||||
|
Loading…
Reference in New Issue
Block a user