These scripts extend the functionality of the 'when' calendar utility
(http://lightandmatter.coom/when/when.html) to provide a means of
receiving reminder notifications.
For more information: http://chipstips.com/?tag=rbremindwhen
BitBucket repository: http://bitbucket.org/sterlingcamden/remindwhen/
The following scripts are provided:
remindwhen.rb Parses 'when' calendars looking for events that are due
remind Adds an event to the 'reminders' calendar
reminders Shows today's events from the 'reminders' calendar
alarm Turn audible alarms on/off, and/or test current state
echoif Conditional echo
tocal Pipe when output to an HTML calendar
whencal View when calendar in w3m
ical2when.rb Convert iCalendar to a when entry
icalview.rb View iCalendar
icalorg.rb Extract organizer from iCalendar
icalrespond.rb Create an iCalendar response
icalmutt.rb iCalendar handler for mutt
These scripts presume that the user has two 'when' calendars:
~/.when/calendar The default 'when' calendar
~/.when/reminders A calendar for reminders only
The 'reminders' calendar will be created if it does not exist the first time
you add a reminder using 'remind'.
The reason for having separate calendars is that many reminders (especially
recurring ones) are not really calendar events, and the user may not want to
see those when invoking 'when' directly. For instance, I have a reminder set
for every day at 6PM to tell me to stop work. If that reminder were placed
on my regular calendar, I'd see seven of them in a weekly calendar listing.
This script is designed to be run at timed intervals, but you can also invoke
it from the command line. It parses first the 'reminders' calendar, and then
the default calendar, looking for entries that are due on today's date and
that contain a time in the form HH:MM[pm]. That is, one or two digits of hours,
colon, one or two digits of minutes, and an optional "pm" (case-insensitive).
If found, this string is passed to Ruby's Time#parse method to produce a Time
By default, if that time is on or after the current time but not more than three
minutes beyond the current time, the event is considered due. You can create
an advance warning by following the time with then +n, where n is the number of
minutes of advance warning (any number of digits). For example:
2010 May 5, 2:35pm +5 Fix typos in README
Will notify me at 2:30. Note that whitespace between the time and advance is
The advance can optionally be followed by the letter q (case-insensitive) to
specify that the notification should be quiet. That means that no sound should
be played. By default, if the file ~/.when/reminder.wav exists, it will be
played whenever remindwhen.rb prints an event to stdout. You may specify the
quiet option without an advance as just "+q". Examples:
2010 May 28, 2:00pm +5q Add new features to README
2010 May 28, 2:20pm +q Post on Chip's Tips
The first event will begin notification at five minutes before 2 without sound,
and the second will begin at 2:20 also without sound.
remindwhen.rb strips off the date, advance, and any q option, and sends
"Reminder: " followed by the event text (including the time as specified) to stdout.
Each reminder is terminated by a newline.
Thus, for instance, you can include the first reminder due in xmobar by adding
the following command to your .xmobarrc:
Run Com "remindwhen.rb"  "reminders" 600
This runs the script every 60 seconds and sends the output to an xmobar
template variable named "reminders". You could also mail the output to yourself,
send it to a dzen/xmessage window, or whatever notification mechanism tickles
your tickler sensitivities.
This command-line tool allows you to easily add reminders to the 'reminders'
remind time event
where time is a time in the format expected (HH:MM[pm][+advance]).
event is the text of the reminder. Be smart and use quotes.
remind adds the event to the end of ~/.when/reminders, creating it if it does
not exist. Today's date is presumed -- if you want a reminder for tomorrow,
you'll have to use 'reminders e' as shown below.
This simple script calls 'when' to list the reminders calendar, limited to today's
events, when called without arguments. You can, however, pass arguments that
will in turn be passed to 'when'. So, to edit the reminders calendar, you can
This shell script returns 0 if ~/.when/reminder.wav exists, otherwise 1. It can
optionally take an argument:
"off" if ~/.when/reminder.wav exists, renames it to ~/.when/reminder_off.wav
"on" if ~/.when/reminder.wav does not exists, renames ~/.when/reminder_off.wav
Any other argument value is ignored. In any case, the return value reflects the
This shell script conditionally echoes a string to stdout. Usage:
echoif <cond> <then> <else>
where <cond> is an expression that will be evaluated for truth (in /bin/sh)
<then> is an expression to echo if true
<else> is an expression to echo if false
You may wish to enclose each argument in quotes for safety's sake.
echoif alarm "on" "off"
In my own case, I want to have an xmobar notification whenever I have alarms muted,
so I added a line to .xmobarrc like so:
Run Com "echoif" ["alarm '' ' MUTE'"] "remindmuted" 60
which displays " MUTE" in the bar whenever alarms are off. Note how I pass an empty
string to echo nothing when alarms are not muted.
echoif is also useful for composing conditional shell commands. For instance, I
have mod4-shift-M mapped in xmonad to toggle alarm muting as follows:
, ((mod4Mask .|. shiftMask, xK_m), spawn "alarm `echoif alarm off on`")
So if the inner call to alarm returns true, I pass "off" to the outer call,
Naturally, echoif's usefulness extends beyond the realm of reminders and xmonad.
This ruby script takes input in when's output format and reformats it to
feed into the pcal utility (http://pcal.sourceforge.net) to render an HTML
calendar that includes the specified dates. The HTML is sent to stdout.
This script is used by whencal below.
Generates a calendar from when and views it in w3m. You can pass any arguments
to whencal that are supported by when. The w3m browser (http://w3m.sourceforge.net)
will be invoked to view the resulting calendar, which includes all the dates that
I chose w3m because, unlike many browsers, it can receive its page from stdin.
The when options --wrap=0 and --nopaging are on by default to keep the pipe
will view a calendar for the next year.
Takes iCalendar entries on stdin or via file arguments and produces one when entry
for each event on stdout. The iCalendar dtstart is converted to the local time zone,
and the event summary is used as the text of the when entry (after the time). If
the event has an alarm with a trigger that specifies a negative offset from the start
time in minutes, then "+n" is appended to the time (where n is the number of minutes)
as expected by remindwhen.rb.
This script make a useful pipe from MUAs such as mutt. For example, you could
map Ctrl+W in mutt's attachment menu to save the attachment to your when calendar
by adding the following to .muttrc:
macro attach \Cw "|ical2when.rb >> ~/.when/calendar\n" "Add appointment to when"
A simple text view of an iCalendar. This script does not view attachments, nor does
it include all possible iCalendar elements, but it hits the high points. I use it to
view iCalendar attachments from mutt by adding this to my .mailcap:
text/calendar; icalview.rb %s | less;
But see icalmutt.rb below for a more comprehensive solution.
Extracts the originator from an iCalendar and sends it to stdout.
Takes iCalendar entries on stdin or via file arguments and produces an iCalendar
response, depending on the mode switch. Options include:
-a, --accept Accept the appointment
-d, --decline Decline the appointment
-i, --identity email Specify which responder you are
-m, --message msg Message to accompany response
-t, --tentative Tentatively accept
Exactly one of -a, -d, or -t must be passed, along with -i and your email address
prefixed with "mailto:".
If you include the -m option, then you can specify the message to include as the
iCalendar DESCRIPTION. Otherwise, the original description will be used.
The output (to stdout) is an iCalendar that can be sent as an attachment of
content/type text/calendar. If you name the file with the .ics extension, mutt
will automatically apply that content/type.
This script is designed specifically for use with mutt. It takes a received
iCalendar attachment as an argument, along with the option '-i identity' as in
icalrespond.rb above. This script combines the features of the above scripts:
1. The screen is cleared.
2. The message is viewed with icalview.rb
3. The user is asked to respond with a single letter indicating
disposition: (a)ccept, (d)ecline, (t)entative, or (n)ot now. If the
(a) the event is added to the user's when calendar (~/.when/calendar)
using ical2when.rb, then an acceptance response is created with
icalrespond.rb and emailed to the originator with mutt.
(d) the event is not added to the user's calendar, but a decline
response is emailed to the originator.
(t) the event is not added to the user's calendar, but a tentative
response is emailed to the originator.
(n) nothing else happens.
(anything else) the script asks for the response again.
In any of the above cases where a response is generated, the user is
asked for "Message [none]:". If the user enters anything, that will
be passed to icalrespond.rb, with any single quotes (') removed.
If mutt is your email program and when is your calendar, then you can
use this script to view and/or respond to iCalendar attachements by adding
the following to .mailcap:
text/calendar; icalmutt.rb -i 'mailto:firstname.lastname@example.org' %s;
This should be used instead of the entry shown under icalview.rb.
Replace 'email@example.com' with your email address.