/*
 * Announce xcal appointment entries.  Typical use is to announce a few 
 * days' worth.  Also possible to dump every entry in "calendar" format.
 *
 *	Options: <date> - date to start at - mm/dd[/yy[yy]]
 *		 -d <RootDirectory> - of diary (default ~/Calendar)
 *		 -n <n> - where <n> is number of days to display
 *		 -c	- dump everything in "calendar" format;
 *				 ignores <date> and -n.
 */


#include <stdio.h>
#include <time.h>
#include <utmp.h>
#include <pwd.h>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FALSE 0
#define TRUE  1

void usage();

struct tm *tm;			/* hold times	*/
char rootdir[256];		/* build directory name here	*/
FILE *fd;			/* read file descriptor	*/
char filename[256];		/* to build filename in	*/
char *months[] = {
    "Jan", "Feb", "Mar", "Apr",
    "May", "Jun", "Jul", "Aug",
    "Sep", "Oct", "Nov", "Dec"
    };
int days_in_months[] = { 
    31, 28, 31, 30,
    31, 30, 31, 31,
    30, 31, 30, 31,
};


main(argc, argv)
unsigned int argc;
char **argv;
{
    int ndays;			/* number of days to announce	*/
    char c, *s;			/* reading and writing	*/
    char *dirname;		/* root directory name	*/
    struct passwd *pwd;
    long ti;
    int cdump = 0;		/* dump into calendar?	*/
    int i;


    /* defaults	*/
    ti = time(0);		/* default to today	*/
    tm = localtime(&ti);
    tm->tm_year += 1900;

    ndays = 1;			/* and to printing just one day	*/

    if ((pwd = getpwuid(getuid())) == NULL) {
	fprintf(stderr, "Who are you?\n");
	exit(42);
    };					     
    strcpy(rootdir, pwd->pw_dir);	/* default to home directory	*/
    endpwent();
    strcat(rootdir, "/Calendar");
    dirname = rootdir;


    /* check options	*/
    argc--, argv++;
    while (argc > 0) {

	if (isdigit(argv[0][0])) {
	    if ((sscanf(argv[0], "%d/%d/%d", &tm->tm_mon,
			&tm->tm_mday, &tm->tm_year)) < 2) { 
		usage();
		exit(1);
	    }
	    else {
		tm->tm_mon--;	/* internal month # is 0-11	*/
		if (valid_date() != 0) {	 /* user-supplied date	*/
						 /* must make sense	*/
		    usage();
		    exit(2);
		}
	    }

	}			/* end if first character is digit	*/
	else if (argv[0][0] == '-') {
	    switch(argv[0][1]) {
	    case 'd':		/* dirname	*/
		if (--argc <=0) {
		    usage();	/* nothing there	*/
		    exit(3);
		}
		dirname = (++argv)[0];
		break;
	    case 'n':		/* number of days	*/
		if (--argc <= 0) {
		    usage();	/* nothing there	*/
		    exit(4);
		}
		if ((sscanf((++argv)[0], "%d", &ndays)) != 1) {
		    usage();	/* nothing there	*/
		    exit(5);
		}
		break;
	    case 'c':
		cdump = 1;
		break;
	    default:
		usage();
		exit(6);
	    }
	}
	argc--, argv++;
    }

    if (cdump) {		/* a dump?	*/
	return(dumpit(dirname));	/* go do so	*/
    }

    while (ndays--) {	/* otherwise loop, for each day requested	*/

	valid_date();	/* Make current m, d, y make sense	*/

	/* build filename -- e.g. "/mu/swb/Calendar/xy1990/xc1Oct1990"	*/
	sprintf(filename, "%s/xy%04d/xc%d%s%d",
		dirname, tm->tm_year, tm->tm_mday,
		months[tm->tm_mon], tm->tm_year); 

	/* Read from file, if it exists, and print.	*/
	if (fd = fopen(filename, "r")) {
	    fprintf(stdout, "%02d %s %d:\n------------\n",
		    tm->tm_mday, months[tm->tm_mon], tm->tm_year);
	    while ((c = getc(fd)) != EOF) putc(c, stdout);
	    fclose(fd);
	    fprintf(stdout, "\n");
	}

	tm->tm_mday++;		/* do the next day	*/
    }
    exit(0);
}

/*
 * valid_date takes the (external) date and makes it reasonable.  First
 * it increments the month until the day given is within a month (as
 * opposed to, say, 3/47/91).  Then it increments the year until the
 * month is valid.  Right now it doesn't know anything about leap
 * years. 
 */

valid_date()
{
    int rc;

    rc = 0;
    days_in_months[1] = 28;	/* default */
    if (leap_year(tm->tm_year)) days_in_months[1] = 29;

    while (tm->tm_mday > days_in_months[tm->tm_mon]) {
	tm->tm_mday -= days_in_months[tm->tm_mon];
	tm->tm_mon++;
	rc++;
    }

    while (tm->tm_mon >= 12) {	/* month should be 0-11	*/
	tm->tm_mon -= 12;
	tm->tm_year++;
	rc++;
    }

    return(rc);
}

/*
 * leap year?
 */
int leap_year(year)
int year;
{

    if (year%4000 == 0) return FALSE;
    else if (year%400 == 0) return TRUE;
    else if (year%100 == 0) return FALSE;
    else if (year%4 == 0) return TRUE;
    else return FALSE;

}



/*
 * explain usage
 */
void
usage()
{
    fprintf(stderr, "Usage: [date] [-d directory] [-n ndays] [-c]\n");
    fprintf(stderr, "         -c dumps all entries in calendar(1) format.\n");
}

/*
 * dumpit dumps every single xcal entry pre-ambled with monthname,
 * day, and year.
 */
dumpit(dirname)
    char *dirname;
{
    DIR	*Cdirp, *ydirp;
    struct dirent	*Centp, *yentp;
    struct stat	statbuf;
    char	*Cpathend, *ypathend;	/* loc for fname in filepath	*/
    char	*year;		/* ascii year			*/
    char	prebuf[14];	/* "calendar" preamble space	*/
    char	inbuf[1024];
    int i;

    if ((Cdirp = opendir(dirname)) == NULL) {	/* top xcal dir	*/	
	perror(dirname);
	return(errno);
    }

    strcpy(filename, dirname);	/* initialize file path	*/
    strcat(filename, "/");
    Cpathend = filename + strlen(filename);	/* put year dir here	*/
    

    /* for each year directory	*/
    while ((Centp = readdir(Cdirp)) != NULL) {	/* foreach year dir	*/
	
	if (Centp->d_name[0] == '.') continue;	/* no ., ..	*/	

	/* check each year directory	*/
	strcpy(Cpathend, Centp->d_name);	/* build filename	*/
	if ((i = stat(filename, &statbuf)) != 0) {
	    perror(filename);
	    return(errno);
	}
	if (!S_ISDIR(statbuf.st_mode)) {
/*	    fprintf(stderr, "%s not a directory, ignoring ... \n",	*/
/*		    filename);						*/
	    continue;
	}

	if ((ydirp = opendir(filename)) == NULL) {
	    perror(filename);
	    return(errno);
	}
	strcat(filename, "/");	/* path to open data files		*/
	year = Centp->d_name + 2;	/* use year in preamble		*/
	ypathend = filename + strlen(filename);	/* where to put fnames	*/


	/* for each day file in year dir	*/
	while ((yentp = readdir(ydirp)) != NULL) {
	
	    if (yentp->d_name[0] == '.') continue;
	    strcpy(ypathend, yentp->d_name);
	    if ((i = stat(filename, &statbuf)) != 0) {
		perror(filename);
		return(errno);
	    }
	    if (!S_ISREG(statbuf.st_mode)) {
/*		fprintf(stderr,						*/
/*			"%s not a regular file, ignoring ... \n",	*/
/*		       filename);					*/
		continue;
	    }

	    /* build what to dump in front of info	*/
	    sscanf( &(yentp->d_name[2]), "%d%3c", &i, prebuf);
	    *(prebuf+3) = '.'; sprintf(prebuf+4, " %02d ", i);
	    strncpy(prebuf+8, year, 4);
	    *(prebuf+12) = '\0';

	    /* open file and put each line in stdout, prepended	*/
	    /* with the contents of prebuf and a tab.		*/
	    
	    if (!(fd = fopen(filename, "r"))) {
		fprintf(stderr,
			"Error %d opening %s, ignoring ... \n", errno,
		       filename);
		continue;	/* the foreach file loop	*/
	    }
	    
	    while (fgets(inbuf, sizeof(inbuf), fd)) {
		printf("%s\t%s", prebuf, inbuf);
		if (*(inbuf + strlen(inbuf) - 1) != '\n')
		    printf("\n");
	    }
	    fclose(fd);

	}			/* end for each day file	*/
	
	if ((closedir(ydirp)) != 0) {
	    *(ypathend-1) = '\0';	/* reinit to just dirname	*/
	    perror(filename);
	}
    }				/* end for each year	*/

    if ((closedir(Cdirp)) != 0) {
	perror(dirname);
	return(errno);
    }

    return(0);
}
