/*****************
datebook.php by Kyle Kienapfel 2006 (doctor.whom of gmail.com)
This script reads in a datebook.dat file from say Palm Desktop 4.1.4 and
outputs in iCalendar (RFC 2445). Output has been tested in Sunbird and
Google Calendar.
Sept 13th remaining issues
Lack of EXDATE support in google calendar wasted a few hours of thinking :(
Sunbird 0.2RC2 doesn't wrapping long lines in the Note
Only one repeat method is supported, "1st wednesday of every month" "$X $WeekDay of every month"
I actually use "Repeat daily until DATE"
http://w3.misterhouse.net:81/mh/code/public/palm_calendar.pl (not by me) has a complete repeat system but doesn't convert to iCalendar, actually this seems to read the file in a way better way.
*************************/
//ord -- Return ASCII value of character
//list(,$c) = unpack("s","A\0");echo $c;
function xxdate($format, $t) {
//PDT is GMT-7 and PST is GMT-6
//This could be expanded to use a global variable, but PHP5 will make this unnecessary
if (date("I",$t)) {
// && date("Z",$t) != -25200
$Offset=date("Z",$t)-"-25200";
} else {
$Offset=date("Z",$t)-"-28800"; //whoops had as 21600
}
//print date("Z",$t)."\n";
return date($format,$t-$Offset);
}
$DatebookFile = file_get_contents("datebook.dat");
$DatebookIndex=0;
$MOTUWE = array("SU", "MO", "TU", "WE", "TH", "FR", "SA");
//substr(string, start, length)
//be ba fe ca could be an endianess detector.. CAFEBABE
list(,$Magic) = unpack("V",substr($DatebookFile,$DatebookIndex,4));
//$Magic=substr($DatebookFile,$DatebookIndex,4);
//3405691582 says calc, -889275714 says V
if ($Magic != -889275714) { echo "Doesn't look like a CAFEBABE file\n"; }
$DatebookIndex += 4;
//echo $DatebookIndex."
\n";
$DatebookIndex=40;
$DatebookEntries=ord(substr($DatebookFile,$DatebookIndex,1));
$DatebookIndex += 12;
//echo ord(substr($DatebookFile,$DatebookIndex,1));
//echo "There are $DatebookEntries entries
\n";
//This is where we start actually using the DatebookIndex to roll on forward
//StringLength to be a bitch variable like $i.
$StringLength = ord(substr($DatebookFile,$DatebookIndex,1));
$DatebookIndex += 1;
// don't really need to output the location of this file really
$DatebookLocation = substr($DatebookFile,$DatebookIndex,$StringLength);
$DatebookLocation = str_replace("\\","\\\\",$DatebookLocation);
//echo substr($DatebookFile,$DatebookIndex,$StringLength);
//echo "
\n";
if (strstr($_SERVER["HTTP_USER_AGENT"],"Firefox")) {
print "
Goes through as html on Firefox, force text/calendar with datebook.php/basic.ics or something\n\n";
}
else {
header('Content-type: text/calendar');
}
?>
BEGIN:VCALENDAR
PRODID:-//Kyle Kienapfel/datebook.php//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:Palm
X-WR-TIMEZONE:America/Los_Angeles
X-WR-CALDESC:Export of
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
X-LIC-LOCATION:America/Los_Angeles
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
TZNAME:PST
DTSTART:19701025T020000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
TZNAME:PDT
DTSTART:19700405T020000
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
END:DAYLIGHT
END:VTIMEZONE
$Entries = explode("\xFF\xFF\xFF\x7F",$DatebookFile);
//$Entries = explode("Krista",$DatabookFile);
$Header=array_shift($Entries);
$Count=1;
//echo count($Entries);
foreach ($Entries as $value) {
$fullvalue=$value;
//It's either up here or right before the }
unset($Note,$Location,$Exclusions);
print "BEGIN:VEVENT\n";
$Category = ord(substr($value,4,1));
//substr($value,38,4)
list(,$StartTime) = unpack("V",substr($value,70,4));
list(,$EndTime) = unpack("V",substr($value,78,4));
$StringLength=ord(substr($value,90,1));
$Title = substr($value,91,$StringLength);
$Title = str_replace("\r\n","\\n",$Title);
print "SUMMARY:$Title\n";
//Cut the processed parts off...
$value = substr($value,91+$StringLength);
$StringLength = ord(substr($value,16,1)); $StringStart=17;
if ($StringLength == 255) {
list(,$StringLength) = unpack("v",substr($value,17,2));
$StringStart=19;
}
if ($StringLength != 0) {
$Note = substr($value,$StringStart,$StringLength);
$value = substr($value,$StringStart+$StringLength);
}
else {
$value = substr($value,17);
}
//cut off some more common cruft
$value = substr($value,36);
//if not the last one, cut off last 36 bytes
if ($Count != count($Entries)) {
//print "$tail\n";
//echo chunk_split(implode(" ",unpack("H*",$tail)),2," ") . "\n";
//echo chunk_split(implode(" ",unpack("H*",$fullvalue)),2," ") . "\n";
//$tail=substr($value,-36);
$value = substr($value,0,-36);
}
// if md5($value) == "abc9b358f24c8c9b1a998e792d3eea3e" we're done
//current index 11 is place to check for location
if (substr($value,0,12) == "\0\0\0\0\x05\0\0\0\0\0\0\0") {
// No repeat information, move directly on to Location
$StringLength = ord(substr($value,12,1));
if ($StringLength != 0) {
$Location = substr($value,13,$StringLength);
print "LOCATION:$Location\n";
}
//print "No repeat for Item $Count $Location";
}
// probably going to end up processing repeat events in if/else crap...
else {
//Well we have to process the rest, may as well delete some end cruft
$value=substr($value,0,-35);
list(,$ExclusionCount) = unpack("v",substr($value,0,2));
$value = substr($value,2);
//echo "ExclusionCount $ExclusionCount\n";
while ($ExclusionCount != 0) {
list(,$c) = unpack("V",substr($value,0,4));
$Exclusions[$ExclusionCount-1] = date("Ymd",$c);
//echo $ExclusionCount." ".$Exclusions[$ExclusionCount-1]."\n";
$value = substr($value,4);
$ExclusionCount--;
}
if (isset($Exclusions)) {
print "EXDATE:" . join(",",$Exclusions)."\n";
}
//Now for repeats!
if (substr($value,0,6) == "\x01\x80\x03\0\0\0" || substr($value,6,11) == "CDayOfMonth") {
//RRULE:FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1WE
//ef a1 9e 74 00 00 00 00 04 00 00 00 01 00 00 00
// date | TH 2
//work backwards with this
list(,$LastDate) = unpack("V",substr($value,-16,4));
list(,$WK) = unpack("v",substr($value,-4,2));
$WK++;
list(,$WD) = unpack("v",substr($value,-8,2));
$WD=$MOTUWE[$WD];
$WD=$WK.$WD;
print "RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=".date("Ymd",$LastDate).";BYDAY=$WD\n";
//print "RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=$WD\n";
}
}
//print "Item $Count, C$Category $Title\n";
echo "DTSTART;TZID=America/Los_Angeles:" . xxdate("Ymd",$StartTime)."T".xxdate("His",$StartTime)."\n";
echo "DTEND;TZID=America/Los_Angeles:" . xxdate("Ymd",$EndTime)."T".xxdate("His",$EndTime)."\n";
//echo $StringLength;
//echo $StartTime ." " . date("F jS, Y @ g:i:sa",$StartTime);
//print "
\n";
//echo $EndTime ." " . date("F jS, Y @ g:i:sa",$EndTime);
//print "
\n";
if (isset($Note)) {
$Note = str_replace(",","\,",$Note);
print "DESCRIPTION:".str_replace("\r\n","\\n",$Note)."\n";
}
/*if (substr($value,0,12) != "\0\0\0\0\x05\0\0\0\0\0\0\0") {
print "";
echo $value."\n";
echo chunk_split(implode(" ",unpack("H*",$value)),2," ") . "
\n";
echo md5($value)."\n";
print "";
}*/
print "END:VEVENT\n";
$Count++;
}
//print $Entries[0]; print $DatabookFile;
print "END:VCALENDAR\n";
?>