version 1.21, 2002/12/18 20:34:44 |
version 1.46, 2017/08/21 21:41:13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* 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. Neither the name of the University nor the names of its contributors |
* 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 |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* without specific prior written permission. |
* |
* |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
#ifndef lint |
|
static const char copyright[] = |
|
"@(#) Copyright (c) 1989, 1993\n\ |
|
The Regents of the University of California. All rights reserved.\n"; |
|
#endif /* not lint */ |
|
|
|
#ifndef lint |
|
#if 0 |
|
static const char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94"; |
|
#else |
|
static char rcsid[] = "$OpenBSD$"; |
|
#endif |
|
#endif /* not lint */ |
|
|
|
#include <sys/param.h> |
|
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <sys/time.h> |
#include <sys/time.h> |
#include <sys/types.h> |
#include <sys/types.h> |
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <tzfile.h> |
|
#include <unistd.h> |
#include <unistd.h> |
|
#include <limits.h> |
|
|
#include "pathnames.h" |
#include "pathnames.h" |
#include "calendar.h" |
#include "calendar.h" |
|
|
|
|
struct iovec header[] = { |
struct iovec header[] = { |
{"From: ", 6}, |
{ "From: ", 6 }, |
{NULL, 0}, |
{ NULL, 0 }, |
{" (Reminder Service)\nTo: ", 24}, |
{ " (Reminder Service)\nTo: ", 24 }, |
{NULL, 0}, |
{ NULL, 0 }, |
{"\nSubject: ", 10}, |
{ "\nSubject: ", 10 }, |
{NULL, 0}, |
{ NULL, 0 }, |
{"'s Calendar\nPrecedence: bulk\n\n", 30}, |
{ "'s Calendar\nPrecedence: bulk\n", 29 }, |
|
{ "Auto-Submitted: auto-generated\n\n", 32 }, |
}; |
}; |
|
|
|
|
void |
void |
cal(void) |
cal(void) |
{ |
{ |
int printing; |
int ch, l, i, bodun = 0, bodun_maybe = 0, var, printing; |
char *p; |
|
FILE *fp; |
|
int ch, l, i, bodun = 0, bodun_maybe = 0; |
|
int var; |
|
char buf[2048 + 1], *prefix = NULL; |
|
struct event *events, *cur_evt, *ev1, *tmp; |
struct event *events, *cur_evt, *ev1, *tmp; |
|
char buf[2048 + 1], *prefix = NULL, *p; |
struct match *m; |
struct match *m; |
|
FILE *fp; |
|
|
events = NULL; |
events = NULL; |
cur_evt = NULL; |
cur_evt = NULL; |
|
|
if (strncmp(buf, "LANG=", 5) == 0) { |
if (strncmp(buf, "LANG=", 5) == 0) { |
(void) setlocale(LC_ALL, buf + 5); |
(void) setlocale(LC_ALL, buf + 5); |
setnnames(); |
setnnames(); |
if (!strcmp(buf + 5, "ru_RU.KOI8-R") || |
if (!strcmp(buf + 5, "ru_RU.UTF-8") || |
!strcmp(buf + 5, "uk_UA.KOI8-U") || |
!strcmp(buf + 5, "uk_UA.UTF-8") || |
!strcmp(buf + 5, "by_BY.KOI8-B")) { |
!strcmp(buf + 5, "by_BY.UTF-8")) { |
bodun_maybe++; |
bodun_maybe++; |
bodun = 0; |
bodun = 0; |
if (prefix) |
free(prefix); |
free(prefix); |
|
prefix = NULL; |
prefix = NULL; |
} else |
} else |
bodun_maybe = 0; |
bodun_maybe = 0; |
continue; |
continue; |
} |
} else if (strncmp(buf, "CALENDAR=", 9) == 0) { |
if (bodun_maybe && strncmp(buf, "BODUN=", 6) == 0) { |
char *ep; |
|
|
|
if (buf[9] == '\0') |
|
calendar = 0; |
|
else if (!strcasecmp(buf + 9, "julian")) { |
|
calendar = JULIAN; |
|
errno = 0; |
|
julian = strtoul(buf + 14, &ep, 10); |
|
if (buf[0] == '\0' || *ep != '\0') |
|
julian = 13; |
|
if ((errno == ERANGE && julian == ULONG_MAX) || |
|
julian > 14) |
|
errx(1, "Julian calendar offset is too large"); |
|
} else if (!strcasecmp(buf + 9, "gregorian")) |
|
calendar = GREGORIAN; |
|
else if (!strcasecmp(buf + 9, "lunar")) |
|
calendar = LUNAR; |
|
} else if (bodun_maybe && strncmp(buf, "BODUN=", 6) == 0) { |
bodun++; |
bodun++; |
if (prefix) |
free(prefix); |
free(prefix); |
|
if ((prefix = strdup(buf + 6)) == NULL) |
if ((prefix = strdup(buf + 6)) == NULL) |
err(1, NULL); |
err(1, NULL); |
|
continue; |
} |
} |
/* User defined names for special events */ |
/* User defined names for special events */ |
if ((p = strchr(buf, '='))) { |
if ((p = strchr(buf, '='))) { |
for (i = 0; i < NUMEV; i++) { |
for (i = 0; i < NUMEV; i++) { |
if (strncasecmp(buf, spev[i].name, spev[i].nlen) == 0 && |
if (strncasecmp(buf, spev[i].name, |
(p - buf == spev[i].nlen) && buf[spev[i].nlen + 1]) { |
spev[i].nlen) == 0 && |
p++; |
(p - buf == spev[i].nlen) && |
if (spev[i].uname != NULL) |
buf[spev[i].nlen + 1]) { |
|
p++; |
free(spev[i].uname); |
free(spev[i].uname); |
if ((spev[i].uname = strdup(p)) == NULL) |
if ((spev[i].uname = strdup(p)) == NULL) |
err(1, NULL); |
err(1, NULL); |
spev[i].ulen = strlen(p); |
spev[i].ulen = strlen(p); |
i = NUMEV + 1; |
i = NUMEV + 1; |
|
} |
} |
} |
} |
if (i > NUMEV) |
if (i > NUMEV) |
continue; |
continue; |
|
} |
} |
if (buf[0] != '\t') { |
if (buf[0] != '\t') { |
printing = (m = isnow(buf, bodun)) ? 1 : 0; |
printing = (m = isnow(buf, bodun)) ? 1 : 0; |
|
|
var = 0; |
var = 0; |
if (printing) { |
if (printing) { |
struct match *foo; |
struct match *foo; |
|
|
ev1 = NULL; |
ev1 = NULL; |
while (m) { |
while (m) { |
cur_evt = (struct event *) malloc(sizeof(struct event)); |
cur_evt = malloc(sizeof(struct event)); |
if (cur_evt == NULL) |
if (cur_evt == NULL) |
err(1, NULL); |
|
|
|
cur_evt->when = m->when; |
|
snprintf(cur_evt->print_date, |
|
sizeof(cur_evt->print_date), "%s%c", |
|
m->print_date, (var + m->var) ? '*' : ' '); |
|
if (ev1) { |
|
cur_evt->desc = ev1->desc; |
|
cur_evt->ldesc = NULL; |
|
} else { |
|
if (m->bodun && prefix) { |
|
int l1 = strlen(prefix); |
|
int l2 = strlen(p); |
|
if ((cur_evt->ldesc = |
|
malloc(l1 + l2 + 2)) == NULL) |
|
err(1, "malloc"); |
|
sprintf(cur_evt->ldesc, |
|
"\t%s %s", prefix, p + 1); |
|
} else if ((cur_evt->ldesc = |
|
strdup(p)) == NULL) |
|
err(1, NULL); |
err(1, NULL); |
cur_evt->desc = &(cur_evt->ldesc); |
|
ev1 = cur_evt; |
cur_evt->when = m->when; |
|
snprintf(cur_evt->print_date, |
|
sizeof(cur_evt->print_date), "%s%c", |
|
m->print_date, (var + m->var) ? '*' : ' '); |
|
if (ev1) { |
|
cur_evt->desc = ev1->desc; |
|
cur_evt->ldesc = NULL; |
|
} else { |
|
if (m->bodun && prefix) { |
|
if (asprintf(&cur_evt->ldesc, |
|
"\t%s %s", prefix, |
|
p + 1) == -1) |
|
err(1, NULL); |
|
} else if ((cur_evt->ldesc = |
|
strdup(p)) == NULL) |
|
err(1, NULL); |
|
cur_evt->desc = &(cur_evt->ldesc); |
|
ev1 = cur_evt; |
|
} |
|
insert(&events, cur_evt); |
|
foo = m; |
|
m = m->next; |
|
free(foo); |
} |
} |
insert(&events, cur_evt); |
|
foo = m; |
|
m = m->next; |
|
free(foo); |
|
} |
|
} |
} |
} |
} else if (printing) { |
else if (printing) { |
if (asprintf(&p, "%s\n%s", ev1->ldesc, |
if ((ev1->ldesc = realloc(ev1->ldesc, |
buf) == -1) |
(2 + strlen(ev1->ldesc) + strlen(buf)))) == NULL) |
|
err(1, NULL); |
err(1, NULL); |
strcat(ev1->ldesc, "\n"); |
free(ev1->ldesc); |
strcat(ev1->ldesc, buf); |
ev1->ldesc = p; |
} |
} |
} |
} |
tmp = events; |
tmp = events; |
|
|
tmp = events; |
tmp = events; |
while (tmp) { |
while (tmp) { |
events = tmp; |
events = tmp; |
if (tmp->ldesc) |
free(tmp->ldesc); |
free(tmp->ldesc); |
|
tmp = tmp->next; |
tmp = tmp->next; |
free(events); |
free(events); |
} |
} |
|
|
} |
} |
|
|
int |
int |
getfield(p, endp, flags) |
getfield(char *p, char **endp, int *flags) |
char *p, **endp; |
|
int *flags; |
|
{ |
{ |
int val, var, i; |
int val, var, i; |
char *start, savech; |
char *start, savech; |
|
|
for (; !isdigit(*p) && !isalpha(*p) && *p != '*' && *p != '\t'; ++p) |
for (; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p) && |
|
*p != '*' && *p != '\t'; ++p) |
; |
; |
if (*p == '*') { /* `*' is every month */ |
if (*p == '*') { /* `*' is every month */ |
*flags |= F_ISMONTH; |
*flags |= F_ISMONTH; |
*endp = p+1; |
*endp = p+1; |
return (-1); /* means 'every month' */ |
return (-1); /* means 'every month' */ |
} |
} |
if (isdigit(*p)) { |
if (isdigit((unsigned char)*p)) { |
val = strtol(p, &p, 10); /* if 0, it's failure */ |
val = strtol(p, &p, 10); /* if 0, it's failure */ |
for (; !isdigit(*p) && !isalpha(*p) && *p != '*'; ++p) |
for (; !isdigit((unsigned char)*p) && |
|
!isalpha((unsigned char)*p) && *p != '*'; ++p) |
; |
; |
*endp = p; |
*endp = p; |
return (val); |
return (val); |
} |
} |
for (start = p; isalpha(*++p);) |
for (start = p; isalpha((unsigned char)*++p);) |
; |
; |
|
|
/* Sunday-1 */ |
/* Sunday-1 */ |
if (*p == '+' || *p == '-') |
if (*p == '+' || *p == '-') |
for(; isdigit(*++p);) |
for(; isdigit((unsigned char)*++p); ) |
; |
; |
|
|
savech = *p; |
savech = *p; |
*p = '\0'; |
*p = '\0'; |
|
|
|
|
/* Day */ |
/* Day */ |
else if ((val = getday(start)) != 0) { |
else if ((val = getday(start)) != 0) { |
*flags |= F_ISDAY; |
*flags |= F_ISDAY; |
|
|
/* variable weekday */ |
/* variable weekday */ |
if ((var = getdayvar(start)) != 0) { |
if ((var = getdayvar(start)) != 0) { |
if (var <= 5 && var >= -4) |
if (var <= 5 && var >= -4) |
val += var * 10; |
val += var * 10; |
#ifdef DEBUG |
#ifdef DEBUG |
printf("var: %d\n", var); |
printf("var: %d\n", var); |
#endif |
#endif |
} |
} |
} |
} |
|
|
/* Try specials (Easter, Paskha, ...) */ |
/* Try specials (Easter, Paskha, ...) */ |
|
|
} |
} |
} |
} |
if (i > NUMEV) { |
if (i > NUMEV) { |
switch(*start) { |
const char *errstr; |
|
|
|
switch (*start) { |
case '-': |
case '-': |
case '+': |
case '+': |
var = atoi(start); |
var = strtonum(start + 1, 0, 365, &errstr); |
if (var > 365 || var < -365) |
if (errstr) |
return (0); /* Someone is just being silly */ |
return (0); /* Someone is just being silly */ |
val += (NUMEV + 1) * var; |
if (*start == '-') |
/* We add one to the matching event and multiply by |
var = -var; |
* (NUMEV + 1) so as not to return 0 if there's a match. |
val += (NUMEV + 1) * var; |
* val will overflow if there is an obscenely large |
/* We add one to the matching event and multiply by |
* number of special events. */ |
* (NUMEV + 1) so as not to return 0 if there's a match. |
break; |
* val will overflow if there is an obscenely large |
|
* number of special events. */ |
|
break; |
} |
} |
*flags |= F_SPECIAL; |
*flags |= F_SPECIAL; |
} |
} |
if (!(*flags & F_SPECIAL)) { |
if (!(*flags & F_SPECIAL)) { |
/* undefined rest */ |
/* undefined rest */ |
*p = savech; |
*p = savech; |
return (0); |
return (0); |
} |
} |
} |
} |
for (*p = savech; !isdigit(*p) && !isalpha(*p) && *p != '*' && *p != '\t'; ++p) |
for (*p = savech; !isdigit((unsigned char)*p) && |
|
!isalpha((unsigned char)*p) && *p != '*' && *p != '\t'; ++p) |
; |
; |
*endp = p; |
*endp = p; |
return (val); |
return (val); |
|
|
} |
} |
} |
} |
|
|
if (pipe(pdes) < 0) |
if (pipe(pdes) < 0) { |
|
close(fdin); |
return (NULL); |
return (NULL); |
|
} |
switch (vfork()) { |
switch (vfork()) { |
case -1: /* error */ |
case -1: /* error */ |
(void)close(pdes[0]); |
(void)close(pdes[0]); |
(void)close(pdes[1]); |
(void)close(pdes[1]); |
|
close(fdin); |
return (NULL); |
return (NULL); |
case 0: |
case 0: |
dup2(fdin, STDIN_FILENO); |
dup2(fdin, STDIN_FILENO); |
|
|
(void)close(pdes[1]); |
(void)close(pdes[1]); |
} |
} |
(void)close(pdes[0]); |
(void)close(pdes[0]); |
/* |
/* |
* Set stderr to /dev/null. Necessary so that cron does not |
* Set stderr to /dev/null. Necessary so that cron does not |
* wait for cpp to finish if it's running calendar -a. |
* wait for cpp to finish if it's running calendar -a. |
*/ |
*/ |
|
|
(void)dup2(fderr, STDERR_FILENO); |
(void)dup2(fderr, STDERR_FILENO); |
(void)close(fderr); |
(void)close(fderr); |
} |
} |
execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, (char *)NULL); |
execl(_PATH_CPP, "cpp", "-traditional", "-undef", "-U__GNUC__", |
|
"-P", "-I.", _PATH_INCLUDE, (char *)NULL); |
warn(_PATH_CPP); |
warn(_PATH_CPP); |
_exit(1); |
_exit(1); |
} |
} |
|
|
} |
} |
|
|
void |
void |
closecal(fp) |
closecal(FILE *fp) |
FILE *fp; |
|
{ |
{ |
struct stat sbuf; |
struct stat sbuf; |
int nread, pdes[2], status; |
int nread, pdes[2], status; |
char buf[1024]; |
char buf[1024]; |
|
pid_t pid; |
|
|
if (!doall) |
if (!doall) |
return; |
return; |
|
|
goto done; |
goto done; |
if (pipe(pdes) < 0) |
if (pipe(pdes) < 0) |
goto done; |
goto done; |
switch (vfork()) { |
switch ((pid = vfork())) { |
case -1: /* error */ |
case -1: /* error */ |
(void)close(pdes[0]); |
(void)close(pdes[0]); |
(void)close(pdes[1]); |
(void)close(pdes[1]); |
|
|
|
|
header[1].iov_base = header[3].iov_base = pw->pw_name; |
header[1].iov_base = header[3].iov_base = pw->pw_name; |
header[1].iov_len = header[3].iov_len = strlen(pw->pw_name); |
header[1].iov_len = header[3].iov_len = strlen(pw->pw_name); |
writev(pdes[1], header, 7); |
writev(pdes[1], header, 8); |
while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) |
while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0) |
(void)write(pdes[1], buf, nread); |
(void)write(pdes[1], buf, nread); |
(void)close(pdes[1]); |
(void)close(pdes[1]); |
done: (void)fclose(fp); |
done: (void)fclose(fp); |
while (wait(&status) >= 0) |
while (waitpid(pid, &status, 0) == -1) { |
; |
if (errno != EINTR) |
|
break; |
|
} |
} |
} |
|
|
|
|
void |
void |
insert(head, cur_evt) |
insert(struct event **head, struct event *cur_evt) |
struct event **head; |
|
struct event *cur_evt; |
|
{ |
{ |
struct event *tmp, *tmp2; |
struct event *tmp, *tmp2; |
|
|