allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (05/15/89)
Posting-number: Volume 6, Issue 99 Submitted-by: rsalz@bbn.com (Rich Salz) Archive-name: bday There used to be a machine called oz.ai.mit.edu, and it used to have a wizard who knew when it was your birthday. He was a friendly wizard, not at all deserving of the name "daemon," because he'd send you a nice little note when that special day came around... I had been saving one of my messages for some time, but only just now got around to writing this program. It reads a file with email names and birthdays, and sends mail. It should be run out of cron early every morning. If WEEKEND_HACK is #define'd, then on Friday bday will send mail to people with birthdays on Saturday and Sunday. The program uses getopt and sendmail, but hacking around the latter should be pretty easy. /rich $alz #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 1)." # Contents: MANIFEST Makefile README bday.8 bday.c bdaylist bdaymesg # Wrapped by rsalz@papaya.bbn.com on Mon May 8 11:17:21 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'MANIFEST' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'MANIFEST'\" else echo shar: Extracting \"'MANIFEST'\" \(459 characters\) sed "s/^X//" >'MANIFEST' <<'END_OF_FILE' X File Name Archive # Description X----------------------------------------------------------- X MANIFEST 1 This shipping list X Makefile 1 Makefile for birthday greetings X README 1 Random stuff X bday.8 1 Manual page X bday.c 1 Send birthday greetings to users X bdaylist 1 Control file for bday X bdaymesg 1 Message file for bday END_OF_FILE if test 459 -ne `wc -c <'MANIFEST'`; then echo shar: \"'MANIFEST'\" unpacked with wrong size! fi # end of 'MANIFEST' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(489 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X## X## Makefile for birthday greetings. X## Written by Rich $alz, <rsalz@bbn.com>. This package has no copyright. X## $Header: Makefile,v 1.1 89/05/08 11:07:14 rsalz Exp $ X## X XCFLAGS = -O X Xall: bday bday.8 X Xinstall: all X @echo "Install according to local convention" X Xclean: X rm -f foo core SHAR tags lint a.out *.o bday X Xbday: bday.c X @rm -f bday X $(CC) -o bday $(CFLAGS) bday.c X X## I know it fits in one kit, so... Xkit: X @rm -f SHAR X makekit -m X @rm -f MANIFEST.BAK X @mv Part01 SHAR END_OF_FILE if test 489 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(699 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X XThere used to be a machine called oz.ai.mit.edu, and it used to have a Xwizard who knew when it was your birthday. He was a friendly wizard, not Xat all deserving of the name "daemon," because he'd send you a nice little Xnote when that special day came around... X XI had been saving one of my messages for some time, but only just now got Xaround to writing this program. It reads a file with email names and Xbirthdays, and sends mail. It should be run out of cron early every Xmorning. If WEEKEND_HACK is #define'd, then on Friday bday will send mail Xto people with birthdays on Saturday and Sunday. X XThe program uses getopt and sendmail, but hacking around the latter should Xbe pretty easy. X X /r$ END_OF_FILE if test 699 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'bday.8' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'bday.8'\" else echo shar: Extracting \"'bday.8'\" \(1936 characters\) sed "s/^X//" >'bday.8' <<'END_OF_FILE' X.\" $Header: bday.8,v 1.1 89/05/08 11:07:38 rsalz Exp $" X.TH BDAY 8 X.SH NAME Xbday \- birthday daemon X.SH SYNOPSIS X.B bday X[ X.BI \-b birthdays X] [ X.BI \-m message X] [ X.BI \-r report_to X] [ X.BI \-s sendmail_cmd X] X.SH DESCRIPTION X.I Bday Xis a program intended to be run every day out of X.IR cron (1). XIt reads a file containing a list of user names and birthdays, Xand sends a message to anyone whose birthday is today. XThe ``\-r'' option may be used to specify a person who should receive Xa report whenever a greeting is sent. X.PP XThe ``\-b'' option may be used to specify the file containing the list Xof people's birthdays; the default is X.IR /usr/adm/bdaylist . XThis file should consist of a series of lines of three fields, each separated Xby whitespace: X.RS X.nf X.ta \w'#emailname 'u +\w'month 'u X#emailname month day Xrsalz 2 10 X.fi X.RE XThe first column is the name of the person to send the email message to. XThe second column is the month in which the person's birthday occurs; X1 is for January, and so on up to 12 for December. XThe third column is the day of the month on which their birthday occurs. XBlank lines, and any text after a pound sign is ignored. X.PP XThe ``\-m'' option may be used to specify the file with the birthday message; Xthe default is X.IR /usr/adm/bdaymesg . XThis is useful, for example, to send different greetings to people who's Xbirthday falls on a weekend. X.PP XThe command used to send the mail may be changed by giving the ``\-s'' Xoption; this is useful for debugging. XNote that the details of sending the message (such as the mail headers) Xare compiled into the code, but that's okay because this is just a short Xfun hack, anyhow. X.SH AUTHOR XWritten by Rich $alz, <rsalz@bbn.com>, after receiving just such a message Xfrom one of the machine at MIT. This package has no copyright. X.SH FILES X.ta \w'/usr/adm/bdaylist 'u X/usr/adm/bdaylist Default birthday list X/usr/adm/bdaymesg Default birthday message END_OF_FILE if test 1936 -ne `wc -c <'bday.8'`; then echo shar: \"'bday.8'\" unpacked with wrong size! fi # end of 'bday.8' fi if test -f 'bday.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'bday.c'\" else echo shar: Extracting \"'bday.c'\" \(6081 characters\) sed "s/^X//" >'bday.c' <<'END_OF_FILE' X/* X** When you care enough to send the very best.... X** Written by Rich $alz, <rsalz@bbn.com>, after seeing the MIT program X** in action. This package has no copyright. X*/ X#include <stdio.h> X#include <ctype.h> X#include <sys/types.h> X#include <time.h> X#include <fcntl.h> X#include <sgtty.h> X#ifndef lint X#ifndef SABER Xstatic char RCS[] = X "$Header: bday.c,v 1.1 89/05/08 11:13:22 rsalz Exp $"; X#endif /* SABER */ X#endif /* lint */ X X/* Compilation control. */ X#define STRCHR strchr /* Maybe index */ X#define STRRCHR strrchr /* Maybe rindex */ X#undef WEEKEND_HACK /* Work harder on Friday? */ X X/* Manifest constants. */ X#define TRUE 1 X#define FALSE 0 X#define LEN 128 X#define FROM "The Birthday Wizard <wizard@pineapple.bbn.com>" X X/* Syntactic sugar. */ X#define WHITE(c) ((c) == ' ' || (c) == '\t') X#define Fprintf (void)fprintf X#ifdef lint X#undef putc X#endif /* lint */ X X X/* Global data. */ Xstatic char *progname; Xstatic char *ReportTo = NULL; Xstatic char *Birthdays = "/usr/adm/bdaylist"; Xstatic char *Message = "/usr/adm/bdaymesg"; Xstatic char *sendmail = "/usr/lib/sendmail.sun -t -oi"; X/*static char *sendmail = "/usr/lib/sendmail -t -oi"; */ X X X/* Linked in later. */ Xextern int errno; Xextern char *optarg; Xextern time_t time(); Xextern char *sprintf(); /* Too painful, my ass */ Xextern char *strcpy(); Xextern char *STRCHR(); Xextern char *STRRCHR(); X X X/* X** Return the text string that corresponds to errno. X*/ Xstatic char * Xstrerror(e) X int e; X{ X extern int sys_nerr; X extern char *sys_errlist[]; X static char buff[30]; X X if (e > 0 && e < sys_nerr) X return sys_errlist[e]; X (void)sprintf(buff, "Error code %d", e); X return buff; X} X X X/* X** Send mail to the person. X*/ Xstatic void XDoit(Name) X char *Name; X{ X register FILE *F; X register FILE *M; X register int c; X X /* Prep the pipe. */ X if ((F = popen(sendmail, "w")) == NULL) { X Fprintf(stderr, "%s: Doit(%s) failed to popen \"%s\", %s.\n", X progname, Name, sendmail, strerror(errno)); X return; X } X X /* Write headers. */ X Fprintf(F, "From: %s\n", FROM); X Fprintf(F, "To: %s\n", Name); X Fprintf(F, "Subject: Happy birthday!\n"); X Fprintf(F, "\n"); X X /* Feed in the message. */ X if (M = fopen(Message, "r")) { X while ((c = getc(M)) != EOF) X (void)putc(c, F); X (void)fclose(M); X } X X /* Close up. Done? */ X (void)pclose(F); X if (ReportTo == NULL) X return; X X /* Report it. */ X if ((F = popen(sendmail, "w")) == NULL) { X Fprintf(stderr, "%s: Doit(%s) couldn't report, %s.\n", X progname, Name, strerror(errno)); X return; X } X X /* Write the report. */ X Fprintf(F, "To: %s\n", ReportTo); X Fprintf(F, "Subject: Greetings sent\n"); X Fprintf(F, "\n"); X Fprintf(F, "Sent a message to %s.\n", Name); X X /* Close up. Definitely done. */ X (void)pclose(F); X} X X X/* X** Return pointer to first non-whitespace. X*/ Xstatic char * XSkip(p) X register char *p; X{ X while (*p && WHITE(*p)) X p++; X return p; X} X X X/* X** Check the list in the file for birthdays. X*/ Xstatic void XScanForWork(ThisMonth, ThisDay) X int ThisMonth; X int ThisDay; X{ X register FILE *F; X register char *p; X int UserMonth; X int UserDay; X char UserName[LEN]; X char buff[LEN]; X X /* Open the list of birthdays. */ X if ((F = fopen(Birthdays, "r")) == NULL) { X Fprintf(stderr, "%s: ScanForWork can't open \"%s\" for reading, %s.\n", X progname, Birthdays, strerror(errno)); X return; X } X X /* Scan all lines. */ X while (fgets(buff, sizeof buff, F)) { X /* Clobber comment markers and newlines. */ X if (p = STRCHR(buff, '#')) X *p = '\0'; X if (p = STRCHR(buff, '\n')) X *p = '\0'; X X /* Skip blank or comment lines. */ X if (buff[0] == '\0') X continue; X X /* First field is the user name. */ X for (p = buff; *p && !WHITE(*p); p++) X ; X *p++ = '\0'; X (void)strcpy(UserName, buff); X if (UserName[0] == '\0') X continue; X X /* Second field is the month of the user's birthday. */ X p = Skip(p); X if (*p == '\0') X continue; X for (UserMonth = atoi(p); *p && isdigit(*p); p++) X ; X if (UserMonth == 0) X continue; X X /* Third field is the date of the user's birthday. */ X p = Skip(p); X if (*p == '\0') X continue; X UserDay = atoi(p); X if (UserDay == 0) X continue; X X /* Is this one for us? */ X if (UserMonth == ThisMonth && UserDay == ThisDay) X Doit(UserName); X } X X (void)fclose(F); X} X X X/* X** Make sure the file was specified and is readable. X*/ Xstatic void XCheckFile(Name, Purpose) X char *Name; X char *Purpose; X{ X FILE *F; X X if (Name == NULL) { X Fprintf(stderr, "%s: No %s file given.\n", progname, Purpose); X exit(1); X } X X if ((F = fopen(Name, "r")) == NULL) { X Fprintf(stderr, "%s: Can't open \"%s\" for %s, %s.\n", X progname, Name, Purpose, strerror(errno)); X exit(1); X } X X (void)fclose(F); X} X X Xmain(ac, av) X int ac; X char *av[]; X{ X int i; X time_t t; X struct tm *tm; X char *p; X X /* Parse JCL. */ X progname = (p = STRRCHR(av[0], '/')) ? p + 1 : av[0]; X while ((i = getopt(ac, av, "b:m:r:s:")) != EOF) X switch (i) { X default: X Fprintf(stderr, "Usage:\n\t%s %s\n", X progname, X "[-b list] [-m message] [-s sendcmd] [-r admin]"); X exit(1); X case 'b': X Birthdays = optarg; X break; X case 'm': X Message = optarg; X break; X case 'r': X ReportTo = optarg; X break; X case 's': X sendmail = optarg; X break; X } X X /* Make sure the user gave us readable files. */ X CheckFile(Birthdays, "birthday list"); X CheckFile(Message, "message"); X X /* What time is it? */ X t = time((time_t *)NULL); X tm = localtime(&t); X ScanForWork(tm->tm_mon + 1, tm->tm_mday); X X#ifdef WEEKEND_HACK X /* If it's Friday, check for Saturday and Sunday birthdays. */ X if (tm->tm_wday == 5) { X /* This is easy/sleazy, we avoid checking for end of month... */ X t += 24 * 60 * 60; X tm = localtime(&t); X ScanForWork(tm->tm_mon + 1, tm->tm_mday); X t += 24 * 60 * 60; X tm = localtime(&t); X ScanForWork(tm->tm_mon + 1, tm->tm_mday); X } X#endif /* WEEKEND_HACK */ X X exit(0); X} END_OF_FILE if test 6081 -ne `wc -c <'bday.c'`; then echo shar: \"'bday.c'\" unpacked with wrong size! fi # end of 'bday.c' fi if test -f 'bdaylist' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'bdaylist'\" else echo shar: Extracting \"'bdaylist'\" \(227 characters\) sed "s/^X//" >'bdaylist' <<'END_OF_FILE' X## Data file for birthday program. Written by rsalz@bbn.com; this package X## has no copyright. X## $Header: bdaylist,v 1.1 89/05/08 11:07:48 rsalz Exp $ X## Data lines look like this: X##email month day Xrsalz@bbn.com 2 10 END_OF_FILE if test 227 -ne `wc -c <'bdaylist'`; then echo shar: \"'bdaylist'\" unpacked with wrong size! fi # end of 'bdaylist' fi if test -f 'bdaymesg' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'bdaymesg'\" else echo shar: Extracting \"'bdaymesg'\" \(2880 characters\) sed "s/^X//" >'bdaymesg' <<'END_OF_FILE' X X YY X YYYY YY XHHHHH HHHHH YYY YYYY XHHHHH HHHHH PP PPPPPP YYY YYY X HHH HHH PPP PP YYY YYY X HHH HHH AAAAA PP PPPPPP PP PP YYY YYY X HHH HHH AAAAAAA PPP PP PP PP YYY YYY X HHH HHH AA AA PP PP PP PP YYY YYY X HHH HHH AA AA PP PP PPPPPPP YYYYY X HHHHHHHHHHHHHHH AA AA PP PP PP YYYY X HHHHHHHHHHHHHHH AA AA PPPPPPP PP YYYY ------- X HHHHHHHHHHHHHHH AAAAAAAAA PP PP YYYY ------- X HHH HHH AAAAAAAAA PP PP YYYY ------- X HHH HHH AA AA PP PP YYYY X HHH HHH AA AA PP PP YYYY X HHH HHH AA AA PP PP YYYYYY X HHH HHH AA AA PP PP YYYYYYY X HHH HHH PP PP YYYYYYY XHHHHH HHHHH PP PP YYYYYYY XHHHHH HHHHH PP PP YYYYYYY X YYYYY XBBBBBBBBBBBBB YYY XBBBBBBBBBBBBBB Y X BBBB BBB II YYY YYY X BB BB II DDDDDDDDDDDDD YYYY YYYY X BB BB DDDDDDDDDDDDDD YY YY X BB BB III RRR RRRR DDD DDD A YY YY X BB BB II RRRR RR DDD DDD AAA YY YY X BB BBB II RRR DDD DDD AAAAA YY YY X BBB BBBB II RR DDD DDD AAAAAAA YY YY X BBBBBBBBBBB II RR DDD DDD AA AA YY YY X BBBBBBBBB II RR DDD DDD AA AA YYYY X BBBBBBBBBBB II RR DDD DDD AAAAAAAAA YYY X BBB BBBB IIII RRRR DDD DDD AAAAAAAAA YYY X BB BBB HHH DDD DDD AA AA YYY X BB BBB TT HHHH DDD DDD AA AA YYY X BB BBB TT HH DDD DDD AA AA YYY X BB BBB TTTTTT HH DDD DDD AA AA YYY X BB BBB TT HH DDD DDD YYY X BB BBB TT HHHHHHHH DDDDDDDDDDDDD YYY X BB BBB TT HH HH DDDDDDDDDDDD YYYY X BBBB BBBB TT HH HH YYYY XBBBBBBBBBBBBBBB TT TT HH HH YYYYYYYYYYYYYYYYYYYYYYYYYY XBBBBBBBBBBBBBB TTTT HH HH YYYYYYYYYYYYYYYYYYYYYYYY X HHHH HHHH YYYYYYYYYYYYYYYYYYYYYY END_OF_FILE if test 2880 -ne `wc -c <'bdaymesg'`; then echo shar: \"'bdaymesg'\" unpacked with wrong size! fi # end of 'bdaymesg' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0