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

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

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

# 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:
#	days_in.c	event_today.c	get_home.c	get_month.c	
#	get_today.c	hidden.c	how_many.c	is_future.c	
#	is_leap.c	is_past.c	jan1.c		matches.c	
#	read_sched.c	write_sched.c	version.c	
LANG=""; export LANG

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

days_in(month, year)
short month, year;
{
	switch(month) {
	case 1:
	case 3:
	case 5:
	case 7:
	case 8:
	case 10:
	case 12:
		return(31);
	case 4:
	case 6:
	case 9:
	case 11:
		return(30);
	case 2:
		return(28 + is_leap_year(year));
	}
	/* NOTREACHED */
}
@EOF

chmod 644 days_in.c

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

#include "month.h"

extern struct date_rec current_date;
extern short my_file;
extern int user_id;

event_today(event)
register struct event_rec *event;
{
	/* returns 1 if event is visible on the current day, 0 if not */

	/* check if this in an anti-event */

	if (event->anti)
	    return(0);

	/* check if the file belongs to this user, the event is private,
	   and the user id does not match the event owner */

	if (!my_file && event->private && (user_id != event->event_owner))
	    return(0);

	/* check if event matches the current date */

	if (!event_matches_date(event, &current_date))
	    return(0);

	/* check if event hidden by anti-event */

	if (event_hidden(event, &current_date))
	    return(0);

	return(1);
}
@EOF

chmod 644 event_today.c

echo x - get_home.c
cat >get_home.c <<'@EOF'
#ifndef lint
static char rcsid[] = "$Header: get_home.c,v 1.1 87/12/02 18:07:19 hull Exp $";
#endif

#include <pwd.h>

extern char *malloc();

char *
get_home_dir(uid)
int uid;
{
	struct passwd *pw;
	char *strcpy();
	int strlen();

	if ((pw = getpwuid(uid)) == (struct passwd *)0)
	    return((char *)0);
	else
	    return(strcpy(malloc((unsigned)strlen(pw->pw_dir)+1), pw->pw_dir));
}
@EOF

chmod 644 get_home.c

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

get_month_start(month, year)
register month, year;
{
	short day, i;

	day = jan1(year);

	for (i = 1; i < month; i++) {
		day = (day + days_in(i, year)) % 7;
	}
	return(day);
}
@EOF

chmod 644 get_month.c

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

#if SYS5
#include <time.h>
#else
#include <sys/time.h>
#endif
#include "month.h"

extern struct date_rec todays_date;
extern short dhour, dminute, dsecond;

get_todays_date()
{
#if SYS5
	long tloc, time();
#else
	struct timeval tp;
	struct timezone tzp;
#endif
	struct tm *tmp;

#if SYS5
	if (time(&tloc) == -1)
	    return(-1);
	tmp = localtime(&tloc);
#else
	if (gettimeofday(&tp, &tzp) != 0)
	    return(-1);
	tmp = localtime((long *) &tp.tv_sec);
#endif
	todays_date.month = tmp->tm_mon + 1;
	todays_date.day = tmp->tm_mday;
	todays_date.year = 1900 + tmp->tm_year;
	/* random values for testing */
	/*
	todays_date.month = random(12) + 1;
	todays_date.day = random(29) + 1;
	todays_date.year = 1900 + random(100);
	*/
	dhour = tmp->tm_hour;
	dminute = tmp->tm_min;
	dsecond = tmp->tm_sec;
	return(0);
}

/* for testing */
/*
random(m)
int m;
{
    long lrand48();

    return ((int) (lrand48() % m));
}
*/
@EOF

chmod 644 get_today.c

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

#include "month.h"

extern struct event_rec events;

event_hidden(event, date)
register struct event_rec *event;
register struct date_rec *date;
{
	/* returns 1 if event hidden by anti-event on date, 0 if not */

	register struct event_rec *ptr;
	extern unsigned short file_owner;
	extern int strcmp();

	ptr = events.next_event;

	while (ptr) {
	    if (ptr->anti &&
		(ptr->start_time.hour == event->start_time.hour) &&
		(ptr->start_time.minute == event->start_time.minute) &&
		(ptr->duration.hour == event->duration.hour) &&
		(ptr->duration.minute == event->duration.minute) &&
		(ptr->warning.hour == event->warning.hour) &&
		(ptr->warning.minute == event->warning.minute) &&
		(strcmp(ptr->event_string, event->event_string) == 0) &&
		((ptr->event_owner == event->event_owner) ||
		    (ptr->event_owner == file_owner)) &&
		event_matches_date(ptr, date))
		return(1);
	    ptr = ptr->next_event;
	}
	return(0);
}
@EOF

chmod 644 hidden.c

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

#include "month.h"

how_many_since(edate, cdate)
struct date_rec *edate, *cdate;
{
	register total_days_passed;
	short i;

	if (edate->year < cdate->year) {
	    total_days_passed = 0;
	    for (i = edate->month; i <= 12; i++)
		total_days_passed += days_in(i, edate->year);

	    total_days_passed -= (edate->day - 1);
	    for (i = (edate->year + 1); i < cdate->year; i++)
		total_days_passed += (365 + is_leap_year(i));

	    for (i = 1; i < cdate->month; i++)
		total_days_passed += days_in(i, cdate->year);

	    total_days_passed += cdate->day;
	} else if (edate->month == cdate->month)
	    total_days_passed = cdate->day - edate->day + 1;
	else {
	    total_days_passed = 1 - edate->day;
	    for (i = edate->month; i < cdate->month; i++)
		total_days_passed += days_in(i, cdate->year);

	    total_days_passed += cdate->day;
	}
	return(((total_days_passed - 1) / 7) + 1);
}
@EOF

chmod 644 how_many.c

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

#include "month.h"

is_future_event(event, date)
struct event_rec *event;
struct date_rec *date;
{
	if (date->year < event->start_date.year)
		return(1);

	if (date->year > event->start_date.year)
		return(0);

	if (date->month < event->start_date.month)
		return(1);

	if (date->month > event->start_date.month)
		return(0);

	if (date->day < event->start_date.day)
		return(1);

	return(0);
}
@EOF

chmod 644 is_future.c

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

is_leap_year(year)
int year;
{
    return((((jan1(year + 1) + 7 - jan1(year)) % 7) == 2) ? 1 : 0);
}
@EOF

chmod 644 is_leap.c

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

#include "month.h"

is_past_event(event, date)
struct event_rec *event;
struct date_rec *date;
{
	register end_month, end_day, end_year;

	if (!event->until && (event->monthly || event->yearly || event->every))
		return(0);

	if (event->until) {
		end_month = event->until_date.month;
		end_day = event->until_date.day;
		end_year = event->until_date.year;
	} else {
		end_month = event->start_date.month;
		end_day = event->start_date.day;
		end_year = event->start_date.year;
	}

	if (end_year > date->year)
		return(0);

	if (end_year < date->year)
		return(1);

	if (end_month > date->month)
		return(0);

	if (end_month < date->month)
		return(1);

	if (end_day < date->day)
		return(1);

	return(0);
}
@EOF

chmod 644 is_past.c

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

jan1(year)
register year;
{
	register day;

	day = year + (year + 3) / 4;

	if (year > 1800) {
		day -= (year - 1701) / 100;
		day += (year - 1601) / 400;
	}
	if (year > 4000)
		day -= year / 4000;

	return(day % 7);
}
@EOF

chmod 644 jan1.c

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

#include "month.h"

#define nth_smtwtfs_of_month(date)  (((date->day - 1) / 7) + 1)
#define last_smtwtfs_of_month(date) \
	((date->day + 7) > days_in(date->month, date->year) ? 1 : 0)

event_matches_date(event, date)
register struct event_rec *event;
register struct date_rec *date;
{
	/* returns 1 if event matches date, 0 if not */

	short mnth_start;
	int n;

	/* check if event is a future or past event */

	if (is_future_event(event, date) ||
	    is_past_event(event, date))
		return(0);

	/* one time events must match date */

	if ((event->start_date.year == date->year) &&
	    (event->start_date.month == date->month) &&
	    (event->start_date.day == date->day) && !event->every &&
	    !event->nth_is_on && !event->last && !event->until) {
		return(1);
	}

	/* once monthly or once yearly events */

	if (!event->every && !event->nth_is_on && !event->last) {
	    if (event->monthly) {
		if (event->start_date.day == date->day)
		    return(1);
	    } else if (event->yearly) {
		if ((event->start_date.month == date->month) &&
		    (event->start_date.day == date->day))
		    return(1);
	    }
	}

	mnth_start = get_month_start(date->month, date->year);
	if (!event->smtwtfs[(date->day - 1 + mnth_start) % 7])
	    return(0);

	/* everys */

	if (event->every) {

	    /* every smtwtfs */

	    if (!event->nth_is_on && !event->last) {
EVDAY:		    if (event->smtwtfs[(date->day - 1 + mnth_start) % 7])
			return(1);
		    return(0);
	    }

	    /* every monthly/yearly */

	    if (event->monthly || event->yearly) {
		/* every monthly not-1st2nd3rdlast */
		if (!event->nth_is_on && !event->last)
		    goto EVDAY;

		/* every monthly/yearly with one of 1st2nd3rd... */

		if (event->nth_is_on) {
		    if (event->monthly && (nth_smtwtfs_of_month(date)
			== event->nth)) 
			return(1);
		    if (event->yearly && (nth_smtwtfs_of_year(date)
			== event->nth))
			return(1);
		}

		/* every monthly/yearly with last */

		if (event->last) {
		    if (event->monthly) {
			if (last_smtwtfs_of_month(date))
			    return(1);
		    }
		    if (event->yearly) {
			if (last_smtwtfs_of_year(date))
			    return(1);
		    }
		}

	    } else {

		/* every not-monthly and not-yearly */

		if (!event->nth_is_on && !event->last)
		    goto EVDAY;

		/* every nth/dayofweek */

		if (event->nth == 1)
		    return(1);

		n = how_many_since(&event->start_date, date);
		if ((n % event->nth) == 1)
		    return(1);
	    }
	}
	return(0);
}

nth_smtwtfs_of_year(date)
struct date_rec *date;
{
	short dys, i;

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

	return(((dys - 1) / 7) + 1);
}

last_smtwtfs_of_year(date)
struct date_rec *date;
{
	short dys, i;

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

	return((dys + 7) > (365 + is_leap_year(date->year)) ? 1 : 0);
}
@EOF

chmod 644 matches.c

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

#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"

extern unsigned short file_owner;
extern int fd;
extern struct event_rec events;

read_schedule(m_dir, read_mode)
char *m_dir;
short read_mode;
{
	char *schedule_file_name;
	unsigned rec_size;
	struct stat stat_buf;
	short file_version;
	struct event_rec event_buf, *event_ptr, *chain_ptr;
	extern float get_version();
	extern char *strcat(), *strcpy();

	schedule_file_name = malloc((unsigned) strlen(m_dir)+8);
	strcpy(schedule_file_name, m_dir);
	strcat(schedule_file_name, "/.month");

	rec_size = sizeof(struct event_rec);
	umask(0);

	chain_ptr = events.next_event;	/* free old events */
	while (chain_ptr) {
		event_ptr = chain_ptr;
		chain_ptr = chain_ptr->next_event;
		free((char *)event_ptr);
	}
	events.next_event = 0;

#if MULTIUSER
	if (read_mode == READ_ONLY)
	    fd = open(schedule_file_name, O_RDONLY);
	else {
	    if ((fd = open(schedule_file_name, O_RDWR|O_CREAT, 0660)) != -1)
#if LOCKF
		if (lockf(fd, F_TLOCK, 0L) == -1) {
		    close(fd);
		    fd = -2;
		    return(-2);
		}
#else
#if FLOCK
		if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
		    close(fd);
		    fd = -2;
		    return(-2);
		}
#endif FLOCK
#endif LOCKF
	}
#else
	fd = open(schedule_file_name, O_RDWR|O_CREAT, 0660);
#endif MULTIUSER
	free(schedule_file_name);

	if (fd != -1) {
		if (read(fd, (char *) &file_version, sizeof(file_version))
		    == sizeof(file_version)) {
		    if (file_version != (int) get_version()) {
			close(fd);
			fd = -1;
			return(file_version);
		    }
		} else {	/* no version field so assume empty file */
		    if (read_mode == READ_ONLY) {
			close(fd);
			fd = -1;
		    }
		    return(0);
		}

		chain_ptr = &events;

		while (read(fd, &event_buf, rec_size) == rec_size) {
			if (event_ptr = (struct event_rec *)malloc(rec_size)) {
				chain_ptr->next_event = event_ptr;
				chain_ptr = event_ptr;
				*chain_ptr = event_buf;
				chain_ptr->next_event = (struct event_rec *)0;
			} else
				break;
		}
		fstat(fd, &stat_buf);
		file_owner = stat_buf.st_uid;
		if (read_mode == READ_ONLY) {
		    close(fd);
		    fd = -1;
		}
		return(0);
	}
	/* if here, open failed */
	return(-1);
}
@EOF

chmod 644 read_sched.c

echo x - write_sched.c
cat >write_sched.c <<'@EOF'
#ifndef lint
static char rcsid[] = "$Header: write_sched.,v 8.3 87/12/01 23:40:05 hull Exp $";
#endif

#include "month.h"

extern short updating, update_schedule, keep_old;
extern int fd;
extern off_type lseek();
extern struct date_rec todays_date;
extern struct event_rec events;

write_schedule()
{
	short file_version;
	struct event_rec *chain_ptr;
	float get_version();

	if (fd < 0)	/* file not really open */
	    return(fd);

	if (!update_schedule) {
	    close(fd);
	    return(0);
	}

	updating = 1;
	file_version = (int) get_version();

	if (lseek(fd, (off_type) 0, 0) == -1) {
	    close(fd);
	    return(-1);
	}

#if !SYS5
	if (ftruncate(fd, (off_type) 0) == -1) {
	    close(fd);
	    return(-1);
	}
#endif

	write(fd, (char *) &file_version, sizeof(short));
	chain_ptr = events.next_event;

	while (chain_ptr) {
		if (keep_old || !is_past_event(chain_ptr, &todays_date))
			write(fd, (char *)chain_ptr, sizeof(struct event_rec));
		else
			delete_event(chain_ptr);
		chain_ptr = chain_ptr->next_event;
	}
	close(fd);	/* also releases lock */
	update_schedule = updating = 0;
	return(0);
}
@EOF

chmod 644 write_sched.c

echo x - version.c
cat >version.c <<'@EOF'
#ifndef lint
static char rcsid[] = "$Header: version.c,v 8.7 88/06/03 22:35:16 hull Exp $";
#endif

/* $Log:	version.c,v $
 * Revision 8.7  88/06/03  22:35:16  22:35:16  hull (James Hull)
 * Changed year_area display to always display "whole" decades.
 * Changed semantics of 2-digit year entry.
 * Fixed screen-memory-file consistency bug.
 * 
 * Revision 8.6  88/04/04  11:17:12  11:17:12  hull (James Hull)
 * Added alarm calls and new_day function so today's date is updated.
 * Fixed bug so that 'R' command updates schedule display.
 * Various other bug fixes and code clean-ups.
 * 
 * Revision 8.5  88/01/15  10:48:52  10:48:52  hull (James Hull)
 * Fixed bug by only calling write_schedule if not in read-only mode.
 * 
 * Revision 8.4  87/12/02  18:49:50  18:49:50  hull (James Hull)
 * Moved get_home_dir() out of month.c, monthd.c, and xmonthd.c to a separate file.
 * Deleted some unnecessary include files from month.c, monthd.c, xmonthd.c.
 * 
 * Revision 8.3  87/12/01  23:50:22  23:50:22  hull (James Hull)
 * Fixed bug in read_schedule which caused monthd to mysteriously die.
 * Problem was caused by never closing the file descriptor and eventually
 * reaching the open file descriptor limit imposed by the operating system.
 * 
 * Revision 8.2  87/11/13  21:25:07  21:25:07  hull (James Hull)
 * Fixed 'd', 'm', 'y' bug which allowed exit from schedule area.
 * Fixed user_name bug in 'U' and 'G' commands.
 * Added 'a' (print aliases) command.
 * Added ',' to list of allowed name separators.
 * Fixed security hole in 'a' and 'H' commands.
 * 
 * Revision 8.1  87/11/13  21:24:26  21:24:26  hull (James Hull)
 * Added environment flag and command line option for time mode.
 * Added 't' (change time mode) command in schedule area.
 * 
 * Revision 8.0  87/11/13  21:21:37  21:21:37  hull (James Hull)
 * Added ending time to event_rec structure.
 * Changed "monthd", print_sched, print_book to use ending time.
 * Changed format of schedule_area.
 * Changed all event_rec times to use time_rec structure.
 * Cleaned up do_incr and scroll_time so 'n' and 'p' consistent.
 * Fixed digit counting bug in enter_number.
 * Cleaned up code to "beep" for even more invalid keys.
 * Changed "monthd" to use process group to determine user logout.
 * Merged write_schedule into "common.a".
 * 
 * Revision 7.7  87/11/13  21:21:06  21:21:06  hull (James Hull)
 * Added global alias file for 'G' command.
 * 
 * Revision 7.6  87/11/13  21:20:16  21:20:16  hull (James Hull)
 * Changed get_npdeq to only show appropriate keys.
 * Cleaned up code to "beep" for most invalid keys.
 * 
 * Revision 7.5  87/11/13  21:19:39  21:19:39  hull (James Hull)
 * Split daemon into separate "monthd" program.
 * Created "common.a" library.
 * 
 * Revision 7.4  87/11/13  21:18:37  21:18:37  hull (James Hull)
 * Changed "goto mark" command from 'G' to '''.
 * Added 'G' (group post) command.
 * Minor fixes to push_area, pop_area, more, clear_message_line.
 * 
 * Revision 7.3  87/11/13  21:16:35  21:16:35  morrell (Michael Morrell)
 * Added 'p' (previous) to 'E' command; now identical to 'S'.
 * Fixed security hole in shell escape.
 * Added '-O' option and changed 'O' command to track date.
 * Cleaned up code to make lint happy.
 * 
 * Revision 7.2  87/11/13  21:15:59  21:15:59  hull (James Hull)
 * Added current date to print_sched.
 * Added special case for printing zero-length events.
 * 
 * Revision 7.1  87/11/13  21:15:21  21:15:21  hull (James Hull)
 * Fixed cursor initialization bug.
 * 
 * Revision 7.0  87/11/13  21:13:09  21:13:09  hull (James Hull)
 * Changed functions and event_rec to use date structure.
 * Added push/pop ara functions to fix cursor positioning bug.
 * Added cursor wraparound in months, days, and years areas.
 * Added '!' (shell escape) command.
 * Added 'e' (event editing) to 'E' command.
 * Added 'W' (write schedule) command.
 * 
 * Revision 6.1  87/11/13  21:12:38  21:12:38  hull (James Hull)
 * Fixed next/previous bug in month area when changing years.
 * 
 * Revision 6.0  87/11/13  21:11:55  21:11:55  hull (James Hull)
 * Added anti-events.
 * Fixed boundary conditions for dates.
 * Fixed get_date bug which trashed month, day, year.
 * 
 * Revision 5.3  87/11/13  21:09:22  21:09:22  hull (James Hull)
 * '?', 'C', and 'P' commands check area.
 * Fixed 'In' printf bug in remind.
 * Cleaned up hl_month_year.
 * Added hl_day and day selection (this_day underlined).
 * Removed warn_day and added return to m, d, or y area.
 * Split display.c into hl.c, move.c, print.c, user2.c.
 * Added 'a', 'i', 'k', and 'r' command-line options.
 * Added border around days area.
 * Cleaned up code to make lint happy.
 * 
 * Revision 5.2  87/11/13  21:07:34  21:07:34  hull (James Hull)
 * Added MONTH environment variable.
 * Fixed memory problem in get_home_dir & get_user_arg.
 * Removed many temp print buffers by using mvprintw.
 * Changed several numeric constants to named constants.
 * Added event description editing and insert-mode flag.
 * 
 * Revision 5.0  87/11/13  21:06:16  21:06:16  hull (James Hull)
 * Added warning time to events.
 * Made year optional in '/' command and on command line.
 * Added '?' (help) command and file.
 * 
 * Revision 4.0  87/11/13  21:05:43  21:05:43  hull (James Hull)
 * Added until date to events.
 * Replaced Accept/Cancel with ^A.
 * 
 * Revision 3.0  87/11/13  21:04:14  21:04:14  hull (James Hull)
 * Added owner to events allowing multi-user access.
 * Added read-only flag and '-R' flag.
 * Added version values to .month file and month program.
 * Wrote chmonth to update .month files to new versions.
 * 
 * Revision 2.0  87/11/13  21:03:22  21:03:22  hull (James Hull)
 * Added private flag to events.
 * Added direct entry of hours and minutes.
 * Added curses keypad input.
 * 
 * Revision 1.0  87/11/13  21:00:40  21:00:40  hull (James Hull)
 * Initial revision
 * 
 */

/*
The integer portion of version changes when the event structure changes.
The fractional portion changes for everything else.
*/

float
get_version()
{
	float version;

	(void) sscanf("$Revision: 8.7 $", "%*s%f", &version);
	return(version);
}
@EOF

chmod 644 version.c

exit 0

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