#!/bin/bash
#===============================================================================
#
# CalUpload shell script
#
# This script will search for iCal styled calendar definitions in the file
# system, and collect the event ics files into a single calendar ics file
#
# Some specialized behaviour is defined and described below based on the needs
# of the contractor.
#
# Copyright 2012 by David Paterson and C.T. Paterson
#
# This work is licensed under a Creative Commons Attribution-NonCommercial-
# ShareAlike 3.0 Unported License.
# Refer to http://creativecommons.org/licenses/by-nc-sa/3.0 for full text
#
#===============================================================================
# where to look for the calendar files
BASE_CAL_DIRECTORY=${HOME}/Library/Calendars
# where to put the resulting calendar file(s)
TARGET_ICS_DIRECTORY=${HOME}
# Set as empty string ("") to do all calendars
CALENDAR_TO_PUBLISH="OrangeGroveSpa"
#===============================================================================
#
# collect_events_into_calendar_ics
#
# Recent version of iCal saves a calendar by creating an .ics file for each
# event in the calendar. This function will, in a given directory, extract the
# event details out of each event .ics file and concatenate them together,
# wrapping the result in the necessary header and footer data to create an .ics
# file for the full calendar
#
# Inputs:
# $1 - the calendar directory
#
# Outputs:
# The resuling calendar .ics file is written to stdout (standard output)
#
#===============================================================================
function collect_events_into_calendar_ics {
EVENT_DIR=${1}/Events
# write the head of the calendar ICS
cat <<ICS_HEAD
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 5.0.2//EN
CALSCALE:GREGORIAN
ICS_HEAD
# iterate through ics files in the Events directory, and write only
# the event definition in each (that is, not the whole file)
for E in $(ls ${EVENT_DIR}/ 2>/dev/null | grep .ics); do
get_events_from_file ${EVENT_DIR}/${E}
done
# write the tail of the calendar ICS
cat <<ICS_TAIL
END:VCALENDAR
ICS_TAIL
}
#===============================================================================
#
# get_events_from_file
#
# Process an event ics file and extract the VEVENT definition for each event,
# writing to stdout.
#
# Some data massaging is done at the request of the contractor to suppress
# private details in the events that they do not wish published.
#
# Inputs:
# $1 - the event file name
#
# Outputs:
# The resuling VEVENT definitions, written to stdout (standard output)
#
#===============================================================================
function get_events_from_file {
EVENT_FILE=${1}
# This script was written to take a business calendar and publish it
# online to show available vs. booked times.
#
# For reasons of privacy, many event details are suppressed, to
# let all details display, delete everything from "sed" to the end
# of the command.
cat ${EVENT_FILE} | \
awk 'BEGIN { is_event=0 }
/^BEGIN:VEVENT/ { is_event=1 }
/^END:VEVENT/ { print $0; is_event=0 }
{ if ( 1 == is_event ) { print $0 } }' | \
sed -e 's/SUMMARY:.*/SUMMARY:Booked/' \
-e 's/URI:.*/URI:/' \
-e 's/DESCRIPTION:.*/DESCRIPTION:/' \
-e 's/LOCATION:.*/LOCATION:/' \
-e '/^ /d'
}
#===============================================================================
#
# get_calendar_name
#
# From within a specified calendar directory, the function will parse out the
# "Title" value from the Info.plist file, and return the value
#
# Inputs:
# $1 - the calendar directory
#
# Outputs:
# The value assigned to the "Title" in the Info.plist file
#
#===============================================================================
function get_calendar_name {
CAL_DIR=${1}
awk '/Title/ { getline; print }' ${CAL_DIR}/Info.plist | cut -d '>' -f2 | cut -d '<' -f1
}
#===============================================================================
#
# is_event_calendar
#
# Parse out the EventContainer value from the calendar's Info.plist file.
#
# Inputs:
# $1 - the calendar directory
#
# Outputs:
# The value associated with the EventContainer key, expected to be "true" or
# "false"
#
#===============================================================================
function is_event_calendar {
CAL_DIR=${1}
# Only the gods know what Apple intends; but we think the difference between a
# calendar built for events, and it's companion calendar for tasks, is the
# setting for EventContainer. So, the setting for EventContainer in the Info.plist
# file will be what determines whether this is an "event calendar."
awk '/EventContainer/ { getline; print }' ${CAL_DIR}/Info.plist | cut -d '<' -f2 | cut -d '/' -f1
}
### MAINLINE ###
# Loop through all the calendar directories found within the subdirectories below
# the target directory (set as BASE_CAL_DIRECTORY)
for C in $(find ${BASE_CAL_DIRECTORY}/ -name "*.calendar"); do
# we're only interested in event calendars (as opposed to calendars with only tasks)
if [[ true =~ $(is_event_calendar ${C}) ]]; then
# Get the title of each calendar from the info file
RETRIEVED_CAL_NAME=$(get_calendar_name ${C})
# If the user did no specify a calendar name, or if they did and we've found it...
if [[ "" == "${CALENDAR_TO_PUBLISH}" ]] || [[ "${CALENDAR_TO_PUBLISH}" == "${RETRIEVED_CAL_NAME}" ]]; then
# ... collect the data from the event files into a single calendar file, and put it
# in the directory specified (the TARGET_ICS_DIRECTORY).
collect_events_into_calendar_ics ${C} > "${TARGET_ICS_DIRECTORY}/${RETRIEVED_CAL_NAME}.full.ics"
fi
fi
done
# We're done.
exit