#!/local/bin/perl
# ------------------------------------------------------------------
#                            ical2vcs V0.4
# Perl translator for Apple Ical (.ics) to Palm Vcal (.vcs) format
#
#                              J. Touch
#                           touch@isi.edu
#                      http://www.isi.edu/touch
#
#            USC Information Sciences Institute (USC/ISI)
#               Marina del Rey, California 90292, USA
#                         Copyright (c) 2004-2007
#
# Revision date: Jun. 2, 2007
# ------------------------------------------------------------------
#
# Copyright (c) 2004-2007 by the University of Southern California.
# All rights reserved.
#
# Permission to use, copy, modify, and distribute this software and
# its documentation in source and binary forms for non-commercial
# purposes and without fee is hereby granted, provided that the
# above copyright notice appear in all copies and that both the
# copyright notice and this permission notice appear in supporting
# documentation, and that any documentation, advertising materials,
# and other materials related to such distribution and use
# acknowledge that the software was developed by the University of
# Southern California, Information Sciences Institute.  The name of
# the University may not be used to endorse or promote products
# derived from this software without specific prior written
# permission.
#
# THE UNIVERSITY OF SOUTHERN CALIFORNIA MAKES NO REPRESENTATIONS
# ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS
# SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
# ------------------------------------------------------------------
#
# usage:  
#        ics2vcs2.pl [inputfile.ics] > [outputfile.vcs]
#
# Converts ical calendars to vcs
# Intended primarily to convert Apple-generated IETF ical schedules
# to be importable into Palm Desktop
#
#       WARNING - tested on IETF-61.ics and IETF-64.ics files only
#
# replace codes:
#	ics			vcs (quoted-printable)
#     ---------------------------------------------------
#	\n			=0D=0A
#	\N			=0D=0A
#	\,			,
#	\;			;
#	\\			\
# 	\(other)		ERROR
#
# Also changes some command strings:
#	ics			vcs
#	-------------------------------------------------
#	VERSION:2.0		VERSION:1.0
#	SUMMARY:		SUMMARY;ENCODING=QUOTED-PRINTABLE:
#	DESCRIPTION:		DESCRIPTION;ENCODING=QUOTED-PRINTABLE:
#	PRODID:-//Apple...	PRODID:ics2vcs... (prefixed)
#   	DURATION		DTEND (now allows DURATION before DTSTART)
#
# Unfolds the lines first - vcs doesn't have a line length limit,
#   but ics folds on ?? chars/line (what is this, the 1970's?) 
#   inserting <cr><lf><space>
#
# returns:
#      0 on no illegal characters found (no error)
#      1 if any illegal characters found (error) 
# ------------------------------------------------------------------

####################################################################
# unfold the file - folding is so 1970's ;-(
@wholefile = <>;
$wholefileline = join('XXJDTXX',@wholefile);
$wholefileline =~ s/\nXXJDTXX //g;
@cleanfile = split(/XXJDTXX/,$wholefileline);

while ($line = shift(@cleanfile)) {
	
  ##################################################################
  # substitutions:
  ##################################################################

  # eat the windows carriage returns "^M"s
  $line =~ s/\r//g;

  # printed quotable doesn't react well to '='
  $line =~ s/=/-/g;

  # eat the trailing carriage returns
  $line =~ s/\\n$//i;

  # convert carriage returns and tabs to quoted printable equivalent
  $line =~ s/\\n/=0D=0A/gi;	# case insensitive
  $line =~ s/\t/=0D=0A/g;	# this isn't quite right, but works OK for now

  # omit unneeded escapes
  $line =~ s/\\,/,/g;
  $line =~ s/\\;/;/g;
  $line =~ s/\\\\/\\/g;

  # print warning later for unrecognized backslashes
  if ($line =~ /(\\.*)/) {
    print "ics2vcsERROR: unrecogized backslash escape = >>$1<<\n";
    $errorfound = 1;
  }

  ##################################################################
  # translate portions from ical-speak to vcal-speak
  ##################################################################

  $line =~ s/^VERSION\:2\.0/VERSION\:1\.0/;
  $line =~ s/^SUMMARY\:/SUMMARY\;ENCODING\=QUOTED\-PRINTABLE\:/;
  $line =~ s/^DESCRIPTION\:/DESCRIPTION\;ENCODING\=QUOTED\-PRINTABLE\:/;

  # label output as coming from this software
  $line =~ s/^PRODID\:(.*)/PRODID: ics2vcs 0.4 Joe Touch from $1/;

  # omit time zones on entries; supported in later versions of PalmOS
  $line =~ s/^DTSTART;.*:/DTSTART:/;
  $line =~ s/^DTEND;.*:/DTEND:/;

  ##################################################################
  # look for begin of events to clear out variables 
  ##################################################################
  if ($line =~ /^BEGIN:VEVENT/) {
    $startfound = 0;
    $durfound = 0;
  }
  if ($line =~ /^DTSTART:(.*)/) {
    $starttime = $1;
    $starttime =~ /([0-9]+)T([0-9][0-9])([0-9][0-9])([0-9]*)/;
    $syrday = $1;
    $shour = $2;
    $smin = $3;
    $sextra = $4;
    $startfound = 1;
  }
  if ($line =~ /^DURATION:(.*)/) {
    $dur = $1;
    $dur =~ s/PT(([0-9]+)H)?(([0-9]+)M)?//;
    $dhour = $2;
    $dmin = $4;
    if ($dur != "") {
      print $line;
      print "ics2vcsERROR ONLY HOURS AND MINUTES DURATIONS ARE SUPPORTED\n";
      $errorfound = 1;
    }
    $durfound = 1;
    # eat the line - it's not printed out in vcs
    $line = "";
  }
  if (($startfound == 1) && ($durfound == 1)) {
    # once you find both start and duration, write DTEND
    $shour += $dhour;
    $smin += $dmin;
    if ($smin > 60) {
      $smin -= 60;
      $shour++;
    }
    $hrmin = sprintf "%0.2d%0.2d",$shour, $smin;
    # append line here
    $line .= "DTEND:" . $syrday . "T" . $hrmin . $sextra . "\n";
    $startfound = 0;
    $durfound = 0;
  }
  ##################################################################
  # omit blank lines to compress entries
  ##################################################################
  if ($line !~ /^\s+$/) {
    print $line;
  }  
  if ($line =~ /^DTEND/) {
    if  (($starttime == 0) && ($durfound == 1)) {
      print "ics2vcsERROR INVALID DURATION BEFORE START TIME\n";
      $errorfound = 1;
    }
    if (($starttime == 1) && ($durfound == 0)) {
      print "ics2vcsERROR INVALID START TIME WITHOUT DTEND OR DURATION\n";
      $errorfound = 1;
    }
  }
}
if ($errorfound == 1) {
  printf STDERR  "ERROR FOUND - see \'ics2vcsERROR\' inside output file\n";
}
exit($errorfound);