Customizing Your Calendar Program
Steven G. Isaacson
Our Human Resources department asked if it was possible
to automatically
mail reminders about employee annual reviews. An additional
requirement
was that the reminders be mailed to more than one person:
the department
leader, team leader, etc.
We considered writing a custom reminder program -- easy
to do with
cron and a shell script -- but when it came time to
decide
upon a date format (would it be mm/dd/yy, mm/dd/yyyy,
September 20,
1995?), we decided instead to use the existing calendar
program,
which already knows how to handle dates in a variety
of formats.
This article describes a shell script that works like
/bin/calendar
but adds the ability to send mail to more than one user,
allows multiple
lines per calendar entry, supports include files, and
adds support
for keywords like Daily, Monday, Tuesday, Weekend, etc.
calendar
The /usr/bin/calendar program is a handy reminder service.
By default it looks in your $HOME directory for a file
called
calendar and examines each line for a date. If the date
matches
today or tomorrow (Monday is "tomorrow" for
Friday) then you
are sent reminder mail. On most systems, calendar is
run automatically
from cron.
Here are sample calendar entries:
March 10 -- Sys Admin budget meeting
Jan 5 1995 -- new workstations should arrive next week
Sep 10 -- Anniversary on Sep 20th Send flowers!
Note that line three contains two dates, the 10th and
the 20th. So mail is sent on September 9th and 10th,
and then again
on the 19th and 20th.
Although handy, the calendar program is limited. Only
one
line per entry is allowed and mail is sent to only one
user. Both
of these problems were addressed with our custom calendar.sh
(Listing 1).
Multiple Address
To support multiple email addresses, we had to do two
things: 1) decide
upon an extended format for the calendar entry (i.e.,
some
way to specify the email addresses), and 2) run calendar
manually.
The extended format is as follows:
[email address(es)]| [calendar entry]
Example:
petera sysadm@central| March 10 Sys Admin budget meeting
On March 9th and 10th this calendar entry will be sent
to petera and sysadm@central.
Running calendar Manually
/usr/bin/calendar is actually a shell script that uses
/usr/lib/calprog (a binary program) to figure out what
dates to
look for in the calendar file. Specifically, calprog
figures out which dates to look for by generating regular
expressions
-- one for today and one for tomorrow. On Fridays --
recall
that Monday is "tomorrow" for Friday -- four
regular expressions
are generated. One for Friday, Saturday, Sunday, and
Monday.
On September 7th, for example, calprog generated these
two
regular expressions. The first matches September 7 dates;
the second
matches September 8 dates.
(^|[ (,;])([Ss]ep[^ ]* *|0*9/|\*/)0*7)([^0123456789]|$)
(^|[ (,;])([Ss]ep[^ ]* *|0*9/|\*/)0*8)([^0123456789]|$)
You'll probably never see a more complex regular expression
(for more information on regular expressions see Larry
Reznick's "Using
Regular Expressions," Sys Admin September/October
1992,
vol. 1, no. 3). I was surprised to see that the second
and third letters
of the month are case-sensitive. Sep 7 is a valid calendar
entry,
but SEP 7 isn't!
The calendar program uses calprog to write the regular
expressions to a file. Then egrep, using the regular
expressions
written to the file, scans the calendar file in your
$HOME
directory. To wit:
# create regular expression file
calprog > re.file
# egrep for matches
egrep -f re.file $HOME/calendar
The output, if any, is mailed to you. That's the stock
calendar program -- crude but effective.
Our version of calendar does the same thing, and more.
The
regular expressions for grabbing the correct dates are
generated in
the same way, with /usr/lib/calprog, but instead of
always
sending mail to whoever happens to be running the program,
mail is
sent to the name or names in the first field, the first
field being
everything up to the first pipe symbol. If there is
no first field,
that is, no pipe symbol, then mail is sent to the current
user.
Adding calendar.sh to a nightly cron job and specifing
the calendar file was now all that it took to send calendar
entries to more than one person. Our Human Resources
department was
happy -- but only for a while. Almost immediately there
were requests
for multiple-line calendar entries.
Multiple-Line Calendar Entries
Making calendar.sh send more than one line of information
per entry was easy once the "trick" was figured
out. Consider
the problem. If all entries are only one line, there
isn't a problem.
But some entries are more than one line. So . . .
convert all multi-line
entries to one line, do what you normally do, then undo
the multi-line
conversion before sending the mail.
Here's an example of how it works. This three-line entry
sysadm| Sep 20 Big meeting Be \
There!
is first converted to
sysadm| Sep 20 Big meeting <nl> Be <nl> There!
Each escape character at the end of the line is converted
to <nl> and then converted back again after the
regular calendar
processing is done. So, there are no multiple-line entries;
the problem is solved by ignoring it for a while.
Include Files
Another way to support multiple-line calendar entries
is with include
files. For example: suppose you have quarterly employee
reviews and
want to remind the mail recipients to, say, use a particular
form. One
way to remind them to use the form is by including the
form in the
mail. This feature was easy to add.
The include file syntax is:
[address]| [calendar entry [#f:[filename]]]
as, for example:
sysadm| Sep 20 Big meeting #f:/usr/uubob/big_notes
What happens is that after the calendar entry is selected,
the entry is scanned for the #f: keyword. If the keyword
is
found, the specified file is included in the email.
Shell Commands
Included files are included via cat. That is, a shell
command
(cat [filename]) is executed from within the awk program
that searches for the #f: keyword. If cat is useful,
how about other commands? For example, df to show the
free
disk space, or who, to show who is still logged in early
in
the morning when cron runs calendar.sh.
The shell command syntax is:
[address]| [calendar entry [#!:[shell command]]]
Example:
sysadm| Sep 20 Big meeting #!:df bring disk space report
Recurring Entries
Suppose, now that you have a truly simple means of sending
yourself
or anyone else mail about current disk space, that you'd
like to have
the mail sent daily. You can't do it with the present
calendar scheme,
because once an entry is used, that's it -- no more
mail about
September 20 meetings until the next Sep 20, next year.
So, a nice
addition would be support for keywords such as "Daily,"
"Monday,"
"Tuesday," etc. Adding new keywords to calendar.sh
is simple. For example, to support the days of the week,
add "Monday"
to the regular expression list on Mondays, add "Tuesday"
to
the regular expression list on Tuesday, and so on. To
support "Daily,"
add "Daily" to the list each day. To support
"Weekend,"
add "Weekend" to the regular expression list
on Saturday and
Sunday.
Installing calendar.sh
Installing calendar.sh is easy. Create a calendar
file (or .calendar to avoid conflicts with /usr/bin/calendar)
in your HOME directory, then add an entry to your crontab
to run calendar.sh. Figure 1 shows a sample crontab
entry.
About the Author
Steven G. Isaacson has been programming professionally
since 1985. He works for
FourGen Software, the leading developers of accounting
software and
CASE Tools for the UNIX market. He may be reached at
uunet!4gen!stevei or stevei@fourgen.com.
|