[comp.sources.unix] v16i056: A visual calendar and appointment system, Part03/06

rsalz@uunet.uu.net (Rich Salz) (11/10/88)

Submitted-by: Michael Morrell <hplabs!hpda!morrell>
Posting-number: Volume 16, Issue 56
Archive-name: month8.7/part03

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# This archive contains:
#	print.c		schedule.c	time.c		user.c		
#	user2.c		
LANG=""; export LANG

echo x - print.c
cat >print.c <<'@EOF'
#ifndef lint
static char rcsid[] = "$Header: print.c,v 8.3 88/04/04 10:43:07 hull Exp $";
#endif

#include <curses.h>
#include <pwd.h>
#include "month.h"

char *grids[] = {
"mid .  .  .  1a .  .  .  2a .  .  .  3a .  .  .  4a .  .  .  5a .  .  . 6a",
"6a  .  .  .  7a .  .  .  8a .  .  .  9a .  .  . 10a .  .  . 11a .  .  . noon",
"noon.  .  .  1p .  .  .  2p .  .  .  3p .  .  .  4p .  .  .  5p .  .  . 6p",
"6p  .  .  .  7p .  .  .  8p .  .  .  9p .  .  . 10p .  .  . 11p .  .  . mid"
};

char *month_names[] = {
	"JANUARY",
	"FEBRUARY",
	"MARCH",
	"APRIL",
	"MAY",
	"JUNE",
	"JULY",
	"AUGUST",
	"SEPTEMBER",
	"OCTOBER",
	"NOVEMBER",
	"DECEMBER"
};

char *smtwtfs_names[] = {
	"Su",
	"Mo",
	"Tu",
	"We",
	"Th",
	"Fr",
	"Sa",
};

extern short month_start, days;
extern short all_flag, over_flag, date_flag, ins_mode, keep_old, read_only;
extern short crow, ccol, area_ptr;
extern struct event_rec current_event;
extern struct date_rec current_date, todays_date;
extern struct area_rec areas[];
extern char time_mode, *month_dir, *user_name;

print_screen()
{
	print_day_headers();
	show_all_events(current_date.month, current_date.year);
	print_border();
	print_all_months();
	print_all_years();
	print_user();
	print_flags();
	print_overview();
}

print_day_headers()
{
	static char *days_of_week =
	"Sunday    Monday   Tuesday  Wednesday  Thursday   Friday  Saturday";

	mvaddstr(DAY_ROW, DAY_COL, days_of_week);
}

print_border()
{
	short row;
	static char *border =
	"+------------------------------------------------------------------+";

	mvaddstr(DAY_ROW + 1, CAL_COL - 2, border);

	for (row = DAY_ROW + 2; row < YEAR_ROW - 1; row++) {
	    mvaddch(row, CAL_COL - 2, '|');
	    mvaddch(row, CAL_COL + 65, '|');
	}

	mvaddstr(YEAR_ROW - 1, CAL_COL - 2, border);
}

print_cal(month, year, all_events_list)
register month, year;
char *all_events_list;
{
	short i, month_is_current, cday;
	short row = CAL_ROW, col = CAL_COL;

	if (current_date.day > days)
	    current_date.day = days;
	else if (current_date.day < 1)
	    current_date.day = 1;

	month_is_current = ((month == todays_date.month) &&
	    (year == todays_date.year));

	for (i = 1, cday = 1; i <= 42; i++) {
		if ((cday <= days) && (i >= (month_start + 1))) {
			if (month_is_current && (cday == todays_date.day))
				attron(A_UNDERLINE);

			if (all_events_list && all_events_list[cday])
				mvprintw(row, col, "(%2d)", cday);
			else
				mvprintw(row, col, " %2d ", cday);

			attroff(A_UNDERLINE);
			cday++;
		} else
			mvprintw(row, col, "    ");

		if ((i % 7) == 0) {
			row += 2;
			col = CAL_COL;
		} else
			col += 10;
	}
	hl_day(current_date.day, HL_ON);
}

print_all_months()
{
	short i;

	for (i = 0; i <= 11; i++)
	    mvaddstr(MONTH_ROW + i, 0, month_names[i]);
	hl_month(current_date.month, HL_ON);
}

print_all_years()
{
	int ret = 1;
	short first_year, i;

	if (current_date.year < FIRST_YEAR) {
	    current_date.month = 1;
	    current_date.day = 1;
	    current_date.year = FIRST_YEAR;
	    ret = 0;
	} else if (current_date.year > LAST_YEAR) {
	    current_date.month = 12;
	    current_date.day = 31;
	    current_date.year = LAST_YEAR;
	    ret = 0;
	}

	first_year = current_date.year - (current_date.year % 10);

	move(YEAR_ROW, YEAR_COL);
	for (i = first_year; i < (first_year + 10); i++)
		printw(" %4d ", i);
	hl_year(current_date.year, HL_ON);
	return(ret);
}

print_flags()
{
	if (all_flag)
	    attron(A_BOLD);
	mvaddstr(0, FLAG_COL, "A");
	if (ins_mode)
	    attron(A_BOLD);
	else
	    attroff(A_BOLD);
	mvaddstr(0, FLAG_COL+2, "I");
	if (keep_old)
	    attron(A_BOLD);
	else
	    attroff(A_BOLD);
	mvaddstr(0, FLAG_COL+4, "K");
	if (over_flag)
	    attron(A_BOLD);
	else
	    attroff(A_BOLD);
	mvaddstr(0, FLAG_COL+6, "O");
#if MULTIUSER
	if (read_only)
	    attron(A_BOLD);
	else
	    attroff(A_BOLD);
	mvaddstr(0, FLAG_COL+8, "R");
#endif MULTIUSER
	attroff(A_BOLD);
}

print_user()
{
	if (user_name != NULL) {
	    mvprintw(0, USER_COL, "%*s", FLAG_COL - USER_COL, " ");
	    mvaddstr(0, USER_COL, "User: ");
	    attron(A_UNDERLINE);
	    addstr(user_name);
	    attroff(A_UNDERLINE);
	}
}

print_version()
{
	char ver_string[BUFSIZE];
	extern float get_version();

	sprintf(ver_string, "version %-3.3g", get_version());
	print_message(ver_string, NO_BELL);
}

print_event_regularity(event)
struct event_rec *event;
{
	if (event->monthly)
		attron(A_BOLD);
	mvaddstr(SCHEDULE_ROW, MONTHLY_COL, "monthly");
	attroff(A_BOLD);
	if (event->yearly)
		attron(A_BOLD);
	mvaddstr(SCHEDULE_ROW, YEARLY_COL, "yearly");
	attroff(A_BOLD);
	if (event->every)
		attron(A_BOLD);
	mvaddstr(SCHEDULE_ROW, EVERY_COL, "every");
	attroff(A_BOLD);
	print_smtwtfs(event->smtwtfs);
	print_nth(event);
	if (event->last)
		attron(A_BOLD);
	mvaddstr(SCHEDULE_ROW, LAST_COL, "last");
	attroff(A_BOLD);
	print_until(event);
}

print_smtwtfs(smtwtfs)
char smtwtfs[];
{
	short i;

	move(SCHEDULE_ROW, SMTWTFS_COL);

	for (i = 0; i < 7; i++) {
		if (smtwtfs[i])
			attron(A_BOLD);
		addstr(smtwtfs_names[i]);
		if (smtwtfs[i])
			attroff(A_BOLD);
	}
}

print_event(event)
struct event_rec *event;
{
	clear_schedule_area();
	print_date(event);
	print_event_regularity(event);
	print_event_private(event);
	print_event_anti(event);
	print_times(event);
	print_warning(event);
	print_event_description(event);
	print_owner(event);
}

print_event_private(event)
struct event_rec *event;
{
	if (event->private)
		attron(A_BOLD);
	mvaddstr(SCHEDULE_ROW, PRIVATE_COL, "priv");
	attroff(A_BOLD);
}

print_event_anti(event)
struct event_rec *event;
{
	if (event->anti)
		attron(A_BOLD);
	mvaddstr(SCHEDULE_ROW, ANTI_COL, "anti");
	attroff(A_BOLD);
}

print_times(event)
struct event_rec *event;
{
	short hour;
	char *apm;

	hour = event->start_time.hour;
	apm = (hour < 12) ? "am" : "pm";
	hour = ((hour + 11) % 12) + 1;

	mvaddstr(TIME_ROW-1, START_COL, "start time");
	if (time_mode == START_MODE)
	    attron(A_UNDERLINE);
	mvprintw(TIME_ROW, START_COL, "%2d:%02d %s", hour,
	    event->start_time.minute, apm);

	attroff(A_UNDERLINE);
	mvaddstr(TIME_ROW-1, DURATION_COL, "duration");
	if (time_mode == DURATION_MODE)
	    attron(A_UNDERLINE);
	mvprintw(TIME_ROW, DURATION_COL, "%2d:%02d", event->duration.hour,
		event->duration.minute);

	hour = event->end_time.hour;
	apm = (hour < 12) ? "am" : "pm";
	hour = ((hour + 11) % 12) + 1;

	attroff(A_UNDERLINE);
	mvaddstr(TIME_ROW-1, END_COL, "end time");
	if (time_mode == END_MODE)
	    attron(A_UNDERLINE);
	mvprintw(TIME_ROW, END_COL, "%2d:%02d %s", hour,
	    event->end_time.minute, apm);
	attroff(A_UNDERLINE);
}

print_warning(event)
struct event_rec *event;
{
	mvaddstr(TIME_ROW-1, WARNING_COL, "warning");
	mvprintw(TIME_ROW, WARNING_COL, "%2d:%02d", event->warning.hour,
		event->warning.minute);
}

print_event_description(event)
struct event_rec *event;
{
	mvprintw(DESCRIPTION_ROW, DESCRIPTION_COL-7, "event: %s",
		event->event_string);
}

print_owner(event)
struct event_rec *event;
{
	struct passwd *pw, *getpwuid();

	mvaddstr(OWNER_ROW-1, OWNER_COL, "owner");
	attron(A_UNDERLINE);

	if ((pw = getpwuid(event->event_owner)) != NULL)
	    mvprintw(OWNER_ROW, OWNER_COL, "%s", pw->pw_name);
	else
	    mvprintw(OWNER_ROW, OWNER_COL, "%d", event->event_owner);

	attroff(A_UNDERLINE);
}

print_until(event)
struct event_rec *event;
{
	if (event->until) {
		attron(A_BOLD);
	}
	mvprintw(SCHEDULE_ROW, UMONTH_COL, "%2d/%2d/%4d",
	    event->until_date.month, event->until_date.day,
	    event->until_date.year);
	attroff(A_BOLD);
}

print_date(event)
struct event_rec *event;
{
	attron(A_BOLD);
	mvprintw(SCHEDULE_ROW, SMONTH_COL, "%2d/%2d/%4d",
	    event->start_date.month, event->start_date.day,
	    event->start_date.year);
	attroff(A_BOLD);
}

print_message(str, sound)
char *str;
int sound;
{
	int strlen();

	clear_message_line();
	standout();
	mvaddstr(0, 0, str);
	standend();
	refresh();
	if (sound) {
		sound_bell();
	}
	return(strlen(str));
}

print_nth(event)
struct event_rec *event;
{
	char *ns;
	short n;

	if (event->nth_is_on) {
		attron(A_BOLD);
	}
	n = event->nth;
	if (event->nth > 13) {
		n %= 10;
	}

	switch(n) {
	case 0:
	case 4:
	case 5:
	case 6:
	case 7:
	case 8:
	case 9:
	case 10:
	case 11:
	case 12:
	case 13:
		ns = "th";
		break;
	case 1:
		ns = "st";
		break;
	case 2:
		ns = "nd";
		break;

	case 3:
		ns = "rd";
		break;
	}
	mvprintw(SCHEDULE_ROW, NTH_COL, "%02d%s", event->nth, ns);
	attroff(A_BOLD);
}

print_overview()
{
	short i, row, col, hour, minute, duration, n;
	struct eptr_rec *ep, *events_today;
	char *grid;

	clear_schedule_area();

	if (!over_flag) return;

	(void) get_daily_events(&events_today);

	for (i = 0; i < 4; i++)
	    mvaddstr((SCHEDULE_ROW + i + i), 0, grids[i]);

	attron(A_REVERSE);

	ep = events_today;
	while (ep) {
		hour = ep->event->start_time.hour;
		minute = ep->event->start_time.minute;

		row = SCHEDULE_ROW + ((hour / 6) * 2);

		duration = (ep->event->duration.hour * 60) +
		    ep->event->duration.minute;
		col = (12 * (hour % 6)) + (3 * (minute / 15));
		n = hour / 6;
		grid = grids[n];
		duration /= 15;

		move(row, col);

		for (i = 0; i < duration; i++) {
			addch(grid[col]);
			addch(grid[col + 1]);
			addch(grid[col + 2]);

			col += 3;
			if (col > 71 && i < (duration - 1)) {
				while(grid[col])
					addch(grid[col++]);
				col = 0;
				row += 2;

				if (row > (SCHEDULE_ROW + 6))
					break;
				move(row, col);
				grid = grids[++n];
			}
		}
		ep = ep->next_event;
	}
	attroff(A_REVERSE);
}

print_sched()
{
	short shour, sminute, ehour, eminute, n;
	struct eptr_rec *ep, *events_today;

	if ((n = get_daily_events(&events_today)) <= 0) {
		print_message("no events this day", BELL);
		return;
	}
	sort_events(events_today, n);

	push_area(BOOK);
	clear();
	move(0,0);
	printw("%s  %d/%d/%d\n",
		smtwtfs_names[(current_date.day+month_start-1) % 7],
		current_date.month, current_date.day, current_date.year);

	ep = events_today;
	while (ep) {
		shour = ep->event->start_time.hour;
		sminute = ep->event->start_time.minute;
		ehour = ep->event->end_time.hour;
		eminute = ep->event->end_time.minute;

		if (shour == ehour && sminute == eminute)
		    printw("   %2d:%02d%2s         ",
			((shour + 11) % 12) + 1, sminute,
			((shour < 12) ? "am" : "pm"));
		else
		    printw("   %2d:%02d%2s-%2d:%02d%2s ",
			((shour + 11) % 12) + 1, sminute,
			((shour < 12) ? "am" : "pm"),
			((ehour + 11) % 12) + 1, eminute,
			((ehour < 12) ? "am" : "pm"));
		printw("%s\n", ep->event->event_string);

		ep = ep->next_event;
	}
	prompt_wait();
	clear();
	print_screen();
	pop_area();
}

print_book(ndays)
int ndays;
{
	short shour, sminute, ehour, eminute, n;
	struct eptr_rec *ep, *events_today;

	if (!date_flag) {
	    current_date.month = todays_date.month;
	    current_date.day = todays_date.day;
	    current_date.year = todays_date.year;
	}

	if (ndays <= 0)
	    return(-1);
	if (read_schedule(month_dir, READ_ONLY) != 0)
	    return(-1);

	for (; ndays; ndays--) {
	    month_start = get_month_start(current_date.month,
		current_date.year);
	    days = days_in(current_date.month, current_date.year);
	    if ((n = get_daily_events(&events_today)) == 0) {
		if (incr_date(1, &current_date))
		    continue;
		else
		    break;
	    }

	    sort_events(events_today, n);
	    printf("%s  %d/%d/%d\n",
		smtwtfs_names[(current_date.day+month_start-1) % 7],
		current_date.month, current_date.day, current_date.year);

	    ep = events_today;
	    while (ep) {
		shour = ep->event->start_time.hour;
		sminute = ep->event->start_time.minute;
		ehour = ep->event->end_time.hour;
		eminute = ep->event->end_time.minute;

		if (shour == ehour && sminute == eminute)
		    printf("   %2d:%02d%2s         ",
			((shour + 11) % 12) + 1,sminute,
			((shour < 12) ? "am" : "pm"));
		else
		    printf("   %2d:%02d%2s-%2d:%02d%2s ",
			((shour + 11) % 12) + 1,sminute,
			((shour < 12) ? "am" : "pm"),
			((ehour + 11) % 12) + 1,eminute,
			((ehour < 12) ? "am" : "pm"));
		printf("%s\n", ep->event->event_string);

		ep = ep->next_event;
	    }
	    printf("\n");
	    if (!incr_date(1, &current_date))
		break;
	}
	return(0);
}

sound_bell()
{
	putchar(7);
	fflush(stdout);
}

clear_message_line()
{
	mvprintw(0, 0, "%*s", USER_COL, " ");
	if (current_area == SCAN || current_area == SCHED_SCAN)
	    ccol = 0;
}

clear_schedule_area()
{
	move(SCHEDULE_ROW, 0);
	clrtobot();
}
@EOF

chmod 644 print.c

echo x - schedule.c
cat >schedule.c <<'@EOF'
#ifndef lint
static char rcsid[] = "$Header: schedule.c,v 8.5 88/04/04 10:44:43 hull Exp $";
#endif

#include <curses.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#if LOCKF
#include <fcntl.h>
#include <unistd.h>
#endif LOCKF
#if FLOCK
#include <sys/file.h>
#endif FLOCK
#include "month.h"

struct event_rec current_event = {{0, 0, 0}, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0},
1, 0, 0, {10, 0}, {1, 0}, {0, 15}, {11, 0}, "", 0, 0, 0, 0, {0, 0, 0}, 0};
short update_schedule = 0;
short updating = 0, edit_flag = 0, parsed_correctly, alias_level;
unsigned short file_owner;
int fd;
FILE *alias_file, *glob_alias_file;

extern short days, month_start, my_file;
extern short all_flag, keep_old, read_only;
extern short crow, ccol;
extern struct date_rec current_date, todays_date;
extern short area_ptr;
extern struct area_rec areas[];
extern struct event_rec events;
extern int user_id;
extern char *month_dir, *user_name;

group_post()
{
	char names[BUFSIZE];

	push_area(SCAN);
	ccol = print_message("names: ", NO_BELL);

	if (get_string(names) == 0) {
	    clear_message_line();
	    pop_area();
	    return;
	}

	post_event();		/* does push_area(SCHEDULE) */
	edit_flag = 1;
	parsed_correctly = 0;
	while ((user() == ACCEPT) && !parsed_correctly)
	    ;
	pop_area();
	if (parsed_correctly)
	    post_it_to_em(names, &current_event);
	edit_flag = 0;
	show_all_events(current_date.month, current_date.year);
	pop_area();
}

post_it_to_em(names, event)
char *names;
struct event_rec *event;
{
	short i, save_keep;
	struct name_rec *name_list = NULL, *cur_name;
	char buf[BUFSIZE], *new_dir, *get_user_arg();
	char *alias_file_name;
	char ch, *name;

	glob_alias_file = fopen(ALIASFILE, "r");
	alias_file_name = malloc((unsigned) strlen(month_dir)+10);
	strcpy(alias_file_name, month_dir);
	strcat(alias_file_name, "/.monthrc");
	alias_file = fopen(alias_file_name, "r");
	free(alias_file_name);

	clear_schedule_area();
	refresh();
	alias_level = 0;
	if (expand_aliases(names, &name_list) == -1) {
	    print_message("too many alias levels", BELL);
	    fclose(alias_file);
	    fclose(glob_alias_file);
	    return;
	}
/*
	cur_name = name_list;
	printf("name_list:\n");
	while (cur_name != NULL) {
	    printf("*%s*\n", cur_name->name);
	    cur_name = cur_name->next_name;
	}
*/
	fclose(alias_file);
	fclose(glob_alias_file);
	save_keep = keep_old;
	keep_old = 1;

	/* write out current user's schedule */
	if (!read_only && write_schedule() < 0) {
	    more();
	    sprintf(buf, "user %s: cannot write .month", user_name);
	    ccol = print_message(buf, BELL);
	}

	cur_name = name_list;
	while (cur_name != NULL) {
	    name = cur_name->name;
	    if ((new_dir = get_user_arg(name)) != NULL) {
		while ((i = read_schedule(new_dir, READ_WRITE)) == -2) {
		    more();
		    sprintf(buf, "user %s: .month file locked", name);
		    ccol = print_message(buf, BELL);
		    more();
		    ccol = print_message("try again? ", NO_BELL);
		    ch = get_char();
		    clear_message_line();
		    if (ch != 'y')
			break;		/* i is still -2 */
		}

		if (i == -1) {
		    more();
		    sprintf(buf, "user %s: cannot open .month", name);
		    ccol = print_message(buf, BELL);
		} else if (i > 0) {
		    more();
		    sprintf(buf, "user %s: cannot read .month version %d",
			name, i);
		    ccol = print_message(buf, BELL);
		} else if (i == 0) {	/* normal case */
		    link_event(event);
		    if (write_schedule() < 0) {
			more();
			sprintf(buf, "user %s: cannot write .month", name);
			ccol = print_message(buf, BELL);
		    }
		}
	    } else {
		more();
		sprintf(buf, "invalid user: %s", name);
		ccol = print_message(buf, BELL);
	    }
	    cur_name = cur_name->next_name;
	}

	free_names(name_list);

	/* read in original user's schedule */
	if ((i = read_schedule(month_dir, read_only)) == -2) {
	    more();
	    ccol = print_message(".month file locked", BELL);
	    i = read_schedule(month_dir, READ_ONLY);
	    if (i == 0)
		read_only = 1;
	}

	if (i == -1) {
	    more();
	    ccol = print_message("cannot open .month", BELL);
	} else if (i > 0) {
	    more();
	    sprintf(buf, "cannot read .month version %d", i);
	    ccol = print_message(buf, BELL);
	}
	show_all_events(current_date.month, current_date.year);
	keep_old = save_keep;
}

expand_aliases(names, list)
char *names;
struct name_rec **list;
 {
	struct name_rec *p, *q = NULL, *t;
	char *name, *look_up_name();

	name = strtok(names, " ,\t\n");
	while (name != NULL) {
	    p = (struct name_rec *) malloc(sizeof(struct name_rec));
	    p->name = strcpy(malloc((unsigned) strlen(name)+1), name);
	    p->next_name = NULL;
	    if (q == NULL)
		t = p;
	    else
		q->next_name = p;
	    q = p;
	    name = strtok((char *)NULL, " ,\t\n");
	}

	p = t;
	while (p != NULL) {
	    if ((names = look_up_name(p->name)) != NULL) {
		if (alias_level++ == MAX_ALIAS_LEVEL ||	/* to prevent loops */
		  expand_aliases(names, list) == -1) {
		    free(names);
		    free_names(t);
		    return(-1);
		}
		free(names);
		alias_level--;
	    } else
		add_name(p->name, list);
	    p = p->next_name;
	}

	free_names(t);
	return(0);
}

add_name(name, list)
char *name;
struct name_rec **list;
{
	struct name_rec *p, *q;

	p = *list;
	while (p != NULL) {
	    if (strcmp(p->name, name) == 0)
		return;
	    q = p;
	    p = p->next_name;
	}

	p = (struct name_rec *) malloc(sizeof(struct name_rec));
	p->name = strcpy(malloc((unsigned) strlen(name)+1), name);
	p->next_name = NULL;

	if (*list == NULL) {
/*	    printf("add_name *%s* to empty list\n", p->name); */
	    *list = p;
	} else {
/*	    printf("add_name *%s*\n", p->name); */
	    q->next_name = p;
	}
}

char *
look_up_name(name)
char *name;
{
	char line[MAXLINE], *word;

	if (alias_file != NULL) {
	    rewind(alias_file);
	    while (fgets(line, MAXLINE, alias_file) != NULL) {
		line[strlen(line)-1] = '\0';
		if ((strcmp(strtok(line, " \t\n"), "alias") == 0) &&
		    (strcmp(strtok((char *) NULL, " ,\t\n"), name) == 0) &&
		    ((word = strtok((char *) NULL, " ,\t\n")) != NULL)) {
			*(word + strlen(word)) = ' ';
/*			printf("look_up_name: %s -> *%s*\n", name, word); */
			return(strcpy(malloc((unsigned) strlen(word)+1), word));
		}
	    }
	}

	if (glob_alias_file != NULL) {
	    rewind(glob_alias_file);
	    while (fgets(line, MAXLINE, glob_alias_file) != NULL) {
		line[strlen(line)-1] = '\0';
		if ((strcmp(strtok(line, " \t\n"), "alias") == 0) &&
		    (strcmp(strtok((char *) NULL, " ,\t\n"), name) == 0) &&
		    ((word = strtok((char *) NULL, " ,\t\n")) != NULL)) {
			*(word + strlen(word)) = ' ';
/*			printf("look_up_name: %s -> *%s*\n", name, word); */
			return(strcpy(malloc((unsigned) strlen(word)+1), word));
		}
	    }
	}

	return(NULL);
}

free_names(list)
struct name_rec *list;
{
	struct name_rec *p;

	while (list != NULL) {
	    free(list->name);
	    p = list->next_name;
	    free((char *) list);
	    list = p;
	}
}

post_event()
{
	clear_message_line();
	push_area(SCHEDULE);
	current_event.start_date.month = current_date.month;
	current_event.start_date.day = current_date.day;
	current_event.start_date.year = current_date.year;
	current_event.event_owner = user_id;
	print_event(&current_event);
}

write_sched()
{
	int i;

	if (read_only) {
	    print_message("read-only mode", BELL);
	    return;
	}

	push_area(SCAN);
	if (update_schedule)
	    ccol = print_message("updating schedule", NO_BELL);
	else
	    ccol = print_message("schedule unchanged", NO_BELL);

	if (write_schedule() < 0) {
	    more();
	    ccol = print_message("cannot write .month", BELL);
	    pop_area();
	    return;
	}

	if ((i = read_schedule(month_dir, read_only)) == -2) {
	    more();
	    ccol = print_message(".month file locked", BELL);
	    i = read_schedule(month_dir, READ_ONLY);
	    if (i == 0)
		read_only = 1;
	}

	show_all_events(current_date.month, current_date.year);

	if (i != 0) {
	    more();
	    ccol = print_message("cannot open .month", BELL);
	}
	pop_area();
}

select_regularity_col(col)
register col;
{
	short i, hflag;

	switch(col) {
	case PRIVATE_COL:
		hl_all(&current_event, (current_event.private ? 0 : 1),
		    -1, -1, -1, -1, -1, -1, -1, -1);
		break;
	case ANTI_COL:
		hl_all(&current_event, -1, (current_event.anti ? 0 : 1),
		    -1, -1, -1, -1, -1, -1, -1);
		break;
	case MONTHLY_COL:
		hl_all(&current_event, -1, -1,
		    (current_event.monthly ? 0 : 1), 0, -1, -1, -1, -1, -1);
		break;
	case YEARLY_COL:
		hl_all(&current_event, -1, -1, 0,
		    (current_event.yearly ? 0 : 1), -1, -1, -1, -1, -1);
		break;
	case EVERY_COL:
		hl_all(&current_event, -1, -1, -1, -1,
		   (current_event.every ? 0 : 1), -1, -1, -1, -1);
		break;
	case NTH_COL:
		hl_all(&current_event, -1, -1, -1, -1, -1,
		    (current_event.nth_is_on ? 0 : 1), -1, -1, -1);
		break;
	case LAST_COL:
		hl_all(&current_event, -1, -1, -1, -1, -1, -1,
		    (current_event.last ? 0 : 1), -1, -1);
		break;
	case SMTWTFS_COL:
	case SMTWTFS_COL + 2:
	case SMTWTFS_COL + 4:
	case SMTWTFS_COL + 6:
	case SMTWTFS_COL + 8:
	case SMTWTFS_COL + 10:
	case SMTWTFS_COL + 12:
		i = (col - SMTWTFS_COL) / 2;
		hflag = (current_event.smtwtfs[i] = !current_event.smtwtfs[i]);
		hl_schedule(col, hflag);
		hl_all(&current_event, -1, -1, -1, -1, -1, -1, -1, -1, -1);
		break;
	case UMONTH_COL:
	case UDAY_COL:
	case UYEAR_COL:
		hl_all(&current_event, -1, -1, -1, -1, -1, -1, -1,
		    (current_event.until ? 0 : 1), -1);
		break;
	}
}

accept_current_event()
{
	if ((parse_event(&current_event) != -1)) {
	    if (!edit_flag) {
	        pop_area();
		link_event(&current_event);
	        show_all_events(current_date.month, current_date.year);
	    }
	}
}

cancel_current_event()
{
	if (!edit_flag)
	    pop_area();
	print_overview();
}

link_event(event)
struct event_rec *event;
{
	struct event_rec *t, *ptr;

	if (!(ptr = (struct event_rec *)malloc(sizeof(struct event_rec))))
	    return;
	*ptr = *event;
	t = events.next_event;
	events.next_event = ptr;
	ptr->next_event = t;
	update_schedule++;
}

parse_event(event)
struct event_rec *event;
{
	short hs;

	hs = has_smtwtfs(event->smtwtfs);

	if (!date_ok(&event->start_date)) {
		print_message("invalid start date", BELL);
		return(-1);
	}
	if (event->until && !date_ok(&event->until_date)) {
		print_message("invalid until date", BELL);
		return(-1);
	}
	if ((event->every || event->nth_is_on || event->last) && !hs) {
		print_message("missing day of week", BELL);
		return(-1);
	}
	if (hs && !event->every && !event->nth_is_on && !event->last) {
MQ:		print_message("missing qualifier", BELL);
		return(-1);
	}
	if (!event->every &&
	    (event->monthly || event->yearly) &&
		(event->nth_is_on || event->last)) {
		print_message("need 'every'", BELL);
		return(-1);
	}
	if (event->last && !event->monthly && !event->yearly) {
		print_message("monthly or yearly?", BELL);
		return(-1);
	}
	if ((event->nth_is_on || event->last || event->until) &&
	    (!event->monthly && !event->yearly && !event->every)) {
		goto MQ;
	}
	parsed_correctly = 1;
	return(0);
}

is_event_today()
/* are there any events today? */
{
	struct event_rec *eptr;

	eptr = events.next_event;
	while (eptr) {
	    if (event_today(eptr))
		return(1);
	    eptr = eptr->next_event;
	}

	return(0);
}

get_daily_events(ep)
struct eptr_rec **ep;
{
	short i = 0;
	struct event_rec *eptr;
	struct eptr_rec *p, *q, *first_event;

	first_event = (struct eptr_rec *)NULL;
	q = (struct eptr_rec *)NULL;

	eptr = events.next_event;
	while (eptr) {
	    if (event_today(eptr)) {
		i++;
		p = (struct eptr_rec *)malloc(sizeof(struct eptr_rec));
		p->event = eptr;
		p->next_event = (struct eptr_rec *)NULL;
		p->prev_event = q;
		if (q)
		    q->next_event = p;
		else
		    first_event = p;
		q = p;
	    }
	    eptr = eptr->next_event;
	}

	*ep = first_event;
	return(i);
}

get_every_event(ep)
struct eptr_rec **ep;
{
	short i = 0;
	struct event_rec *eptr;
	struct eptr_rec *p, *q, *first_event;

	first_event = (struct eptr_rec *)NULL;
	q = (struct eptr_rec *)NULL;

	eptr = events.next_event;
	while (eptr) {
	    if (event_visible(eptr)) {
		i++;
		p = (struct eptr_rec *)malloc(sizeof(struct eptr_rec));
		p->event = eptr;
		p->next_event = (struct eptr_rec *)NULL;
		p->prev_event = q;
		if (q)
		    q->next_event = p;
		else
		    first_event = p;
		q = p;
	    }
	    eptr = eptr->next_event;
	}

	*ep = first_event;
	return(i);
}

event_visible(event)
register struct event_rec *event;
{
	/* returns 1 if event is visible, 0 if not */

	return(my_file || !event->private || (user_id == event->event_owner));
}

scan_todays_events()
{
	struct eptr_rec *events_today;
	short n;

	if ((n = get_daily_events(&events_today)) <= 0) {
		print_message("no events this day", BELL);
		return;
	}
	sort_events(events_today, n);

	scan_events(&events_today);
	free_event_ptrs(events_today);
	print_overview();
}

scan_every_event()
{
	struct eptr_rec *first_event;

	if (get_every_event(&first_event) <= 0) {
	    print_message("no events at all", BELL);
	    return;
	}

	scan_events(&first_event);
	free_event_ptrs(first_event);
	print_overview();
}

scan_events(first_event_p)
struct eptr_rec **first_event_p;
{
	register short ch;
	struct event_rec *ptr;
	struct eptr_rec *p, *q;

	push_area(SCHED_SCAN);
	p = *first_event_p;
	while (p) {
	    ptr = p->event;
	    current_event = *ptr;
	    print_event(ptr);

	    ch = get_npdeq(p->next_event != NULL, p->prev_event != NULL,
	      !read_only && (my_file || (ptr->event_owner == user_id)));

	    switch(ch) {
	    case 'n':
		p = p->next_event;
		break;
	    case 'p':
		p = p->prev_event;
		break;
	    case 'd':
		delete_event(ptr);
		show_all_events(current_date.month, current_date.year);
		if (p->prev_event)
		    p->prev_event->next_event = p->next_event;
		else
		    *first_event_p = p->next_event;
		if (p->next_event) {
		    p->next_event->prev_event = p->prev_event;
		    q = p->next_event;
		} else
		    q = p->prev_event;
		free((char *)p);
		p = q;
		break;
	    case 'e':
		edit_flag = 1;
		push_area(SCHEDULE);
		parsed_correctly = 0;
		while (!parsed_correctly)
		    if (user() == ACCEPT) {
			if (parsed_correctly) {
			    *ptr = current_event;
	        	    show_all_events(current_date.month,
				current_date.year);
			    update_schedule++;
			}
		    } else {
			print_event(ptr);
			break;
		    }
		pop_area();
		edit_flag = 0;
		break;
	    case 'q':
		p = (struct eptr_rec *)NULL;
		break;
	    }
	}
	pop_area();
	clear_message_line();
}

delete_event(event)
struct event_rec *event;
{
	struct event_rec *ptr;

	ptr = &events;

	while (ptr && (ptr->next_event != event)) {
		ptr = ptr->next_event;
	}
	if (ptr) {
		ptr->next_event = ptr->next_event->next_event;
		free((char *)event);
	}
	update_schedule++;
}

sort_events(e, n)
register struct eptr_rec *e;
int n;
{
	register struct event_rec *ev, *nev;
	register struct eptr_rec *ev_ptr;
	register i;
	short f;

	for (i = 0; i < n; i++) {
	    f = 0;
	    ev_ptr = e;
	    while (ev_ptr->next_event) {
		ev = ev_ptr->event;
		nev = ev_ptr->next_event->event;
		if ((ev->start_time.hour > nev->start_time.hour) ||
		    ((ev->start_time.hour == nev->start_time.hour) &&
		    (ev->start_time.minute > nev->start_time.minute))) {
			ev_ptr->event = nev;
			ev_ptr->next_event->event = ev;
			f++;
		}
		ev_ptr = ev_ptr->next_event;
	    }
	    if (f == 0)
		break;
	}
}

free_event_ptrs(eptr)
struct eptr_rec *eptr;
{
	while (eptr) {
	    free((char *)eptr);
	    eptr = eptr->next_event;
	}
}

show_all_events(month, year)
register month, year;
{
	register struct event_rec *eptr;
	short i;
	char match_list[32];
	short tday;

	month_start = get_month_start(month, year);
	days = days_in(month, year);

	if (all_flag) {
	    tday = current_date.day;
	    for (i = 1; i <= days; i++) {
		eptr = events.next_event;
		match_list[i] = 0;
		current_date.day = i;

		while (eptr) {
		    if (event_today(eptr)) {
			match_list[i] = 1;
			break;
		    }
		    eptr = eptr->next_event;
		}
	    }
	    current_date.day = tday;
	    print_cal(month, year, match_list);
	} else
	    print_cal(month, year, (char *)0);

	if (current_area != SCHEDULE && current_area != SCHED_SCAN)
	    print_overview();
}

#if !SYS5
char *
strtok(s1, s2)
char *s1, *s2;
{
    static char *pos;
    char *p, *q;

    if (s1 != (char *)NULL)
	pos = s1;

    if (*pos == '\0')
	return((char *)NULL);

    for (p = pos; *p != '\0'; p++) {
	if (index(s2, (int) *p) == (char *)NULL)
	    continue;
	*p = '\0';
	q = pos;
	for (pos = ++p; *pos != '\0' && index(s2, (int) *pos) != (char *)NULL;
	    pos++);
	if (*pos == '\0')
	    return((char *)NULL);
	return(q);
    }
    q = pos;
    pos = (char *)NULL;
    return(q);
}
#endif
@EOF

chmod 644 schedule.c

echo x - time.c
cat >time.c <<'@EOF'
#ifndef lint
static char rcsid[] = "$Header: time.c,v 8.2 87/11/13 21:47:20 hull Exp $";
#endif

#include "month.h"

extern struct date_rec current_date;

void
convert_year(base_year, year)
short base_year, *year;
{
	short delta;

	if (*year < 100) {
	    *year += base_year - (base_year % 100);
	    if ((delta = (*year - base_year)) >= 50)
		*year -= 100;
	    else if (delta < -50)
		*year += 100;
	}
}

date_ok(date)
struct date_rec *date;
{
	if (date->day <= days_in(date->month, date->year))
	    return(1);
	else
	    return(0);
}

has_smtwtfs(smtwtfs)
register char *smtwtfs;
{
	register i;

	for (i = 0; i < 7; i++) {
		if (smtwtfs[i]) {
			return(1);
		}
	}
	return(0);
}

days_since_jan1(date)
struct date_rec *date;
{
	int dys = 0;
	short i;

	for (i = 1; i < date->month; i++) {
		dys += days_in(i, date->year);
	}
	dys += date->day;
	return(dys);
}

incr_date(inc, date)
short inc;
struct date_rec *date;
{
	/* return in date the increment (or decrement) of the current date */
	/* return 1 if incr successful, 0 if not */

	date->month = current_date.month;
	date->day = current_date.day;
	date->year = current_date.year;

	while (inc > 0) {
	    if (date->day < days_in(date->month, date->year))
		date->day = date->day + 1;
	    else {
		if (date->month < 12) {
		    date->month = date->month + 1;
		    date->day = 1;
		} else {
		    if (date->year < LAST_YEAR) {
			date->month = 1;
			date->day = 1;
			date->year = date->year + 1;
		    } else
			return(0);
		}
	    }
	    inc--;
	}

	while (inc < 0) {
	    if (date->day > 1)
		date->day = date->day - 1;
	    else {
		if (date->month > 1) {
		    date->month = date->month - 1;
	            date->day = days_in(date->month, date->year);
		} else {
		    if (date->year > FIRST_YEAR) {
			date->month = 12;
			date->year = date->year - 1;
	                date->day = days_in(date->month, date->year);
		    } else
			return(0);
		}
	    }
	inc++;
	}
	return(1);
}

compute_times(event, mode)
struct event_rec *event;
char mode;
{
	switch(mode) {
	case START_MODE:
	    event->start_time.minute = 60 + event->end_time.minute -
	        event->duration.minute;
	    event->start_time.hour = (23 + event->end_time.hour -
	        event->duration.hour + (event->start_time.minute / 60)) % 24;
	    event->start_time.minute %= 60;
	    break;
	case DURATION_MODE:
	    event->duration.minute = 60 + event->end_time.minute -
	        event->start_time.minute;
	    event->duration.hour = (23 + event->end_time.hour -
	        event->start_time.hour + (event->duration.minute / 60)) % 24;
	    event->duration.minute %= 60;
	    break;
	case END_MODE:
	    event->end_time.minute = event->start_time.minute +
		event->duration.minute;
	    event->end_time.hour = (event->start_time.hour +
		event->duration.hour + (event->end_time.minute / 60)) % 24;
	    event->end_time.minute %= 60;
	    break;
	}
}
@EOF

chmod 644 time.c

echo x - user.c
cat >user.c <<'@EOF'
#ifndef lint
static char rcsid[] = "$Header: user.c,v 8.2 87/11/13 21:47:22 hull Exp $";
#endif

#include <curses.h>
#if SYS5
#include <string.h>
#else
#include <strings.h>
#endif
#include "month.h"

extern short area_ptr, crow, ccol, edit_flag, read_only, over_flag;
extern short my_file, event_status;
extern struct area_rec areas[];
extern struct date_rec current_date, todays_date, mdates[];
extern struct event_rec current_event;

user()
{
	register short ch;
	short n, savecol;
	char *prompt, *incrp, iprompt[BUFSIZE];

	for (;;) {
		move(crow, ccol);
		refresh();

GETCH:
		ch = get_char();
/*
		mvprintw(0, 0, "ch = %c (0x%x)", ch, ch);
		move(crow, ccol);
		refresh();
*/

		switch(ch) {
		case '\001':	/* ^A */
			if (current_area == SCHEDULE) {
			    accept_current_event();
			    if (edit_flag)
				return(ACCEPT);
			} else
			    sound_bell();
			break;
		case '\033':	/* ^[ */
			if (current_area == SCHEDULE) {
			    cancel_current_event();
			    if (edit_flag)
				return(CANCEL);
			} else
			    sound_bell();
			break;
		case '/':
			if (current_area != SCHEDULE) {
			    prompt = "date: ";
			    if (get_date(&current_date, prompt))
				goto_this_day(&current_date);
			} else if (crow == SCHEDULE_ROW) {
			    savecol = ccol;
			    if (ccol <= SYEAR_COL) {
				prompt = "start date: ";
				if (get_date(&current_event.start_date, prompt))
				    print_date(&current_event);
			    } else if (ccol >= UMONTH_COL) {
				prompt = "until date: ";
				if (get_date(&current_event.until_date,
					prompt)) {
				    current_event.until = 1;
				    print_until(&current_event);
				}
			    } else
				sound_bell();
			    ccol = savecol;
			} else
			    sound_bell();
			break;
		case ';':
			if (current_area != SCHEDULE)
			    goto_this_day(&mdates[SEMI_MARK]);
			else
			    sound_bell();
			break;
		case '?':
			if (current_area != SCHEDULE)
			    help();
			else
			    sound_bell();
			break;
		case '+':
		case '-':
			incrp = (ch == '+') ? "increment: " : "decrement: ";
			switch(current_area) {
			case MONTHS:
				strcpy(iprompt, "month ");
				strcat(iprompt, incrp);
				break;
			case DAYS:
				strcpy(iprompt, "day ");
				strcat(iprompt, incrp);
				break;
			case YEARS:
				strcpy(iprompt, "year ");
				strcat(iprompt, incrp);
				break;
			case SCHEDULE:
				if (crow == SCHEDULE_ROW) {
				    switch(ccol) {
				    case SMONTH_COL:
				    case UMONTH_COL:
					strcpy(iprompt, "month ");
					strcat(iprompt, incrp);
					break;
				    case SDAY_COL:
				    case UDAY_COL:
					strcpy(iprompt, "day ");
					strcat(iprompt, incrp);
					break;
				    case SYEAR_COL:
				    case UYEAR_COL:
					strcpy(iprompt, "year ");
					strcat(iprompt, incrp);
					break;
				    case NTH_COL:
					strcpy(iprompt, "nth ");
					strcat(iprompt, incrp);
					break;
				    default:
					sound_bell();
					goto GETCH;
				    }
				} else {	/* must be on TIME_ROW */
				    switch(ccol) {
				    case START_COL:
				    case DURATION_COL:
				    case END_COL:
				    case WARNING_COL:
					strcpy(iprompt, "hour ");
					strcat(iprompt, incrp);
					break;
				    case START_COL+3:
				    case DURATION_COL+3:
				    case END_COL+3:
				    case WARNING_COL+3:
					strcpy(iprompt, "minute ");
					strcat(iprompt, incrp);
					break;
				    default:
					sound_bell();
					goto GETCH;
				    }
				}
				break;
			}
			if ((n = enter_number(ch, iprompt)) >= 0)
				do_incr((ch == '+') ? n : -n);
			break;
#if SHELL_ESCAPE
		case '!':
			if (current_area != SCHEDULE)
			    shell_escape();
			else
			    sound_bell();
			break;
#endif
		case '\n':
			if ((n = selection()) != NOTHING)
			    return(n);
			break;
		case 'a':
			if (current_area != SCHEDULE)
			    print_aliases();
			else
			    sound_bell();
			break;
		case 'd':
		case 'm':
		case 'y':
			if (current_area != SCHEDULE) {
			    pop_area();
			    push_area(ch);
			} else
			    sound_bell();
			break;
		case 'h':
		case 'j':
		case 'k':
		case 'l':
			event_status = NOTHING;
			move_cursor(ch);
			switch(event_status) {
			case ACCEPT:
				accept_current_event();
				if (edit_flag)
					return(event_status);
				break;
			case CANCEL:
				cancel_current_event();
				if (edit_flag)
					return(event_status);
				break;
			}
			break;
		case 'n':
		case 'p':
		case ' ':
		case '\b':
			if (current_area == SCHEDULE)
				do_incr_sched((ch == 'n' || ch == ' ') ? 1: -1);
			else
				do_incr((ch == 'n' || ch == ' ') ? 1: -1);
			break;
		case 't':
			if (current_area == SCHEDULE)
				change_time_mode();
			else
				sound_bell();
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			switch(current_area) {
			case DAYS:
				prompt = "day: ";
				break;
			case MONTHS:
				prompt = "month: ";
				break;
			case YEARS:
				prompt = "year: ";
				break;
			case SCHEDULE:
				if (crow == SCHEDULE_ROW) {
				    switch(ccol) {
				    case SMONTH_COL:
				    case UMONTH_COL:
					prompt = "month: ";
					break;
				    case SDAY_COL:
				    case UDAY_COL:
					prompt = "day: ";
					break;
				    case SYEAR_COL:
				    case UYEAR_COL:
					prompt = "year: ";
					break;
				    case NTH_COL:
					prompt = "nth: ";
					break;
				    default:
					goto GETCH;
				    }
				} else {	/* must be on TIME_ROW */
				    switch(ccol) {
				    case START_COL:
				    case DURATION_COL:
				    case END_COL:
				    case WARNING_COL:
					prompt = "hour: ";
					break;
				    case START_COL+3:
				    case DURATION_COL+3:
				    case END_COL+3:
				    case WARNING_COL+3:
					prompt = "minute: ";
					break;
				    default:
					sound_bell();
					goto GETCH;
				    }
				}
				break;
			}
			if ((n = enter_number(ch, prompt)) >= 0)
				do_number(n);
			break;
		case 'A':
			if (current_area != SCHEDULE) {
			    toggle_flag('A');
			    show_all_events(current_date.month,
				current_date.year);
			} else
			    sound_bell();
			break;
		case 'B':
			if (current_area != SCHEDULE)
			    print_sched();
			else
			    sound_bell();
			break;
		case 'C':
			if (current_area != SCHEDULE) {
			    if (!over_flag)
				clear_schedule_area();
			    clear_message_line();
			} else
			    sound_bell();
			break;
		case 'E':
			if (current_area != SCHEDULE)
			    scan_every_event();
			else
			    sound_bell();
			break;
		case 'G':
			if (current_area != SCHEDULE)
			    group_post();
			else
			    sound_bell();
			break;
		case 'K':
			if (current_area != SCHEDULE)
			    if (!my_file)
				print_message("must keep old events", BELL);
			    else
				toggle_flag('K');
			else
			    sound_bell();
			break;
		case 'L':
			if (current_area != SCHEDULE)
				lunar();
			else
			    sound_bell();
			break;
		case 'M':
		case '\'':
			if (current_area != SCHEDULE)
				mark_day((ch != 'M'));
			else
			    sound_bell();
			break;
		case 'O':
			if (current_area != SCHEDULE) {
				toggle_flag('O');
				print_overview();
			} else
			    sound_bell();
			break;
		case 'P':
			if (current_area != SCHEDULE)
			    if (read_only)
	    			print_message("read-only mode", BELL);
			    else
				post_event();
			else
			    sound_bell();
			break;
		case 'Q':
			if (current_area != SCHEDULE)
				return(ACCEPT);
			else
			    sound_bell();
			break;
#if MULTIUSER
		case 'R':
			if (current_area != SCHEDULE)
				do_read_mode();
			else
			    sound_bell();
			break;
#endif MULTIUSER
		case 'S':
			if (current_area != SCHEDULE)
				scan_todays_events();
			else
			    sound_bell();
			break;
		case 'T':
			if (current_area != SCHEDULE)
				goto_this_day(&todays_date);
			else
			    sound_bell();
			break;
#if MULTIUSER
		case 'U':
			if (current_area != SCHEDULE)
				get_user();
			else
			    sound_bell();
			break;
#endif MULTIUSER
		case 'V':
			if (current_area != SCHEDULE)
				print_version();
			else
			    sound_bell();
			break;
		case 'W':
			if (current_area != SCHEDULE)
				write_sched();
			else
			    sound_bell();
			break;
		default:
			sound_bell();
			goto GETCH;
		}

		if ((current_date.month != mdates[CUR_MARK].month) ||
		    (current_date.day != mdates[CUR_MARK].day) ||
		    (current_date.year != mdates[CUR_MARK].year)) {
			mdates[SEMI_MARK] = mdates[CUR_MARK];
			mdates[CUR_MARK].month = current_date.month;
			mdates[CUR_MARK].day = current_date.day;
			mdates[CUR_MARK].year = current_date.year;
		}
	}
	/* NOTREACHED */
}
@EOF

chmod 644 user.c

echo x - user2.c
cat >user2.c <<'@EOF'
#ifndef lint
static char rcsid[] = "$Header: user2.c,v 8.4 88/04/04 10:13:30 hull Exp $";
#endif

#include <signal.h>
#include <curses.h>
#include "month.h"

extern short delchar, kilchar, update_schedule;
extern short all_flag, ins_mode, keep_old, over_flag, read_only;
extern short crow, ccol, days;
extern short area_ptr;
extern unsigned short getgid(), getegid();
extern int user_id;
extern char time_mode, *home_dir, *month_dir;
extern struct area_rec areas[];
extern struct date_rec current_date, todays_date, mdates[];
extern struct event_rec current_event;

selection()
{
	switch(current_area) {
		case MONTHS:
			if ((crow - MONTH_ROW) != current_date.month - 1) {
			    hl_month(current_date.month, HL_OFF);
			    current_date.month = crow - MONTH_ROW + 1;
			    show_all_events(current_date.month,
				current_date.year);
			    hl_month(current_date.month, HL_ON);
			}
			break;
		case DAYS:
			hl_day(current_date.day, HL_OFF);
			current_date.day = get_day_from_row_col(crow, ccol);
			hl_day(current_date.day, HL_ON);
			print_overview();
			break;
		case YEARS:
			hl_year(current_date.year, HL_OFF);
			current_date.year = current_date.year -
				(current_date.year % 10) +
				   ((ccol - (YEAR_COL + 4)) / 6);
			hl_year(current_date.year, HL_ON);
			show_all_events(current_date.month, current_date.year);
			break;
		case SCHEDULE:
			if (crow == SCHEDULE_ROW)
				select_regularity_col(ccol);
			else
				schedule_move_cursor('\n');
			break;
	}
	return(NOTHING);
}

enter_number(ch, prompt)
short ch;
char *prompt;
{
	char nbuf[BUFSIZE];
	short i = 0, max_digits = 2;
	int retval = -1;

	if (current_area == YEARS) {
	    max_digits = 4;
	    push_area(SCAN);
	} else if (current_area == SCHEDULE) {
	    if (ccol == SYEAR_COL || ccol == UYEAR_COL)
		max_digits = 4;
	    push_area(SCHED_SCAN);
	} else
	    push_area(SCAN);

	ccol = print_message(prompt, NO_BELL);

	for (;;) {
	    if ((ch >= '0') && (ch <= '9')) {
		if (i < max_digits) {
			nbuf[i++] = ch;
			mvaddch(0, ccol++, ch);
			refresh();
		}
	    } else if (ch == '\n') {
		nbuf[i] = 0;
		retval = atoi(nbuf);
		break;
	    } else if (ch == '\b') {
		if (i > 0) {
		    i--; ccol--;
		    mvaddch(0, ccol, ' ');
		    move(0, ccol);
		    refresh();
		}
	    } else if (ch == '\033') {	/* ^[ */
		break;
	    }
	    ch = get_char();
	}
	clear_message_line();
	pop_area();
	return(retval);
}

do_number(n)
short n;
{
	void convert_year();

	switch(current_area) {
	case MONTHS:
	    if (n <= 12 && n >= 1) {
		hl_month(current_date.month, HL_OFF);
		current_date.month = n;
		show_all_events(current_date.month, current_date.year);
		hl_month(current_date.month, HL_ON);
		goto_month();
	    }
	    break;
	case DAYS:
	    if (n >= 1 && n <= days) {
		hl_day(current_date.day, HL_OFF);
		current_date.day = n;
		hl_day(current_date.day, HL_ON);
		print_overview();
		goto_day();
	    }
	    break;
	case YEARS:
	    convert_year(current_date.year, &n);
	    current_date.year = n;
	    print_all_years();
	    show_all_events(current_date.month, current_date.year);
	    goto_year();
	    break;
	case SCHEDULE:
	    if (crow == SCHEDULE_ROW) {
		switch(ccol) {
		case SMONTH_COL:
		    if (n >= 1 && n <= 12)
			current_event.start_date.month = n;
		    print_date(&current_event);
		    break;
		case SDAY_COL:
		    if (n >= 1 && n <= 31)
			current_event.start_date.day = n;
		    print_date(&current_event);
		    break;
		case SYEAR_COL:
	    	    convert_year(current_date.year, &n);
		    if (n >= FIRST_YEAR && n <= LAST_YEAR)
			current_event.start_date.year = n;
		    print_date(&current_event);
		    break;
		case UMONTH_COL:
		    if (n >= 1 && n <= 12) {
			current_event.until_date.month = n;
			current_event.until = 1;
		    }
		    print_until(&current_event);
		    break;
		case UDAY_COL:
		    if (n >= 1 && n <= 31) {
			current_event.until_date.day = n;
			current_event.until = 1;
		    }
		    print_until(&current_event);
		    break;
		case UYEAR_COL:
	    	    convert_year(current_date.year, &n);
		    if (n >= FIRST_YEAR && n <= LAST_YEAR) {
			current_event.until_date.year = n;
			current_event.until = 1;
		    }
		    print_until(&current_event);
		    break;
		case NTH_COL:
		    if (n > 0 && n <= 53) {
			current_event.nth = n;
			current_event.nth_is_on = 1;
			print_nth(&current_event);
		    }
		    break;
		default:
		    sound_bell();
		    break;
		}
	    } else {	/* must be on TIME_ROW */
		switch(ccol) {
		case START_COL:
		    if (n < 24) {
			current_event.start_time.hour = n;
			compute_times(&current_event, time_mode);
			print_times(&current_event);
		    }
		    break;
		case DURATION_COL:
		    if (n < 24) {
			current_event.duration.hour = n;
			compute_times(&current_event, time_mode);
			print_times(&current_event);
		    }
		    break;
		case END_COL:
		    if (n < 24) {
			current_event.end_time.hour = n;
			compute_times(&current_event, time_mode);
			print_times(&current_event);
		    }
		    break;
		case WARNING_COL:
		    if (n < 24) {
			current_event.warning.hour = n;
			print_warning(&current_event);
		    }
		    break;
		case START_COL+3:
		    if (n < 60) {
			current_event.start_time.minute = n;
			compute_times(&current_event, time_mode);
			print_times(&current_event);
		    }
		    break;
		case DURATION_COL+3:
		    if (n < 60) {
			current_event.duration.minute = n;
			compute_times(&current_event, time_mode);
			print_times(&current_event);
		    }
		    break;
		case END_COL+3:
		    if (n < 60) {
			current_event.end_time.minute = n;
			compute_times(&current_event, time_mode);
			print_times(&current_event);
		    }
		    break;
		case WARNING_COL+3:
		    if (n < 60) {
			current_event.warning.minute = n;
			print_warning(&current_event);
		    }
		    break;
		default:
		    sound_bell();
		    break;
		}
	    }
	    break;
	}
}

do_incr_sched(dir)
register dir;
{
	if (crow == TIME_ROW) {
	    switch(ccol) {
	    case START_COL:
	    case DURATION_COL:
	    case END_COL:
	    case WARNING_COL:
		do_incr(dir);
		break;
	    case START_COL+3:
	    case DURATION_COL+3:
	    case END_COL+3:
	    case WARNING_COL+3:
		do_incr(15 * dir);
		break;
	    default:
		sound_bell();
		break;
	    }
	} else	/* must be on SCHEDULE_ROW */
	    do_incr(dir);
}

do_incr(n)
short n;
{
	short shift;

	switch(current_area) {
	case MONTHS:
	    hl_month(current_date.month, HL_OFF);
	    if (n < 0)
		shift = -((abs(n) / 12) +
		    ((current_date.month - (abs(n) % 12) < 1) ? 1 : 0));
	    else
		shift = (n / 12) +
		    ((current_date.month + (n % 12) > 12) ? 1 : 0);

	    current_date.year += shift;
	    if (print_all_years())
	        mod(&current_date.month, 1, 12, n);
	    show_all_events(current_date.month, current_date.year);
	    hl_month(current_date.month, HL_ON);
	    goto_month();
	    break;
	case DAYS:
	    hl_month(current_date.month, HL_OFF);
	    (void) incr_date(n, &current_date);
	    print_all_years();
	    hl_month(current_date.month, HL_ON);
	    show_all_events(current_date.month, current_date.year);
	    goto_day();
	    break;
	case YEARS:
	    hl_month(current_date.month, HL_OFF);
	    current_date.year += n;
	    print_all_years();
	    hl_month(current_date.month, HL_ON);
	    show_all_events(current_date.month, current_date.year);
	    goto_year();
	    break;
	case SCHEDULE:
	    if (crow == SCHEDULE_ROW) {
		switch(ccol) {
		case SMONTH_COL:
		    mod(&current_event.start_date.month, 1, 12, n);
		    print_date(&current_event);
		    break;
		case SDAY_COL:
		    mod(&current_event.start_date.day, 1, 31, n);
		    print_date(&current_event);
		    break;
		case SYEAR_COL:
		    mod(&current_event.start_date.year, FIRST_YEAR,
		        LAST_YEAR, n);
		    print_date(&current_event);
		    break;
		case UMONTH_COL:
		    mod(&current_event.until_date.month, 1, 12, n);
		    current_event.until = 1;
		    print_until(&current_event);
		    break;
		case UDAY_COL:
		    mod(&current_event.until_date.day, 1, 31, n);
		    current_event.until = 1;
		    print_until(&current_event);
		    break;
		case UYEAR_COL:
		    mod(&current_event.until_date.year, FIRST_YEAR,
			LAST_YEAR, n);
		    current_event.until = 1;
		    print_until(&current_event);
		    break;
		case NTH_COL:
		    modc(&current_event.nth, 0, 53, n);
		    current_event.nth_is_on = 1;
		    print_nth(&current_event);
		    break;
		default:
		    sound_bell();
		    break;
		}
	    } else {	/* must be on TIME_ROW */
		switch(ccol) {
		case START_COL:
		    mod(&current_event.start_time.hour, 0, 23, n);
		    compute_times(&current_event, time_mode);
		    print_times(&current_event);
		    break;
		case DURATION_COL:
		    mod(&current_event.duration.hour, 0, 23, n);
		    compute_times(&current_event, time_mode);
		    print_times(&current_event);
		    break;
		case END_COL:
		    mod(&current_event.end_time.hour, 0, 23, n);
		    compute_times(&current_event, time_mode);
		    print_times(&current_event);
		    break;
		case WARNING_COL:
		    mod(&current_event.warning.hour, 0, 23, n);
		    print_warning(&current_event);
		    break;
		case START_COL+3:
		    mod(&current_event.start_time.minute, 0, 59, n);
		    compute_times(&current_event, time_mode);
		    print_times(&current_event);
		    break;
		case DURATION_COL+3:
		    mod(&current_event.duration.minute, 0, 59, n);
		    compute_times(&current_event, time_mode);
		    print_times(&current_event);
		    break;
		case END_COL+3:
		    mod(&current_event.end_time.minute, 0, 59, n);
		    compute_times(&current_event, time_mode);
		    print_times(&current_event);
		    break;
		case WARNING_COL+3:
		    mod(&current_event.warning.minute, 0, 59, n);
		    print_warning(&current_event);
		    break;
		default:
		    sound_bell();
		    break;
		}
	    }
	    break;
	}
}

prompt_wait()
{
	move(LINES-1, 0);
	clrtoeol();
	standout();
	addstr("Press any key to return to calendar ");
	standend();
	refresh();
	(void) get_char();
}

more()
{
	if (ccol != 0) {
	    standout();
	    addstr(" -more-");
	    standend();
	    ccol += 7;
	    refresh();
	    (void) get_char();
	}
}

mark_day(goto_flag)
short goto_flag;
{
	short ch;

	print_message("mark: ", NO_BELL);

	for (;;) {
		ch = get_char();

		switch(ch) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			mvaddch(0, 6, ch);
			refresh();
			ch -= '0';

			if (goto_flag)
				goto_this_day(&mdates[ch]);
			else {
				mdates[ch].month = current_date.month;
				mdates[ch].day = current_date.day;
				mdates[ch].year =  current_date.year;
			}
			return;
		case '\033':	/* ^[ */
		case '\n':
			clear_message_line();
			return;
		}
	}
}

toggle_flag(flag_char)
char flag_char;
{
	switch(flag_char) {
	case 'A':
	    all_flag = !all_flag;
	    break;
	case 'I':
	    ins_mode = !ins_mode;
	    break;
	case 'K':
	    keep_old = !keep_old;
	    break;
	case 'O':
	    over_flag = !over_flag;
	    break;
	case 'R':
	    read_only = !read_only;
	    break;
	}

	print_flags();
}

mod(var, min, max, inc)
short *var, min, max, inc;
{
	if (inc > 0)
	    *var = ((*var - min + inc) % (max - min + 1)) + min;
	else
	    *var = ((*var - min + (max - min + 1) -
	    (abs(inc) % (max - min + 1))) % (max - min + 1)) + min;
}

modc(var, min, max, inc)
char *var;
short min, max, inc;
{
	if (inc > 0)
	    *var = (char) ((*var - min + inc) % (max - min + 1)) + min;
	else
	    *var = (char) ((*var - min + (max - min + 1) -
	    (abs(inc) % (max - min + 1))) % (max - min + 1)) + min;
}

#if MULTIUSER
do_read_mode()
{
	int i;
	char buf[BUFSIZE];

	if (read_only) {
	    if ((i = read_schedule(month_dir, READ_WRITE)) == 0)
		toggle_flag('R');
	    else if (i == -2) {
		print_message(".month file locked", BELL);
		i = read_schedule(month_dir, READ_ONLY);
	    }

	    if (i != 0)
		if (i == -1)
		    print_message("cannot open .month", BELL);
	        else {
		    sprintf(buf, "cannot read .month version %d", i);
		    print_message(buf, BELL);
		}
	} else	/* read/write */ {
	    push_area(SCAN);
	    if (update_schedule)
		ccol = print_message("updating schedule", NO_BELL);
	    else
		ccol = print_message("schedule unchanged", NO_BELL);

	    if (write_schedule() < 0) {
		more();
		print_message("cannot write .month", BELL);
	        pop_area();
		return;
	    }
	    toggle_flag('R');
	    pop_area();
	}

	show_all_events(current_date.month, current_date.year);
}
#endif MULTIUSER

help()
{
	char *buf;
	int blast_out(), terminate();

	push_area(HELP);
	clear();
	refresh();
	buf = malloc((unsigned) (strlen(PG) + strlen(HELPFILE) + 2));
	sprintf(buf, "%s %s", PG, HELPFILE);
	do_system(buf);
	prompt_wait();
	clear();
	print_screen();
	pop_area();
	new_day();              /* may be new day now */
}

print_aliases()
{
	char *alias_file_name, *buf;
	extern char *strcat(), *strcpy();

	alias_file_name = malloc((unsigned) strlen(month_dir)+10);
	strcpy(alias_file_name, month_dir);
	strcat(alias_file_name, "/.monthrc");

	push_area(ALIAS);
	clear();
	refresh();
	buf = malloc((unsigned) (strlen(PG) + strlen(alias_file_name) +
	    strlen(ALIASFILE) + 3));
	sprintf(buf, "%s %s %s", PG, alias_file_name, ALIASFILE);
	free(alias_file_name);
	do_system(buf);
	prompt_wait();
	clear();
	print_screen();
	pop_area();
	new_day();		/* may be new day now */
}

#if SHELL_ESCAPE
shell_escape()
{
	char *buf;

	buf = malloc((unsigned) (strlen(SH) + 1));
	sprintf(buf, "%s", SH);
	clear();
	mvprintw(0, 0, "!%s\n", buf);
	refresh();
	endwin();
	do_system(buf);
	initscr();
	crmode();
	noecho();
#if SYS5CURSES
	keypad(stdscr, TRUE);
#endif
	clear();
	print_screen();
	new_day();		/* may be new day now */
}
#endif

do_system(buf)
char *buf;
{
	int gid, egid;
	int blast_out(), terminate();
	alarm_t alarm();

	alarm((alarm_t) 0);
	signal(SIGINT, SIG_DFL);
	signal(SIGQUIT, SIG_DFL);
	signal(SIGHUP, SIG_DFL);
	signal(SIGALRM, SIG_DFL);
	gid = (int) getgid();	/* get original group */
	egid = (int) getegid();	/* get group month */
	setgid(gid);		/* change to original group */
	system(buf);
	setgid(egid);		/* restore group month */
	free(buf);
	signal(SIGINT, blast_out);
	signal(SIGQUIT, blast_out);
	signal(SIGHUP, terminate);
}

lunar()
{
	long yday, calculate();

	yday = (long) (days_since_jan1(&current_date) + 1);
	(void) calculate(yday, ((long) (current_date.year - 1900)),
	    11L, 0L);
	push_area(LUNAR);
	draw();
	prompt_wait();
	clear();
	print_screen();
	pop_area();
}

change_time_mode()
{
	short i, *cols;

	static short time_cols[] = {
	    START_COL, START_COL+3, DURATION_COL, DURATION_COL+3,
	    END_COL, END_COL+3, WARNING_COL, WARNING_COL+3
	};
	static short start_cols[] = {
	    DURATION_COL, DURATION_COL+3, DURATION_COL, DURATION_COL+3,
	    END_COL, END_COL+3, WARNING_COL, WARNING_COL+3
	};
	static short duration_cols[] = {
	    START_COL, START_COL+3, END_COL, END_COL+3,
	    END_COL, END_COL+3, WARNING_COL, WARNING_COL+3
	};
	static short end_cols[] = {
	    START_COL, START_COL+3, DURATION_COL, DURATION_COL+3,
	    START_COL, START_COL+3, WARNING_COL, WARNING_COL+3
	};
	
	switch(time_mode) {
	case START_MODE:
	    cols = end_cols;
	    time_mode = END_MODE;
	    break;
	case DURATION_MODE:
	    cols = start_cols;
	    time_mode = START_MODE;
	    break;
	case END_MODE:
	    cols = duration_cols;
	    time_mode = DURATION_MODE;
	    break;
	}

	if (crow == TIME_ROW) {
	    i = 0;
	    while(time_cols[i] != ccol)
		i++;
	    ccol = *(cols+i);
	}

	print_times(&current_event);
}
@EOF

chmod 644 user2.c

exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.