version 1.4, 1996/12/04 09:06:00 |
version 1.5, 1996/12/05 06:04:38 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* $NetBSD: calendar.c,v 1.8 1995/09/02 05:38:38 jtc Exp $ */ |
|
|
|
/* |
/* |
* Copyright (c) 1989, 1993, 1994 |
* Copyright (c) 1989, 1993, 1994 |
|
|
*/ |
*/ |
|
|
#ifndef lint |
#ifndef lint |
static char copyright[] = |
static const char copyright[] = |
"@(#) Copyright (c) 1989, 1993\n\ |
"@(#) Copyright (c) 1989, 1993\n\ |
The Regents of the University of California. All rights reserved.\n"; |
The Regents of the University of California. All rights reserved.\n"; |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
#ifndef lint |
#ifndef lint |
#if 0 |
#if 0 |
static char sccsid[] = "@(#)calendar.c 8.4 (Berkeley) 1/7/95"; |
static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; |
#endif |
#else |
static char rcsid[] = "$OpenBSD$"; |
static char rcsid[] = "$OpenBSD$"; |
|
#endif |
#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 <err.h> |
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <locale.h> |
#include <pwd.h> |
#include <pwd.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <tzfile.h> |
#include <time.h> |
#include <unistd.h> |
#include <unistd.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)); |
|
|
|
int |
int |
main(argc, argv) |
main(argc, argv) |
int argc; |
int argc; |
char *argv[]; |
char *argv[]; |
{ |
{ |
extern int optind; |
|
int ch; |
int ch; |
char *caldir; |
char *caldir; |
|
|
while ((ch = getopt(argc, argv, "-a")) != EOF) |
(void) setlocale(LC_ALL, ""); |
|
|
|
while ((ch = getopt(argc, argv, "?-af:t:A:B:")) != EOF) |
switch (ch) { |
switch (ch) { |
case '-': /* backward contemptible */ |
case '-': /* backward contemptible */ |
case 'a': |
case 'a': |
if (getuid()) { |
if (getuid()) |
errno = EPERM; |
errx(1, strerror(EPERM)); |
err(1, NULL); |
|
} |
|
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(); |
|
|
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); |
|
|
(void)seteuid(0); |
(void)seteuid(0); |
} |
} |
else if ((caldir = getenv("CALENDAR_DIR")) != NULL) { |
else if ((caldir = getenv("CALENDAR_DIR")) != NULL) { |
if(!chdir(caldir)) |
if(!chdir(caldir)) |
cal(); |
cal(); |
} else |
} else |
cal(); |
cal(); |
|
|
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 |
void |
settime() |
|
{ |
|
time_t now; |
|
|
|
(void)time(&now); |
|
tp = localtime(&now); |
|
if (isleap(tp->tm_year + 1900)) { |
|
yrdays = DAYSPERLYEAR; |
|
cumdays = daytab[1]; |
|
} else { |
|
yrdays = DAYSPERNYEAR; |
|
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; |
|
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]; |
|
|
|
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."); |
|
} |
|
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]); |
|
(void)setuid(geteuid()); |
|
(void)setgid(getegid()); |
|
execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL); |
|
warn("execl: %s", _PATH_CPP); |
|
_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]); |
|
(void)setuid(geteuid()); |
|
(void)setgid(getegid()); |
|
execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F", |
|
"\"Reminder Service\"", "-f", "root", NULL); |
|
warn("execl: %s", _PATH_SENDMAIL); |
|
_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 |
|
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); |
} |
} |