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. remindwhen.rb ------------- 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 object. 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 ignored. 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. remind ------ This command-line tool allows you to easily add reminders to the 'reminders' calendar. Usage: 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. reminders --------- 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 enter: reminders e alarm ----- 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 to ~/.when/reminder.wav Any other argument value is ignored. In any case, the return value reflects the final state. echoif ------ 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. Example: 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, otherwise "on". Naturally, echoif's usefulness extends beyond the realm of reminders and xmonad. tocal ----- 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. whencal ------- 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 were supplied. 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 flowing smoothly. Example: whencal y will view a calendar for the next year. ical2when.rb ------------ 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" icalview.rb ----------- 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. icalorg.rb ---------- Extracts the originator from an iCalendar and sends it to stdout. icalrespond.rb -------------- 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. icalmutt.rb ----------- 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 user responds: (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:email@example.com' %s; This should be used instead of the entry shown under icalview.rb. Replace 'firstname.lastname@example.org' with your email address.