Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v06i099: Happy birthday to you...

19 views
Skip to first unread message

Brandon S. Allbery - comp.sources.misc

unread,
May 14, 1989, 11:29:05 PM5/14/89
to
Posting-number: Volume 6, Issue 99
Submitted-by: rs...@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 rs...@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, <rs...@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, <rs...@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, <rs...@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 <wiz...@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 rs...@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
Xrs...@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

0 new messages