| 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. 
 
 
 |